カスタム投稿タイプのクイック編集セクションと一括編集セクションにカスタムフィールドを追加できるようにするコードがあります。これが私が使っているものです: https://github.com/bamadesigner/manage-wordpress-posts-using-bulk-edit-and-quick-edit
Quick Editから保存することができない以外は、すべてがうまく機能しています。一括編集はうまく機能し保存できますが、変更を保存しないのはクイック編集だけです。下記は私が関連するコードであると信じるものです。誰が私が間違っていることを私に言うことによって助けることができますか?
以下のコード全体を更新しました。
PHPクイック編集プラグインの場合
<?php
/**
* Plugin Name: Manage WordPress Posts Using Bulk Edit and Quick Edit
* Description: This is the code for a tutorial WP Dreamer wrote about managing WordPress posts using bulk and quick edit.
* Author: WP Dreamer
* Author URI: http://wpdreamer.com/2012/03/manage-wordpress-posts-using-bulk-edit-and-quick-edit/
*/
/**
* I decided to convert the tutorial to a plugin format
* so I could easily monitor it on my development environment
* and store it on GitHub.
*
* With that said, you could easily take this code and paste it
* into your theme's functions.php file. There is, however,
* an included javascript file so be sure to check the
* manage_wp_posts_be_qe_enqueue_admin_scripts()
* function to confirm you're enqueueing the right javascript file.
*
* Also, after a few requests for custom field examples other than
* text boxes, I updated the tutorial to include a select dropdown
* and a radio button.
*
* Custom Fields:
* 'Release Date - input text
* 'Coming Soon' - input radio
* 'Film Rating' - select dropdown
*
* If you find any issues with the tutorial, or code, please let me know. Thanks!
*/
/**
* Since Bulk Edit and Quick Edit hooks are triggered by custom columns,
* you must first add custom columns for the fields you wish to add, which are setup by
* 'filtering' the column information.
*
* There are 3 different column filters: 'manage_pages_columns' for pages,
* 'manage_posts_columns' which covers ALL post types (including custom post types),
* and 'manage_{$post_type_name}_posts_columns' which only covers, you guessed it,
* the columns for the defined $post_type_name.
*
* The 'manage_pages_columns' and 'manage_{$post_type_name}_posts_columns' filters only
* pass $columns (an array), which is the column info, as an argument, but 'manage_posts_columns'
* passes $columns and $post_type (a string).
*
* Note: Don't forget that it's a WordPress filter so you HAVE to return the first argument that's
* passed to the function, in this case $columns. And for filters that pass more than 1 argument,
* you have to specify the number of accepted arguments in your add_filter() declaration,
* following the priority argument.
*
*/
add_filter( 'manage_posts_columns', 'manage_wp_posts_be_qe_manage_posts_columns', 10, 2 );
function manage_wp_posts_be_qe_manage_posts_columns( $columns, $post_type ) {
/**
* The first example adds our new columns at the end.
* Notice that we're specifying a post type because our function covers ALL post types.
*
* Uncomment this code if you want to add your column at the end
*/
if ( $post_type == 'products' ) {
$columns[ 'field_products_sale' ] = 'Sale Icon';
$columns[ 'field_products_description_under_button' ] = 'Sale Description';
}
return $columns;
/**
* The second example adds our new column after the �Title� column.
* Notice that we're specifying a post type because our function covers ALL post types.
*/
switch ( $post_type ) {
case 'products':
// building a new array of column data
$new_columns = array();
foreach( $columns as $key => $value ) {
// default-ly add every original column
$new_columns[ $key ] = $value;
/**
* If currently adding the title column,
* follow immediately with our custom columns.
*/
if ( $key == 'title' ) {
$new_columns[ 'field_products_sale' ] = 'Sale Icone';
$new_columns[ 'field_products_description_under_button' ] = 'Description';
}
}
return $new_columns;
}
return $columns;
}
/**
* The following filter allows you to make your column(s) sortable.
*
* The 'edit-products' section of the filter name is the custom part
* of the filter name, which tells WordPress you want this to run
* on the main 'products' custom post type edit screen. So, e.g., if
* your custom post type's name was 'books', then the filter name
* would be 'manage_edit-books_sortable_columns'.
*
* Don't forget that filters must ALWAYS return a value.
*/
add_filter( 'manage_edit-products_sortable_columns', 'manage_wp_posts_be_qe_manage_sortable_columns' );
function manage_wp_posts_be_qe_manage_sortable_columns( $sortable_columns ) {
/**
* In order to make a column sortable, add the
* column data to the $sortable_columns array.
*
* I want to make my 'Release Date' column
* sortable so the array indexes (the 'field_products_sale_column'
* value between the []) need to match from
* where we added the column in the
* manage_wp_posts_be_qe_manage_posts_columns()
* function.
*
* The array value (after the =) should be set to
* identify the data that is going to be sorted,
* i.e. what will be placed in the URL when it's sorted.
* Since my release date is a custom field, I just
* use the custom field name, 'field_products_sale'.
*
* When the column is clicked, the URL will look like this:
* http://mywebsite.com/wp-admin/edit.php?post_type=products&orderby=field_products_sale&order=asc
*/
$sortable_columns[ 'field_products_sale' ] = 'field_products_sale';
$sortable_columns[ 'field_products_description_under_button' ] = 'field_products_description_under_button';
return $sortable_columns;
}
/**
* Now that we have a column, we need to fill our column with data.
* The filters to populate your custom column are pretty similar to the ones
* that added your column: 'manage_pages_custom_column', 'manage_posts_custom_column',
* and 'manage_{$post_type_name}_posts_custom_column'. All three pass the same
* 2 arguments: $column_name (a string) and the $post_id (an integer).
*
* Our custom column data is post meta so it will be a pretty simple case of retrieving
* the post meta with the meta key 'field_products_sale'.
*
* Note that we are wrapping our post meta in a div with an id of �field_products_sale-� plus the post id.
* This will come in handy when we are populating our �Quick Edit� row.
*/
add_action( 'manage_posts_custom_column', 'manage_wp_posts_be_qe_manage_posts_custom_column', 10, 2 );
function manage_wp_posts_be_qe_manage_posts_custom_column( $column_name, $post_id ) {
switch( $column_name ) {
case 'field_products_sale':
echo '<span class="produce-sale ' . get_post_meta( $post_id, 'products_sale', true ) . '"></span><div id="field_products_sale-' . $post_id . '">' . get_post_meta( $post_id, 'products_sale', true ) . '</div>';
break;
case 'field_products_description_under_button':
echo '<div id="products_description_under_button-' . $post_id . '">' . get_post_meta( $post_id, 'products_description_under_button', true ) . '</div>';
break;
}
}
/**
* Just because we've made the column sortable doesn't
* mean the posts will sort by our column data. That's where
* this next 2 filters come into play.
*
* If your sort data is simple, i.e. alphabetically or numerically,
* then 'pre_get_posts' is the filter to use. This filter lets you
* change up the query before it's run.
*
* If your orderby data is more complicated, like our release date
* which is a date string stored in a custom field, then check out
* the 'posts_clauses' filter example used below.
*
* In the example below, when the main query is trying to order by
* the 'film_rating', it's a simple alphabetical sorting by a custom
* field so we're telling the query to set our 'meta_key' which is
* 'film_rating' and that we want to order by the query by the
* custom field's meta_value, e.g. PG, PG-13, R, etc.
*
* Check out http://codex.wordpress.org/Class_Reference/WP_Query
* for more info on WP Query parameters.
*/
add_action( 'pre_get_posts', 'manage_wp_posts_be_qe_pre_get_posts', 1 );
function manage_wp_posts_be_qe_pre_get_posts( $query ) {
/**
* We only want our code to run in the main WP query
* AND if an orderby query variable is designated.
*/
if ( $query->is_main_query() && ( $orderby = $query->get( 'orderby' ) ) ) {
switch( $orderby ) {
// If we're ordering by 'film_rating'
case 'field_products_sale':
// set our query's meta_key, which is used for custom fields
$query->set( 'meta_key', 'products_sale' );
/**
* Tell the query to order by our custom field/meta_key's
* value, in this case: PG, PG-13, R, etc.
*
* If your meta value are numbers, change
* 'meta_value' to 'meta_value_num'.
*/
$query->set( 'orderby', 'meta_value' );
break;
// If we're ordering by 'film_rating'
case 'field_products_description_under_button':
// set our query's meta_key, which is used for custom fields
$query->set( 'meta_key', 'products_description_under_button' );
/**
* Tell the query to order by our custom field/meta_key's
* value, in this case: PG, PG-13, R, etc.
*
* If your meta value are numbers, change
* 'meta_value' to 'meta_value_num'.
*/
$query->set( 'orderby', 'meta_value' );
break;
}
}
}
/**
* Just because we've made the column sortable doesn't
* mean the posts will sort by our column data. That's where
* the filter above, 'pre_get_posts', and the filter below,
* 'posts_clauses', come into play.
*
* If your sort data is simple, i.e. alphabetically or numerically,
* then check out the 'pre_get_posts' filter used above.
*
* If your orderby data is more complicated, like combining
* several values or a date string stored in a custom field,
* then the 'posts_clauses' filter used below is for you.
* The 'posts_clauses' filter allows you to manually Tweak
* the query clauses in order to sort the posts by your
* custom column data.
*
* The reason more complicated sorts will not with the
* "out of the box" WP Query is because the WP Query orderby
* parameter will only order alphabetically and numerically.
*
* Usually I would recommend simply using the 'pre_get_posts'
* and altering the WP Query itself but because our custom
* field is a date, we have to manually set the query to
* order our posts by a date.
*/
add_filter( 'posts_clauses', 'manage_wp_posts_be_qe_posts_clauses', 1, 2 );
function manage_wp_posts_be_qe_posts_clauses( $pieces, $query ) {
global $wpdb;
/**
* We only want our code to run in the main WP query
* AND if an orderby query variable is designated.
*/
if ( $query->is_main_query() && ( $orderby = $query->get( 'orderby' ) ) ) {
// Get the order query variable - ASC or DESC
$order = strtoupper( $query->get( 'order' ) );
// Make sure the order setting qualifies. If not, set default as ASC
if ( ! in_array( $order, array( 'ASC', 'DESC' ) ) )
$order = 'ASC';
switch( $orderby ) {
// If we're ordering by field_products_sale
case 'field_products_sale':
/**
* We have to join the postmeta table to include
* our release date in the query.
*/
$pieces[ 'join' ] .= " LEFT JOIN $wpdb->postmeta wp_rd ON wp_rd.post_id = {$wpdb->posts}.ID AND wp_rd.meta_key = 'field_products_sale'";
// Then tell the query to order by our date
$pieces[ 'orderby' ] = "STR_TO_DATE( wp_rd.meta_value,'%m/%d/%Y' ) $order, " . $pieces[ 'orderby' ];
break;
// If we're ordering by field_products_sale
case 'field_products_description_under_button':
/**
* We have to join the postmeta table to include
* our release date in the query.
*/
$pieces[ 'join' ] .= " LEFT JOIN $wpdb->postmeta wp_rd ON wp_rd.post_id = {$wpdb->posts}.ID AND wp_rd.meta_key = 'field_products_description_under_button'";
// Then tell the query to order by our date
$pieces[ 'orderby' ] = "STR_TO_DATE( wp_rd.meta_value,'%m/%d/%Y' ) $order, " . $pieces[ 'orderby' ];
break;
}
}
return $pieces;
}
/**
* Now that you have your custom column, it's bulk/quick edit showtime!
* The filters are 'bulk_edit_custom_box' and 'quick_edit_custom_box'. Both filters
* pass the same 2 arguments: the $column_name (a string) and the $post_type (a string).
*
* Your data's form fields will obviously vary so customize at will. For this example,
* we're using an input. Also take note of the css classes on the <fieldset> and <div>.
* There are a few other options like 'inline-edit-col-left' and 'inline-edit-col-center'
* for the fieldset and 'inline-edit-col' for the div. I recommend studying the WordPress
* bulk and quick edit HTML to see the best way to layout your custom fields.
*/
add_action( 'bulk_edit_custom_box', 'manage_wp_posts_be_qe_bulk_quick_edit_custom_box', 10, 2 );
add_action( 'quick_edit_custom_box', 'manage_wp_posts_be_qe_bulk_quick_edit_custom_box', 10, 2 );
function manage_wp_posts_be_qe_bulk_quick_edit_custom_box( $column_name, $post_type ) {
switch ( $post_type ) {
case 'products':
switch( $column_name ) {
case 'field_products_sale':
?><fieldset class="inline-edit-col-left">
<div class="inline-edit-col">
<label>
<span class="title">Products Sale</span>
<span class="input-text-wrap">
<input type="text" value="" name="field_products_sale">
</span>
</label>
</div>
</fieldset><?php
break;
case 'field_products_description_under_button':
?><fieldset class="inline-edit-col-left">
<div class="inline-edit-col">
<label>
<span class="title">Sale Description</span>
<span class="input-text-wrap">
<input type="text" value="" name="field_products_description_under_button">
</span>
</label>
</div>
</fieldset><?php
break;
}
break;
}
}
/**
* When you click 'Quick Edit', you may have noticed that your form fields are not populated.
* WordPress adds one 'Quick Edit' row which moves around for each post so the information cannot
* be pre-populated. It has to be populated with JavaScript on a per-post 'click Quick Edit' basis.
*
* WordPress has an inline edit post function that populates all of their default quick edit fields
* so we want to hook into this function, in a sense, to make sure our JavaScript code is run when
* needed. We will 'copy' the WP function, 'overwrite' the WP function so we're hooked in, 'call'
* the original WP function (via our copy) so WordPress is not left hanging, and then run our code.
*
* Remember where we wrapped our column data in a <div> in Step 2? This is where it comes in handy,
* allowing our Javascript to retrieve the data by the <div>'s element ID to populate our form field.
* There are other methods to retrieve your data that involve AJAX but this route is the simplest.
*
* Don't forget to enqueue your script and make sure it's dependent on WordPress's 'inline-edit-post' file.
* Since we'll be using the jQuery library, we need to make sure 'jquery' is loaded as well.
*
* I have provided several scenarios for where you've placed this code. Simply uncomment the scenario
* you're using. For all scenarios, make sure your javascript file is in the same folder as your code.
*/
add_action( 'admin_print_scripts-edit.php', 'manage_wp_posts_be_qe_enqueue_admin_scripts' );
function manage_wp_posts_be_qe_enqueue_admin_scripts() {
// if code is in theme functions.php file
//wp_enqueue_script( 'manage-wp-posts-using-bulk-quick-edit', trailingslashit( get_bloginfo( 'stylesheet_directory' ) ) . 'bulk_quick_edit.js', array( 'jquery', 'inline-edit-post' ), '', true );
// if using code as plugin
wp_enqueue_script( 'manage-wp-posts-using-bulk-quick-edit', trailingslashit( plugin_dir_url( __FILE__ ) ) . 'bulk_quick_edit.js', array( 'jquery', 'inline-edit-post' ), '', true );
}
/**
* Saving your 'Quick Edit' data is exactly like saving custom data
* when editing a post, using the 'save_post' hook. With that said,
* you may have already set this up. If you're not sure, and your
* 'Quick Edit' data is not saving, odds are you need to hook into
* the 'save_post' action.
*
* The 'save_post' action passes 2 arguments: the $post_id (an integer)
* and the $post information (an object).
*/
add_action( 'save_post', 'save_quick_edit_custom_fields', 10, 2 );
function save_quick_edit_custom_fields( $post_id, $post ) {
// pointless if $_POST is empty (this happens on bulk edit)
if ( empty( $_POST ) )
return $post_id;
// verify quick edit nonce
if ( isset( $_POST[ '_inline_edit' ] ) && ! wp_verify_nonce( $_POST[ '_inline_edit' ], 'inlineeditnonce' ) )
return $post_id;
// don't save for autosave
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return $post_id;
// dont save for revisions
if ( isset( $post->post_type ) && $post->post_type == 'revision' )
return $post_id;
switch( $post->post_type ) {
case 'products':
/**
* Because this action is run in several places, checking for the array key
* keeps WordPress from editing data that wasn't in the form, i.e. if you had
* this post meta on your "Quick Edit" but didn't have it on the "Edit Post" screen.
*/
$custom_fields = array( 'products_sale', 'products_description_under_button' );
foreach( $custom_fields as $field ) {
if ( array_key_exists( $field, $_POST ) )
update_post_meta( $post_id, $field, $_POST[ $field ] );
}
break;
}
}
/**
* Saving the 'Bulk Edit' data is a little trickier because we have
* to get JavaScript involved. WordPress saves their bulk edit data
* via AJAX so, guess what, so do we.
*
* Your javascript will run an AJAX function to save your data.
* This is the WordPress AJAX function that will handle and save your data.
*/
add_action( 'wp_ajax_manage_wp_posts_using_bulk_quick_save_bulk_edit', 'manage_wp_posts_using_bulk_quick_save_bulk_edit' );
function manage_wp_posts_using_bulk_quick_save_bulk_edit() {
// we need the post IDs
$post_ids = ( isset( $_POST[ 'post_ids' ] ) && !empty( $_POST[ 'post_ids' ] ) ) ? $_POST[ 'post_ids' ] : NULL;
// if we have post IDs
if ( ! empty( $post_ids ) && is_array( $post_ids ) ) {
// get the custom fields
$custom_fields = array( 'products_sale', 'products_description_under_button' );
foreach( $custom_fields as $field ) {
// if it has a value, doesn't update if empty on bulk
if ( isset( $_POST[ $field ] ) && !empty( $_POST[ $field ] ) ) {
// update for each post ID
foreach( $post_ids as $post_id ) {
update_post_meta( $post_id, $field, $_POST[ $field ] );
}
}
}
}
}
?>
クイック編集プラグインのJavaScript
(function($) {
// we create a copy of the WP inline edit post function
var $wp_inline_edit = inlineEditPost.edit;
// and then we overwrite the function with our own code
inlineEditPost.edit = function( id ) {
// "call" the original WP edit function
// we don't want to leave WordPress hanging
$wp_inline_edit.apply( this, arguments );
// now we take care of our business
// get the post ID
var $post_id = 0;
if ( typeof( id ) == 'object' )
$post_id = parseInt( this.getId( id ) );
if ( $post_id > 0 ) {
// define the edit row
var $edit_row = $( '#edit-' + $post_id );
// get the release date
var $products_sale = $( '#field_products_sale-' + $post_id ).text();
var $products_description_under_button = $( '#products_description_under_button-' + $post_id ).text();
// set the release date
$edit_row.find( 'input[name="field_products_sale"]' ).val( $products_sale );
$edit_row.find( 'input[name="field_products_description_under_button"]' ).val( $products_description_under_button );
}
};
$( '#bulk_edit' ).live( 'click', function() {
// define the bulk edit row
var $bulk_row = $( '#bulk-edit' );
// get the selected post ids that are being edited
var $post_ids = new Array();
$bulk_row.find( '#bulk-titles' ).children().each( function() {
$post_ids.Push( $( this ).attr( 'id' ).replace( /^(ttle)/i, '' ) );
});
// get the custom fields
var $products_sale = $bulk_row.find( 'input[name="field_products_sale"]' ).val();
var $products_description_under_button = $bulk_row.find( 'input[name="field_products_description_under_button"]' ).val();
// save the data
$.ajax({
url: ajaxurl, // this is a variable that WordPress has already defined for us
type: 'POST',
async: false,
cache: false,
data: {
action: 'manage_wp_posts_using_bulk_quick_save_bulk_edit', // this is the name of our WP AJAX function that we'll set up next
post_ids: $post_ids, // and these are the 2 parameters we're passing to our function
products_sale: $products_sale,
products_description_under_button: $products_description_under_button
}
});
});
console.log("new version 1");
$( 'button.save' ).live( 'click', function() {
console.log("uh oh!");
// define the bulk edit row
var $quick_edit_row = $( '.inline-edit-row' );
// get the selected post ids that are being edited
var $post_ids = $quick_edit_row.attr( 'id' ).replace( /^(edit-)/i, '' );
// get the custom fields
var $products_sale = $quick_edit_row.find( 'input[name="field_products_sale"]' ).val();
var $products_description_under_button = $quick_edit_row.find( 'input[name="field_products_description_under_button"]' ).val();
// save the data
$.ajax({
url: ajaxurl, // this is a variable that WordPress has already defined for us
type: 'POST',
async: false,
cache: false,
data: {
action: 'manage_wp_posts_using_bulk_quick_save_bulk_edit', // this is the name of our WP AJAX function that we'll set up next
post_ids: $post_ids, // and these are the 2 parameters we're passing to our function
products_sale: $products_sale,
products_description_under_button: $products_description_under_button
}
});
});
})(jQuery);
私のカスタム投稿タイプの場合はPHP
<?php
add_action( 'init', 'grav_custom_post_type_products' );
function grav_custom_post_type_products()
{
$single_label = 'Product';
$plural_label = $single_label.'s';
$name = strtolower(str_replace(' ', '-', $plural_label));
$slug = $name;
register_post_type($name, array(
'label' => $plural_label,
'description' => '',
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'capability_type' => 'post',
'map_meta_cap' => true,
'hierarchical' => false,
'rewrite' => array('with_front' => false, 'slug' => $slug),
'query_var' => true,
'exclude_from_search' => false,
'can_export' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-star-empty',
'supports' => array('title','editor','excerpt','thumbnail'),
'labels' => array (
'name' => $plural_label,
'singular_name' => $single_label,
'menu_name' => $plural_label,
'add_new' => 'Add '.$single_label,
'add_new_item' => 'Add New '.$single_label,
'edit' => 'Edit',
'edit_item' => 'Edit '.$single_label,
'new_item' => 'New '.$single_label,
'view' => 'View '.$single_label,
'view_item' => 'View '.$single_label,
'search_items' => 'Search '.$plural_label,
'not_found' => 'No '.$plural_label.' Found',
'not_found_in_trash' => 'No '.$plural_label.' Found in Trash',
'parent' => 'Parent '.$single_label,
)));
register_taxonomy(
$name.'_categories',
$name,
array(
'labels' => array (
'name' => $plural_label.' Categories',
'singular_name' => 'Category',
'menu_name' => $plural_label.' Categories',
'add_new' => 'Add '.$plural_label,
'add_new_item' => 'Add New Category',
'edit' => 'Edit',
'edit_item' => 'Edit Category',
'new_item' => 'New Category',
'view' => 'View Category',
'view_item' => 'View Category',
'search_items' => 'Search Categories',
),
'hierarchical' => true,
'rewrite' => array('with_front' => false, 'slug' => $name.'-categories' )
)
);
}
?>
PHP _ products_sale
カスタムフィールドの場合
array (
'key' => 'field_products_sale',
'label' => 'Sale',
'name' => 'products_sale',
'type' => 'text',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => array (
'width' => '',
'class' => 'icomoon-select',
'id' => '',
),
'default_value' => '',
'placeholder' => '',
'formatting' => 'none', // none | html
'prepend' => '',
'append' => '',
'maxlength' => '',
'readonly' => 0,
'disabled' => 0,
)
GitHubで参照されているコードをダウンロードしてアクティブ化し、元の例と一致するように movies のカスタム投稿タイプ登録コードを追加しました。
manage_wp_posts_be_qe_bulk_quick_edit_custom_box()
のswitchステートメントがrelease_date
、coming_soon
、およびfilm_rating
の代わりにrelease_date_column
、coming_soon_column
、およびfilm_rating_column
をチェックするというバグがGitHubのコードにあることに気付いたので、それらの問題を修正しました。その後、例は私のために働きました。クイック編集と一括編集の両方で、予想される値が保存されます。
以下の例のJSと同様に、調整されたPHPを貼り付けました。
<?php
/**
* Plugin Name: Manage WordPress Posts Using Bulk Edit and Quick Edit
* Description: This is the code for a tutorial WP Dreamer wrote about managing WordPress posts using bulk and quick edit.
* Author: WP Dreamer
* Author URI: http://wpdreamer.com/2012/03/manage-wordpress-posts-using-bulk-edit-and-quick-edit/
*/
/**
* I decided to convert the tutorial to a plugin format
* so I could easily monitor it on my development environment
* and store it on GitHub.
*
* With that said, you could easily take this code and paste it
* into your theme's functions.php file. There is, however,
* an included javascript file so be sure to check the
* manage_wp_posts_be_qe_enqueue_admin_scripts()
* function to confirm you're enqueueing the right javascript file.
*
* Also, after a few requests for custom field examples other than
* text boxes, I updated the tutorial to include a select dropdown
* and a radio button.
*
* Custom Fields:
* 'Release Date - input text
* 'Coming Soon' - input radio
* 'Film Rating' - select dropdown
*
* If you find any issues with the tutorial, or code, please let me know. Thanks!
*/
/**
* Since Bulk Edit and Quick Edit hooks are triggered by custom columns,
* you must first add custom columns for the fields you wish to add, which are setup by
* 'filtering' the column information.
*
* There are 3 different column filters: 'manage_pages_columns' for pages,
* 'manage_posts_columns' which covers ALL post types (including custom post types),
* and 'manage_{$post_type_name}_posts_columns' which only covers, you guessed it,
* the columns for the defined $post_type_name.
*
* The 'manage_pages_columns' and 'manage_{$post_type_name}_posts_columns' filters only
* pass $columns (an array), which is the column info, as an argument, but 'manage_posts_columns'
* passes $columns and $post_type (a string).
*
* Note: Don't forget that it's a WordPress filter so you HAVE to return the first argument that's
* passed to the function, in this case $columns. And for filters that pass more than 1 argument,
* you have to specify the number of accepted arguments in your add_filter() declaration,
* following the priority argument.
*
*/
add_filter( 'manage_posts_columns', 'manage_wp_posts_be_qe_manage_posts_columns', 10, 2 );
function manage_wp_posts_be_qe_manage_posts_columns( $columns, $post_type ) {
/**
* The first example adds our new columns at the end.
* Notice that we're specifying a post type because our function covers ALL post types.
*
* Uncomment this code if you want to add your column at the end
*/
/*if ( $post_type == 'movies' ) {
$columns[ 'release_date' ] = 'Release Date';
$columns[ 'coming_soon' ] = 'Coming Soon';
$columns[ 'film_rating' ] = 'Film Rating';
}
return $columns;*/
/**
* The second example adds our new column after the ÒTitleÓ column.
* Notice that we're specifying a post type because our function covers ALL post types.
*/
switch ( $post_type ) {
case 'movies':
// building a new array of column data
$new_columns = array();
foreach( $columns as $key => $value ) {
// default-ly add every original column
$new_columns[ $key ] = $value;
/**
* If currently adding the title column,
* follow immediately with our custom columns.
*/
if ( $key == 'title' ) {
$new_columns[ 'release_date_column' ] = 'Release Date';
$new_columns[ 'coming_soon_column' ] = 'Coming Soon';
$new_columns[ 'film_rating_column' ] = 'Film Rating';
}
}
return $new_columns;
}
return $columns;
}
/**
* The following filter allows you to make your column(s) sortable.
*
* The 'edit-movies' section of the filter name is the custom part
* of the filter name, which tells WordPress you want this to run
* on the main 'movies' custom post type edit screen. So, e.g., if
* your custom post type's name was 'books', then the filter name
* would be 'manage_edit-books_sortable_columns'.
*
* Don't forget that filters must ALWAYS return a value.
*/
add_filter( 'manage_edit-movies_sortable_columns', 'manage_wp_posts_be_qe_manage_sortable_columns' );
function manage_wp_posts_be_qe_manage_sortable_columns( $sortable_columns ) {
/**
* In order to make a column sortable, add the
* column data to the $sortable_columns array.
*
* I want to make my 'Release Date' column
* sortable so the array indexes (the 'release_date_column'
* value between the []) need to match from
* where we added the column in the
* manage_wp_posts_be_qe_manage_posts_columns()
* function.
*
* The array value (after the =) should be set to
* identify the data that is going to be sorted,
* i.e. what will be placed in the URL when it's sorted.
* Since my release date is a custom field, I just
* use the custom field name, 'release_date'.
*
* When the column is clicked, the URL will look like this:
* http://mywebsite.com/wp-admin/edit.php?post_type=movies&orderby=release_date&order=asc
*/
$sortable_columns[ 'release_date_column' ] = 'release_date';
// Let's also make the film rating column sortable
$sortable_columns[ 'film_rating_column' ] = 'film_rating';
return $sortable_columns;
}
/**
* Now that we have a column, we need to fill our column with data.
* The filters to populate your custom column are pretty similar to the ones
* that added your column: 'manage_pages_custom_column', 'manage_posts_custom_column',
* and 'manage_{$post_type_name}_posts_custom_column'. All three pass the same
* 2 arguments: $column_name (a string) and the $post_id (an integer).
*
* Our custom column data is post meta so it will be a pretty simple case of retrieving
* the post meta with the meta key 'release_date'.
*
* Note that we are wrapping our post meta in a div with an id of Òrelease_date-Ó plus the post id.
* This will come in handy when we are populating our ÒQuick EditÓ row.
*/
add_action( 'manage_posts_custom_column', 'manage_wp_posts_be_qe_manage_posts_custom_column', 10, 2 );
function manage_wp_posts_be_qe_manage_posts_custom_column( $column_name, $post_id ) {
switch( $column_name ) {
case 'release_date_column':
echo '<div id="release_date-' . $post_id . '">' . get_post_meta( $post_id, 'release_date', true ) . '</div>';
break;
case 'coming_soon_column':
echo '<div id="coming_soon-' . $post_id . '">' . get_post_meta( $post_id, 'coming_soon', true ) . '</div>';
break;
case 'film_rating_column':
echo '<div id="film_rating-' . $post_id . '">' . get_post_meta( $post_id, 'film_rating', true ) . '</div>';
break;
}
}
/**
* Just because we've made the column sortable doesn't
* mean the posts will sort by our column data. That's where
* this next 2 filters come into play.
*
* If your sort data is simple, i.e. alphabetically or numerically,
* then 'pre_get_posts' is the filter to use. This filter lets you
* change up the query before it's run.
*
* If your orderby data is more complicated, like our release date
* which is a date string stored in a custom field, then check out
* the 'posts_clauses' filter example used below.
*
* In the example below, when the main query is trying to order by
* the 'film_rating', it's a simple alphabetical sorting by a custom
* field so we're telling the query to set our 'meta_key' which is
* 'film_rating' and that we want to order by the query by the
* custom field's meta_value, e.g. PG, PG-13, R, etc.
*
* Check out http://codex.wordpress.org/Class_Reference/WP_Query
* for more info on WP Query parameters.
*/
add_action( 'pre_get_posts', 'manage_wp_posts_be_qe_pre_get_posts', 1 );
function manage_wp_posts_be_qe_pre_get_posts( $query ) {
/**
* We only want our code to run in the main WP query
* AND if an orderby query variable is designated.
*/
if ( $query->is_main_query() && ( $orderby = $query->get( 'orderby' ) ) ) {
switch( $orderby ) {
// If we're ordering by 'film_rating'
case 'film_rating':
// set our query's meta_key, which is used for custom fields
$query->set( 'meta_key', 'film_rating' );
/**
* Tell the query to order by our custom field/meta_key's
* value, in this case: PG, PG-13, R, etc.
*
* If your meta value are numbers, change
* 'meta_value' to 'meta_value_num'.
*/
$query->set( 'orderby', 'meta_value' );
break;
}
}
}
/**
* Just because we've made the column sortable doesn't
* mean the posts will sort by our column data. That's where
* the filter above, 'pre_get_posts', and the filter below,
* 'posts_clauses', come into play.
*
* If your sort data is simple, i.e. alphabetically or numerically,
* then check out the 'pre_get_posts' filter used above.
*
* If your orderby data is more complicated, like combining
* several values or a date string stored in a custom field,
* then the 'posts_clauses' filter used below is for you.
* The 'posts_clauses' filter allows you to manually Tweak
* the query clauses in order to sort the posts by your
* custom column data.
*
* The reason more complicated sorts will not with the
* "out of the box" WP Query is because the WP Query orderby
* parameter will only order alphabetically and numerically.
*
* Usually I would recommend simply using the 'pre_get_posts'
* and altering the WP Query itself but because our custom
* field is a date, we have to manually set the query to
* order our posts by a date.
*/
add_filter( 'posts_clauses', 'manage_wp_posts_be_qe_posts_clauses', 1, 2 );
function manage_wp_posts_be_qe_posts_clauses( $pieces, $query ) {
global $wpdb;
/**
* We only want our code to run in the main WP query
* AND if an orderby query variable is designated.
*/
if ( $query->is_main_query() && ( $orderby = $query->get( 'orderby' ) ) ) {
// Get the order query variable - ASC or DESC
$order = strtoupper( $query->get( 'order' ) );
// Make sure the order setting qualifies. If not, set default as ASC
if ( ! in_array( $order, array( 'ASC', 'DESC' ) ) )
$order = 'ASC';
switch( $orderby ) {
// If we're ordering by release_date
case 'release_date':
/**
* We have to join the postmeta table to include
* our release date in the query.
*/
$pieces[ 'join' ] .= " LEFT JOIN $wpdb->postmeta wp_rd ON wp_rd.post_id = {$wpdb->posts}.ID AND wp_rd.meta_key = 'release_date'";
// Then tell the query to order by our date
$pieces[ 'orderby' ] = "STR_TO_DATE( wp_rd.meta_value,'%m/%d/%Y' ) $order, " . $pieces[ 'orderby' ];
break;
}
}
return $pieces;
}
/**
* Now that you have your custom column, it's bulk/quick edit showtime!
* The filters are 'bulk_edit_custom_box' and 'quick_edit_custom_box'. Both filters
* pass the same 2 arguments: the $column_name (a string) and the $post_type (a string).
*
* Your data's form fields will obviously vary so customize at will. For this example,
* we're using an input. Also take note of the css classes on the <fieldset> and <div>.
* There are a few other options like 'inline-edit-col-left' and 'inline-edit-col-center'
* for the fieldset and 'inline-edit-col' for the div. I recommend studying the WordPress
* bulk and quick edit HTML to see the best way to layout your custom fields.
*/
add_action( 'bulk_edit_custom_box', 'manage_wp_posts_be_qe_bulk_quick_edit_custom_box', 10, 2 );
add_action( 'quick_edit_custom_box', 'manage_wp_posts_be_qe_bulk_quick_edit_custom_box', 10, 2 );
function manage_wp_posts_be_qe_bulk_quick_edit_custom_box( $column_name, $post_type ) {
switch ( $post_type ) {
case 'movies':
switch( $column_name ) {
case 'release_date_column':
?><fieldset class="inline-edit-col-left">
<div class="inline-edit-col">
<label>
<span class="title">Release Date</span>
<span class="input-text-wrap">
<input type="text" value="" name="release_date">
</span>
</label>
</div>
</fieldset><?php
break;
case 'coming_soon_column':
?><fieldset class="inline-edit-col-left">
<div class="inline-edit-col">
<label>
<span class="title">Coming Soon</span>
<span class="input-text-wrap">
<label style="display:inline;">
<input type="radio" name="coming_soon" value="Yes" /> Yes
</label>
<label style="display:inline;">
<input type="radio" name="coming_soon" value="No" /> No
</label>
</span>
</label>
</div>
</fieldset><?php
break;
case 'film_rating_column':
?><fieldset class="inline-edit-col-left">
<div class="inline-edit-col">
<label>
<span class="title">Film rating</span>
<span class="input-text-wrap">
<select name="film_rating">
<option value="">Rating</option>
<option value="G">G</option>
<option value="PG">PG</option>
<option value="PG-13">PG-13</option>
<option value="R">R</option>
<option value="NC-17">NC-17</option>
<option value="X">X</option>
<option value="GP">GP</option>
<option value="M">M</option>
<option value="M/PG">M/PG</option>
</select>
</span>
</label>
</div>
</fieldset><?php
break;
}
break;
}
}
/**
* When you click 'Quick Edit', you may have noticed that your form fields are not populated.
* WordPress adds one 'Quick Edit' row which moves around for each post so the information cannot
* be pre-populated. It has to be populated with JavaScript on a per-post 'click Quick Edit' basis.
*
* WordPress has an inline edit post function that populates all of their default quick edit fields
* so we want to hook into this function, in a sense, to make sure our JavaScript code is run when
* needed. We will 'copy' the WP function, 'overwrite' the WP function so we're hooked in, 'call'
* the original WP function (via our copy) so WordPress is not left hanging, and then run our code.
*
* Remember where we wrapped our column data in a <div> in Step 2? This is where it comes in handy,
* allowing our Javascript to retrieve the data by the <div>'s element ID to populate our form field.
* There are other methods to retrieve your data that involve AJAX but this route is the simplest.
*
* Don't forget to enqueue your script and make sure it's dependent on WordPress's 'inline-edit-post' file.
* Since we'll be using the jQuery library, we need to make sure 'jquery' is loaded as well.
*
* I have provided several scenarios for where you've placed this code. Simply uncomment the scenario
* you're using. For all scenarios, make sure your javascript file is in the same folder as your code.
*/
add_action( 'admin_print_scripts-edit.php', 'manage_wp_posts_be_qe_enqueue_admin_scripts' );
function manage_wp_posts_be_qe_enqueue_admin_scripts() {
// if code is in theme functions.php file
//wp_enqueue_script( 'manage-wp-posts-using-bulk-quick-edit', trailingslashit( get_bloginfo( 'stylesheet_directory' ) ) . 'bulk_quick_edit.js', array( 'jquery', 'inline-edit-post' ), '', true );
// if using code as plugin
wp_enqueue_script( 'manage-wp-posts-using-bulk-quick-edit', trailingslashit( plugin_dir_url( __FILE__ ) ) . 'bulk_quick_edit.js', array( 'jquery', 'inline-edit-post' ), '', true );
}
/**
* Saving your 'Quick Edit' data is exactly like saving custom data
* when editing a post, using the 'save_post' hook. With that said,
* you may have already set this up. If you're not sure, and your
* 'Quick Edit' data is not saving, odds are you need to hook into
* the 'save_post' action.
*
* The 'save_post' action passes 2 arguments: the $post_id (an integer)
* and the $post information (an object).
*/
add_action( 'save_post', 'manage_wp_posts_be_qe_save_post', 10, 2 );
function manage_wp_posts_be_qe_save_post( $post_id, $post ) {
// pointless if $_POST is empty (this happens on bulk edit)
if ( empty( $_POST ) )
return $post_id;
// verify quick edit nonce
if ( isset( $_POST[ '_inline_edit' ] ) && ! wp_verify_nonce( $_POST[ '_inline_edit' ], 'inlineeditnonce' ) )
return $post_id;
// don't save for autosave
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return $post_id;
// dont save for revisions
if ( isset( $post->post_type ) && $post->post_type == 'revision' )
return $post_id;
switch( $post->post_type ) {
case 'movies':
/**
* Because this action is run in several places, checking for the array key
* keeps WordPress from editing data that wasn't in the form, i.e. if you had
* this post meta on your "Quick Edit" but didn't have it on the "Edit Post" screen.
*/
$custom_fields = array( 'release_date', 'coming_soon', 'film_rating' );
foreach( $custom_fields as $field ) {
if ( array_key_exists( $field, $_POST ) )
update_post_meta( $post_id, $field, $_POST[ $field ] );
}
break;
}
}
/**
* Saving the 'Bulk Edit' data is a little trickier because we have
* to get JavaScript involved. WordPress saves their bulk edit data
* via AJAX so, guess what, so do we.
*
* Your javascript will run an AJAX function to save your data.
* This is the WordPress AJAX function that will handle and save your data.
*/
add_action( 'wp_ajax_manage_wp_posts_using_bulk_quick_save_bulk_edit', 'manage_wp_posts_using_bulk_quick_save_bulk_edit' );
function manage_wp_posts_using_bulk_quick_save_bulk_edit() {
// we need the post IDs
$post_ids = ( isset( $_POST[ 'post_ids' ] ) && !empty( $_POST[ 'post_ids' ] ) ) ? $_POST[ 'post_ids' ] : NULL;
// if we have post IDs
if ( ! empty( $post_ids ) && is_array( $post_ids ) ) {
// get the custom fields
$custom_fields = array( 'release_date', 'coming_soon', 'film_rating' );
foreach( $custom_fields as $field ) {
// if it has a value, doesn't update if empty on bulk
if ( isset( $_POST[ $field ] ) && !empty( $_POST[ $field ] ) ) {
// update for each post ID
foreach( $post_ids as $post_id ) {
update_post_meta( $post_id, $field, $_POST[ $field ] );
}
}
}
}
}
// Register 'movies' cpt for this demo.
add_action( 'init', 'wpse237805_register_movies' );
function wpse237805_register_movies() {
$labels = array(
"name" => __( 'Movies', 'textdomain' ),
"singular_name" => __( 'Movie', 'textdomain' ),
);
$args = array(
"label" => __( 'Movies', 'textdomain' ),
"labels" => $labels,
"description" => "",
"public" => true,
"publicly_queryable" => true,
"show_ui" => true,
"show_in_rest" => false,
"rest_base" => "",
"has_archive" => false,
"show_in_menu" => true,
"exclude_from_search" => false,
"capability_type" => "post",
"map_meta_cap" => true,
"hierarchical" => false,
"rewrite" => array( "slug" => "movies", "with_front" => true ),
"query_var" => true,
"supports" => array( "title", "editor", "custom-fields" ),
);
register_post_type( "movies", $args );
}
bulk_quick_edit.js:
(function($) {
// we create a copy of the WP inline edit post function
var $wp_inline_edit = inlineEditPost.edit;
// and then we overwrite the function with our own code
inlineEditPost.edit = function( id ) {
// "call" the original WP edit function
// we don't want to leave WordPress hanging
$wp_inline_edit.apply( this, arguments );
// now we take care of our business
// get the post ID
var $post_id = 0;
if ( typeof( id ) == 'object' )
$post_id = parseInt( this.getId( id ) );
if ( $post_id > 0 ) {
// define the edit row
var $edit_row = $( '#edit-' + $post_id );
// get the release date
var $release_date = $( '#release_date-' + $post_id ).text();
// set the release date
$edit_row.find( 'input[name="release_date"]' ).val( $release_date );
// get the release date
var $coming_soon = $( '#coming_soon-' + $post_id ).text();
// set the film rating
$edit_row.find( 'input[name="coming_soon"][value="' + $coming_soon + '"]' ).prop( 'checked', true );
// get the film rating
var $film_rating = $( '#film_rating-' + $post_id ).text();
// set the film rating
$edit_row.find( 'select[name="film_rating"]' ).val( $film_rating );
}
};
$( '#bulk_edit' ).live( 'click', function() {
// define the bulk edit row
var $bulk_row = $( '#bulk-edit' );
// get the selected post ids that are being edited
var $post_ids = new Array();
$bulk_row.find( '#bulk-titles' ).children().each( function() {
$post_ids.Push( $( this ).attr( 'id' ).replace( /^(ttle)/i, '' ) );
});
// get the custom fields
var $release_date = $bulk_row.find( 'input[name="release_date"]' ).val();
var $coming_soon = $bulk_row.find( 'input[name="coming_soon"]:checked' ).val();
var $film_rating = $bulk_row.find( 'select[name="film_rating"]' ).val();
// save the data
$.ajax({
url: ajaxurl, // this is a variable that WordPress has already defined for us
type: 'POST',
async: false,
cache: false,
data: {
action: 'manage_wp_posts_using_bulk_quick_save_bulk_edit', // this is the name of our WP AJAX function that we'll set up next
post_ids: $post_ids, // and these are the 2 parameters we're passing to our function
release_date: $release_date,
coming_soon: $coming_soon,
film_rating: $film_rating
}
});
});
})(jQuery);