Site icon Hip-Hop Website Design and Development

Custom Post Meta from custom metaboxes is randomly being deleted

For a while now I’ve been applying and updating some custom metaboxes that my company re-uses on different sites. (Not the same metaboxes, but the same methodology.)

Essentially it allows for the ‘association’ of individual posts of different custom post-types to be assigned/associated with default WP pages and posts.

So, for example Post ID = 449 which is a of Post Type = CustomA can be assigned to any page or post.

What I have built, works. It’s worked for a long time. And it still works.

What we’ve started to see however is that on the odd occasion, one of the Pages/Posts will see all of this custom post meta simply purged from the page.

I have never been able to replicate the error myself. I’m just given URLs to edit screens of posts or pages where the custom post meta was assigned, and now it’s gone.

I have tried repeatedly to force the issue and try and trigger something that will make it happen while I’m monitoring the developer console, but I can’t trigger it.

Error logs are empty. (There’s the odd warning every couple of days, but nothing that pertains to any of the posts or functions in question.)

<?php
    //ADD CPT SELECTION METABOX TO PAGES AND POSTS
    function cpt_add_cpt_selection() {
        $screens = ['page', 'post'];
        foreach( $screens as $screen ) {
            add_meta_box(
                'cpt_assignment',
                'Assign A Custom Post Type',
                'cpt_assign_metabox',
                $screen,
                'side',
                'low',
                 array(
                    '__block_editor_compatible_meta_box' => true,
                    '__back_compat_meta_box'             => false,
                )
            );
        }
    }
    add_action( 'add_meta_boxes', 'cpt_add_cpt_selection' );
    //QUICK LINKS SELECTION METABOX OPTIONS
    function cpt_assign_metabox( $post ) {
        wp_nonce_field( basename( __FILE__ ), 'cpt_nonce' );
        $cpt_position               = get_post_meta( $post->ID, 'cpt_position', true );
        $cpt_appended_cpts          = get_post_meta( $post->ID, 'cpt_cpts', false );
        ?>
        <label for="cpt_position_sidebar" style="display:block;margin-bottom:0.5rem;">
            <input type="radio" id="cpt_position_sidebar" name="cpt_position" value="sidebar" <?php checked( 'sidebar' == $cpt_position ); ?>/> Display in Sidebar
        </label>
        <label for="cpt_position_content" style="display:block;margin-bottom:0.5rem;">
            <input type="radio" id="cpt_position_content" name="cpt_position" value="content" <?php checked( 'content' == $cpt_position ); ?>/> Display below Content
        </label>
        <select id="cpt_cpts" name="cpt_cpts[]" multiple="multiple" style="width:90%;">
        <?php
        if( $cpt_appended_cpts ) {
            foreach( $cpt_appended_cpts as $cpt_ids ) {
                foreach( $cpt_ids as $cpt_id ) {
                    $cpt_title = get_the_title( $cpt_id );
                    $cpt_title = ( mb_strlen( $cpt_title ) > 50 ) ? mb_substr( $cpt_title, 0, 49 ) . '...' : $cpt_title;
                    echo '<option value="' . $cpt_id . '" selected="selected">' . $cpt_title . '</option>';
                }
            }
        }
        ?>
        </select>
    <?php }
    //SAVE THE CPT ASSIGNMENT FIELDS TO POSTS AND PAGES.
    function cpt_assign_save_postdata( $post_id ) {
        if( isset( $_POST['cpt_cpts'] ) ) {
            update_post_meta( $post_id, 'cpt_cpts', $_POST['cpt_cpts'] );
        } else {
            delete_post_meta( $post_id, 'cpt_cpts' );
        }
        if( isset( $_POST['cpt_position'] ) ) {
            update_post_meta( $post_id, 'cpt_position', $_POST['cpt_position'] );
        } else {
            delete_post_meta( $post_id, 'cpt_position' );
        }
    }
    add_action( 'save_post', 'cpt_assign_save_postdata' );
    //AJAX QUERY FOR POSTS USING SELECT2
    function cpt_get_cpts_ajax_callback() {
        $return = array();
        $search_results = new WP_Query( array(
            's'                     => $_GET['q'],
            'post_type'             => 'the_custom_cpt_in_question',
            'post_status'           => 'publish',
            'ignore_sticky_posts'   => 1,
            'posts_per_page'        => -1
        ) );
        if( $search_results->have_posts() ) :
            while( $search_results->have_posts() ) : $search_results->the_post();
                $title = ( mb_strlen( $search_results->post->post_title ) > 50 ) ? mb_substr( $search_results->post->post_title, 0, 49 ) . '...' : $search_results->post->post_title;
                $return[] = array( $search_results->post->ID, $title );
            endwhile;
        endif;
        echo json_encode( $return );
        wp_die();
    }
    add_action( 'wp_ajax_getcustompt', 'cpt_get_cpts_ajax_callback' );

Like I said, it’s actually working. Every day across numerous large sites, people are adding and removing a number of Custom Post Types from being associated with different posts and pages. The CPTs themselves are stuff like ‘FAQs’ or ‘Team Members’ and the themes being used have template tags applied that will display the contents of the CPTs if any have been assigned to pages. It all works.

The one anomaly is that maybe once every 3-4 weeks, a page that HAD these fields populated, including the field that assigns whether the content should be applied to either the sidebar or below the content, is simply being purged from the postmeta table.

(Two different template tags are used that run a conditional check before retrieving any content to determine whether the assigned CPTs should be displayed in the sidebar or beneath the content.)

My two theories, neither of which I can replicate are:

People are navigating away from the page before the ‘Update’ process is finished. But I keep trying this and every time I do it, the page still has the custom post meta.

We use WPML and people will have multiple tabs open and often across different languages (all of our client sites are bilingual) and I’ve noticed that this sometimes causes things to get confused in the back end… …you start editing in one language, go to check something in a new tab with a second language, go back to the first page you were editing and your searches no longer work, because the search is executing in language of the tab you most recently opened, which set a language cookie.

So, my question is, does anyone see something in my metaboxes and save process that could result in occasional purging of postmeta on posts/pages?

(Patiently waits for SallyCJ. ;-P)

P.S. I know there is a different way of building these metaboxes, and am planning on doing it, but with my current workload I do not have the time to stop working on new projects and go revisit something that ostensibly works. I also don’t know if using the new React based metaboxes will address the issue we’re intermittently experiencing.