0

I've read quite a bit of documentation around it, tons of other answers here, but I can't seem to discern why the custom meta box I'm trying to add to posts (and pages, but let's start with one at a time) isn't saving the post meta. I've got a custom CPT and it works perfectly. I've even used the Select2 method as part of theme options that allows me to assign up to 8 of the posts from my CPT to the front page. That works perfectly.

The issue I'm having is getting the traditional add_metabox method to save the selected posts from the CPT to the post meta. The Select2 works perfectly and I can search and select as many of the CPTs as I want. They display, when I click 'Update' on a post, the little wheel spins and it appears as though it HAS saved the post meta. However, the saved post meta does not appear in the database.

Here's what I have:

//REGISTER CPT META SO BLOCK EDITOR CAN SAVE IT TO POSTS
function mycpt_register_post_meta() {
    register_post_meta(
        'post',
        'mycpt_cpts',
        array(
            'show_in_rest' => true,
            'single' => true,
            'type' => 'string',
        )
    );
}
add_action( 'init', 'mycpt_register_post_meta' );

//ADD CPT SELECTION METABOX TO PAGES AND POSTS
function mycpt_add_cpt_selection() {
    $screens = ['page', 'post'];
    foreach( $screens as $screen ) {
        add_meta_box(
            'mycpt_assignment',
            'Assign Quick Links',
            'mycpt_assign_metabox',
            $screen,
            'side',
            'low',
             array(
                '__block_editor_compatible_meta_box' => true,
                '__back_compat_meta_box'             => false,
            )
        );
    }
}
add_action( 'add_meta_boxes', 'mycpt_add_ql_selection' );

//CPT SELECTION METABOX OPTIONS
function mycpt_assign_metabox( $post ) {
    wp_nonce_field( basename( __FILE__ ), 'mycpt_ql_nonce' );
    $mycpt_appended_cpts = get_post_meta( $post->ID, 'mycpt_cpts', false ); ?>
    <select id="mycpt_cpts" name="mycpt_cpts[]" multiple="multiple" style="width:90%;">
    <?php
    if ( mycpt_appended_cpts ) {
        foreach( $mycpt_appended_cpts 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>
    <small style="display:block;font-size:0.8em;width:95%;">
        Add some instructions here...
    </small>
<?php }

Eventually, I'm going to start building these as native blocks, but I've not done that yet and there's deadlines, etc, that I'm chasing. From all the documentation I've read, and other questions/answers here and elsewhere, this SHOULD work, but it doesn't. I just don't know what step I'm missing.

(For context, I want to allow the users to assign posts from the CPT to a post or a page, in the template, I will use the post meta to output a list of links to the CPTs in a sidebar.)

  • I think I’ve solved this... will post an answer in case anyone can add to it or needs it in future. – Tony Djukic May 3 at 22:48
0

So, it simply turns out that the method I usually use to save post meta doesn't work in this context, even though it does in when using the classic editor. I don't know why this is, but I did find another article (https://www.codeinwp.com/blog/make-plugin-compatible-with-gutenberg-sidebar-api/) and there was a line in there that eventually led me to a solution. Additionally the entire, mycpt_register_post_meta() function doesn't appear to be necessary at all if you're saving data in this manner. For the clarification, I didn't actually show my usual saving method in my question because it wasn't working and I'd long since abandoned trying to use it in this particular instance - so I didn't include it. (If anyone wants to see it I can add it.)

function mycpt_add_cpt_selection() {
    $screens = ['page', 'post'];
    foreach( $screens as $screen ) {
        add_meta_box(
            'mycpt_assignment',
            'Assign Quick Links',
            'mycpt_assign_metabox',
            $screen,
            'side',
            'low',
             //not even sure that this array is necessary
             array(
                '__block_editor_compatible_meta_box' => true,
                '__back_compat_meta_box'             => false,
            )
        );
    }
}
add_action( 'add_meta_boxes', 'mycpt_add_cpt_selection' );
function mycpt_assign_metabox( $post ) {
    wp_nonce_field( basename( __FILE__ ), 'mycpt_cpt_nonce' );
    $mycpt_appended_cpts = get_post_meta( $post->ID, 'mycpt_cpts', false ); ?>
    <select id="mycpt_cpts" name="mycpt_cpts[]" multiple="multiple" style="width:90%;">
    <?php
    if( $mycpt_appended_cpts ) {
        foreach( $mycpt_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>
    <small style="display:block;font-size:0.8em;width:95%;">
        Instructions
    </small>
<?php }
function mycpt_assign_save_postdata( $post_id ) {
    if( isset( $_POST['mycpt_cpts'] ) ) {
        update_post_meta( $post_id, 'mycpt_cpts', $_POST['mycpt_cpts'] );
    }
}
add_action( 'save_post', 'mycpt_assign_save_postdata' );

So everything works almost exactly the way I want it. The only oddity that still perplexes me is when retrieving the post_meta it's actually putting an array into another array. It's creating a multi-dimensional array, which isn't what happens when I use the same methods in other areas.

As an example, in the database, when I've assigned four of my CPT posts to a WP post - it's saved as the following:

a:2:{i:0;s:2:"65";i:1;s:2:"66";}

Which would be:

array(
  0 => "65",
  1 => "66"
)

However, when I retrieve using get_post_meta(), what I get back is the following:

array(
  0 => array(
    0 => "65",
    1 => "66" 
  ),
)

You can see from select output that I have 2 foreach loops in there, so I've got a workaround, but I'm still going to figure out how to get it to return just a single array.

Hope someone else finds this useful.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.