After Monday’s post, where I added custom taxonomy data to Quick Edit as dropdowns, you know I had to tackle adding more data. While most of my data is custom taxonomies, some is post-meta and one is a weird cross-relational CPT to CPT(s). CMB2 themselves noted that this isn’t something easy to do. But I had already tackled this in one way and felt confident.
When I showed my initial function to add the quick edit box, you may have noticed I had multiple cases:
add_action('quick_edit_custom_box', 'lezchars_quick_edit_add', 10, 2); function lezchars_quick_edit_add($column_name, $post_type) { switch ( $column_name ) { case 'cpt-shows': // Multiselect - CPT where characters may have multiple break; case 'postmeta-roletype': // Single Select - Custom Taxonomy break; case 'taxonomy-lez_gender': // Taxonomy in a dropdown break; case 'taxonomy-lez_sexuality': ... break; } }
I actually added in the values for gender when I did the sexuality. I renamed the cases from just ‘roleype’ to ‘postmeta-roletype’ and ‘shows’ to ‘cpt-shows’ in order to help remind me what was what. WordPress itself adds in taxonomy-
as a prefix for taxonomies, so it was in-keeping with the theme.
In order to add the new code for roles, I edit my case for postmeta-roletype
in lezchars_quick_edit_add
and everything will be awesome. I just have to get the data, validate it, sanitize it, update it, and javascript it.
Here we go!
Understanding the Data
In order to know how to save the data, and how to get it, we should understand how we’re creating it in the first place. Like I said before I’m using CMB2. I do this on a post by post basis. This means my code is going to be saved as post meta. I know that for extracting and updating that data I’ll need to know three things: post ID, post meta key, and post meta value.
I have a global variable $lez_character_roles
which allows me to use the same data in my CMB2 array for this data and I’ll be able to reuse this all over the place. The array keys are the slugs (regular, recurring, guest) and the values are the names (Regular/Main Character, etc…).
I’m already extracting the data for displaying in the custom column. While my custom column code covers both the shows CPT stuff (which is complicated in order to handle multiple shows), I’m only going to concentrate on adding the post meta data for role type. Here’s the code:
add_action( 'manage_post_type_characters_posts_custom_column' , 'custom_post_type_characters_column', 10, 2 ); function custom_post_type_characters_column( $column, $post_id ) { // Snipped the annoying code to get the show title switch ( $column ) { case 'cpt-shows': echo implode(", ", $show_title ); break; case 'postmeta-roletype': echo ucfirst(get_post_meta( $post_id, 'lezchars_type', true )); break; } }
As you can see, the line echo ucfirst(get_post_meta( $post_id, 'lezchars_type', true ));
is super straightforward. That’s why we’re starting with this. Oh and the reason it’s set to ‘true’ is that a character should only have one role. Admittedly, this gets weird when a character is regular, then leaves and comes back as a guest, but we default to ‘highest role applicable.’
Of note, this shows the role ‘key’ (‘recurring’ vs ‘Recurring Character’) but that’s okay. If I was to show the full data here, it could make the page very content-heavy. I wanted to avoid that. If, instead, I wanted to show the display name, I’d add a global for $lez_character_roles
(see how that array pays off?) and then change the case to do this:
case 'postmeta-roletype': $roleslug = get_post_meta( $post_id, 'lezchars_type', true ); echo $lez_character_roles[$roleslug]; break;
For my use case, the simpler method is enough.
Making the Dropdown
We’re going to use the same function we used last time, lezchars_quick_edit_add
, and add in a switch for the column name postmeta-roletype
with this (omitting other cases for brevity):
add_action('quick_edit_custom_box', 'lezchars_quick_edit_add', 10, 2); function lezchars_quick_edit_add($column_name, $post_type) { global $lez_character_roles; switch ( $column_name ) { // CPT: Shows (snipped) // Post Meta: Role Type case 'postmeta-roletype': ?> <fieldset class="inline-edit-col-left"> <div class="inline-edit-col"> <span class="title">Character Role</span> <input type="hidden" name="lez_roletype_noncename" id="lez_roletype_noncename" value="" /> <select name='postmeta_lez_role' id='postmeta_lez_role'> <option class='lez_role-option' value='0'>(Undefined)</option> <?php foreach ($lez_character_roles as $roleslug => $rolename) { echo "<option class='lez_role-option' value='{$roleslug}'>{$rolename}</option>\n"; } ?> </select> </div> </fieldset> <?php break; // Taxonomy: Gender (snipped) // Taxonomy: Sexuality (snipped) } }
That array for my roles really makes life easier here!
I will note, in retrospect making the character roles a taxonomy would have made a lot of other things easier when I started making the pages for statistics, but that’s another post.
Saving the Data
Again, we’re re-using what we have. Remember the function lezchars_quick_edit_save
?
add_action('save_post', 'lezchars_quick_edit_save'); function lezchars_quick_edit_save($post_id) { global $lez_character_roles; // Criteria for not saving: Auto-saves, not post_type_characters, can't edit if ( ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) || ( 'post_type_characters' != $_POST['post_type'] ) || !current_user_can( 'edit_page', $post_id ) ) { return $post_id; } $post = get_post($post_id); // RoleType if ( isset($_POST['postmeta_lez_role']) && ($post->post_type != 'revision') ) { $lez_roletype = esc_attr($_POST['postmeta_lez_role']); if ( array_key_exists( $lez_roletype, $lez_character_roles ) ) { update_post_meta( $post_id, 'lezchars_type', $lez_roletype ); } } // Sexuality went here // Gender went here }
Here we’ve added our global for the character roles again, because we want to make sure the role is a legit role before we save it. Like update_option
, the update_post_meta
function will add the meta field for the post if it does not exist. Makes our life super easy, doesn’t that?
Javascript Hell Again
Now the shit I hate. Again, since we can’t pass post data to quick edit natively, we have to use javascript. We use our two functions for that:
add_action('admin_footer', 'lezchars_quick_edit_js'); function lezchars_quick_edit_js() { global $current_screen; if ( ($current_screen->id !== 'edit-post_type_characters') || ($current_screen->post_type !== 'post_type_characters') ) return; ?> <script type="text/javascript"> <!-- // Sexuality function set_inline_lez_quick_edit_defaults( sexualitySet, genderSet, roleSet, nonce ) { // revert Quick Edit menu so that it refreshes properly inlineEditPost.revert(); var sexualityInput = document.getElementById('terms_lez_sexuality'); var genderInput = document.getElementById('terms_lez_gender'); var roleInput = document.getElementById('postmeta_lez_role'); var nonceInput = document.getElementById('lez_sexuality_noncename'); nonceInput.value = nonce; // Set Sexuality Option [snip] // Set Gender Option [snip] // Set Role Option for (i = 0; i < roleInput.options.length; i++) { if (roleInput.options[i].value == roleSet) { roleInput.options[i].setAttribute("selected", "selected"); } else { roleInput.options[i].removeAttribute("selected"); } } } //--> </script> <?php }
and
// Calls the JS in the previous function add_filter('post_row_actions', 'lezchars_quick_edit_link', 10, 2); function lezchars_quick_edit_link($actions, $post) { global $current_screen; if (($current_screen->id != 'edit-post_type_characters') || ($current_screen->post_type != 'post_type_characters')) return $actions; $nonce = wp_create_nonce( 'lez_sexuality_'.$post->ID); $sex_terms = wp_get_post_terms( $post->ID, 'lez_sexuality', array( 'fields' => 'all' ) ); $gender_terms = wp_get_post_terms( $post->ID, 'lez_gender', array( 'fields' => 'all' ) ); $role_term = get_post_meta( $post->ID, 'lezchars_type', true ); $actions['inline hide-if-no-js'] = '<a href="#" class="editinline" title="'; $actions['inline hide-if-no-js'] .= esc_attr( __( 'Edit this item inline' ) ) . '" '; $actions['inline hide-if-no-js'] .= " onclick=\"set_inline_lez_quick_edit_defaults('{$sex_terms[0]->name}', '{$gender_terms[0]->name}', '{$role_term}', '{$nonce}')\">"; $actions['inline hide-if-no-js'] .= __( 'Quick Edit' ); $actions['inline hide-if-no-js'] .= '</a>'; return $actions; }
This works. It’s ugly as hell, but it works. Sadly it’s broken. If you quick edit twice, it shows the first values. I’m sure I’ll figure that out eventually.
Comments
One response to “Adding Post Meta Data to Quick Edit”
I hadn’t even thought about sticking fields into the quick edit section.