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'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.)
Share Improve this question asked May 3, 2020 at 21:02 Tony DjukicTony Djukic 2,2774 gold badges19 silver badges34 bronze badges 1- I think I’ve solved this... will post an answer in case anyone can add to it or needs it in future. – Tony Djukic Commented May 3, 2020 at 22:48
1 Answer
Reset to default 3So, 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/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.