最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Custom Column in CPT admin table not updated after Quick Edit save

programmeradmin2浏览0评论

I have a CPT named company with custom fields url and partner.

Custom column is shown properly with correct content in CPT admin table. Quick fields are also shown and properly populated for each row.

When the Update button is clicked in Quick Edit the post_meta are properly updated, values saved in database, but column's content is not updated by Ajax. If I refresh the page custom column is displayed correctly but the whole point of this Quick Edit is to avoid a page refresh. Client will not know his changes were saved and will keep quick-editing and lose data. What am I missing?

EDIT: My problem was because of a caching function related to PODS, a framework I am using for custom port_meta and fields. Row was returned after quick edit but values were cached. I overridden caching for these functions and everything worked properly.

Full working code with Quick & Bulk Edit

Custom columns:

add_filter(
    'manage_company_posts_columns',
    function () {
        return [
            'cb'           => true,
            'title'        => _x( 'Title', 'column name' ),
            'partner'      => 'Partner',
            'date'         => __( 'Date' ),
            'last_updated' => __( 'Last Updated' ),
        ];
    }
);

Custom columns content

 add_action(
      'manage_company_posts_custom_column',
        function ( $column, $post_id ) {
            if ( 'last_updated' == $column ) {
                $post_modified = get_post_field( 'post_modified', $post_id );
                if ( ! $post_modified ) {
                    $post_modified = 'Undefined';
                }
                echo date( 'Y-m-d', strtotime( $post_modified ) );
            }
            if ( 'partner' == $column ) {
                 if ( get_post_meta( $post_id , 'partner' , true ) !== '0' ) {
                    echo '<a href="'.get_post_meta($post_id , 'url' , true ) .'">
                          <span class="partner">Partner Company</span></a>';
                 } else {
                    echo 'Not a partner company.';
            }
        }, 10, 2
    );

Quick edit fields

add_action(
    'quick_edit_custom_box',
    function ( $column_name, $post_type ) {           
        if ( $post_type != 'company' ) return;
        switch( $column_name ) :
            case 'partner': {
                wp_nonce_field( 'company_cpt_quick_edit', 'my_nonce' );
                ?> 
                    <fieldset class="inline-edit-col-right">
                        <div class="inline-edit-col">
                            <div class="inline-edit-group wp-clearfix">
                                <label class="alignleft">
                                    <span class="title">Company URL</span>
                                    <input type="text" name="url" value="">
                                </label>
                                <label class="alignleft">
                                    <input type="checkbox" name="partner">
                                    <span class="checkbox-title">Partner Company</span>
                                </label>
                            </div>
                        </div>
                    </fieldset>
                <?php
                break;
            }
        endswitch;
    }, 10, 2
);

Save Post action

add_action(
    'save_post',
    function ( $post_id ){
        if ( empty( $_POST ) ) return $post_id;
        if ( !current_user_can( 'edit_post', $post_id ) ) return $post_id;
        if ( !wp_verify_nonce( $_POST['my_nonce'], 'company_cpt_quick_edit' ) ) return $post_id;
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return $post_id;
        if ( isset( $post->post_type ) && $post->post_type == 'revision' ) return $post_id;

        if ( isset( $_POST['url'] ) ) {
           update_post_meta( $post_id, 'url', $_POST['url'] );
        }
        if ( isset( $_POST['partner'] ) ) {
           update_post_meta( $post_id, 'partner', '1' );
        } else {
           update_post_meta( $post_id, 'partner', '0' );
        }
    }
);

JavaScript for quick edit

jQuery(function($){

    var wp_inline_edit_function = inlineEditPost.edit;

    inlineEditPost.edit = function( post_id ) {

        wp_inline_edit_function.apply( this, arguments );
        
        var id = 0;
        if ( typeof( post_id ) == 'object' ) {
            id = parseInt( this.getId( post_id ) );
        }
 
        if ( id > 0 ) {
            var specific_post_edit_row = $( '#edit-' + id ),
                specific_post_row = $( '#post-' + id ),
                url = $( '.column-partner', specific_post_row ).find('a:first').attr('href'),
                partner = false;
 
            if( $( '.column-partner', specific_post_row ).find('span.partner').length !== 0 ) partner = true;
 
            $( ':input[name="url"]', specific_post_edit_row ).val( url );
            $( ':input[name="partner"]', specific_post_edit_row ).prop('checked', partner );
        }
    }
});

Bulk Edit radio field

add_action(
    'bulk_edit_custom_box',
    function ( $column_name, $post_type ) {           
        if ( $post_type != 'company_single' ) return;
        switch( $column_name ) :
            case 'partner': {
                ?> 
                    <fieldset class="inline-edit-col-right">
                        <div class="inline-edit-col">
                            <div class="inline-edit-group wp-clearfix">
                                <label class="alignleft">
                                    <input type="radio" id="partner" name="partner" class="partner" value="0">
                                    <label for="partner">Partner</label>
                                    <input type="radio" id="non_partner" name="partner" class="partner" value="1">
                                    <label for="non_partner" >Non-partner</label>
                                </label>
                            </div>
                        </div>
                    </fieldset>
                <?php
                break;
            }
        endswitch;
    }, 10, 2
);

Bulk Edit save function

function company_bulk_edit_save_hook() {
    if( empty( $_POST[ 'post_ids' ] ) ) {
        die();
    }
    foreach( $_POST[ 'post_ids' ] as $id ) {

        if ( isset( $_POST['partner'] ) ) {
            update_post_meta( $id, 'partner', $_POST['partner'] );
        } else {
            update_post_meta( $id, 'partner', '0' );
        }

    }
    wp_die();
}
add_action( 'wp_ajax_company_bulk_edit_save', 'company_bulk_edit_save_hook' );

AJAX for Bulk Edit

jQuery(function($){
    $( 'body' ).on( 'click', 'input[name="bulk_edit"]', function() {

        $( this ).after('<span class="spinner is-active"></span>');
 
        var bulk_edit_row = $( 'tr#bulk-edit' ),
            post_ids = new Array(),
            partner = bulk_edit_row.find( '.partner:checked' ).val();
 
        bulk_edit_row.find( '#bulk-titles' ).children().each( function() {
            post_ids.push( $( this ).attr( 'id' ).replace( /^(ttle)/i, '' ) );
        });
 
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            async: false,
            cache: false,
            data: {
                action: 'company_bulk_edit_save',
                post_ids: post_ids,
                partner: partner
            }
        });
    });
});

I have a CPT named company with custom fields url and partner.

Custom column is shown properly with correct content in CPT admin table. Quick fields are also shown and properly populated for each row.

When the Update button is clicked in Quick Edit the post_meta are properly updated, values saved in database, but column's content is not updated by Ajax. If I refresh the page custom column is displayed correctly but the whole point of this Quick Edit is to avoid a page refresh. Client will not know his changes were saved and will keep quick-editing and lose data. What am I missing?

EDIT: My problem was because of a caching function related to PODS, a framework I am using for custom port_meta and fields. Row was returned after quick edit but values were cached. I overridden caching for these functions and everything worked properly.

Full working code with Quick & Bulk Edit

Custom columns:

add_filter(
    'manage_company_posts_columns',
    function () {
        return [
            'cb'           => true,
            'title'        => _x( 'Title', 'column name' ),
            'partner'      => 'Partner',
            'date'         => __( 'Date' ),
            'last_updated' => __( 'Last Updated' ),
        ];
    }
);

Custom columns content

 add_action(
      'manage_company_posts_custom_column',
        function ( $column, $post_id ) {
            if ( 'last_updated' == $column ) {
                $post_modified = get_post_field( 'post_modified', $post_id );
                if ( ! $post_modified ) {
                    $post_modified = 'Undefined';
                }
                echo date( 'Y-m-d', strtotime( $post_modified ) );
            }
            if ( 'partner' == $column ) {
                 if ( get_post_meta( $post_id , 'partner' , true ) !== '0' ) {
                    echo '<a href="'.get_post_meta($post_id , 'url' , true ) .'">
                          <span class="partner">Partner Company</span></a>';
                 } else {
                    echo 'Not a partner company.';
            }
        }, 10, 2
    );

Quick edit fields

add_action(
    'quick_edit_custom_box',
    function ( $column_name, $post_type ) {           
        if ( $post_type != 'company' ) return;
        switch( $column_name ) :
            case 'partner': {
                wp_nonce_field( 'company_cpt_quick_edit', 'my_nonce' );
                ?> 
                    <fieldset class="inline-edit-col-right">
                        <div class="inline-edit-col">
                            <div class="inline-edit-group wp-clearfix">
                                <label class="alignleft">
                                    <span class="title">Company URL</span>
                                    <input type="text" name="url" value="">
                                </label>
                                <label class="alignleft">
                                    <input type="checkbox" name="partner">
                                    <span class="checkbox-title">Partner Company</span>
                                </label>
                            </div>
                        </div>
                    </fieldset>
                <?php
                break;
            }
        endswitch;
    }, 10, 2
);

Save Post action

add_action(
    'save_post',
    function ( $post_id ){
        if ( empty( $_POST ) ) return $post_id;
        if ( !current_user_can( 'edit_post', $post_id ) ) return $post_id;
        if ( !wp_verify_nonce( $_POST['my_nonce'], 'company_cpt_quick_edit' ) ) return $post_id;
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return $post_id;
        if ( isset( $post->post_type ) && $post->post_type == 'revision' ) return $post_id;

        if ( isset( $_POST['url'] ) ) {
           update_post_meta( $post_id, 'url', $_POST['url'] );
        }
        if ( isset( $_POST['partner'] ) ) {
           update_post_meta( $post_id, 'partner', '1' );
        } else {
           update_post_meta( $post_id, 'partner', '0' );
        }
    }
);

JavaScript for quick edit

jQuery(function($){

    var wp_inline_edit_function = inlineEditPost.edit;

    inlineEditPost.edit = function( post_id ) {

        wp_inline_edit_function.apply( this, arguments );
        
        var id = 0;
        if ( typeof( post_id ) == 'object' ) {
            id = parseInt( this.getId( post_id ) );
        }
 
        if ( id > 0 ) {
            var specific_post_edit_row = $( '#edit-' + id ),
                specific_post_row = $( '#post-' + id ),
                url = $( '.column-partner', specific_post_row ).find('a:first').attr('href'),
                partner = false;
 
            if( $( '.column-partner', specific_post_row ).find('span.partner').length !== 0 ) partner = true;
 
            $( ':input[name="url"]', specific_post_edit_row ).val( url );
            $( ':input[name="partner"]', specific_post_edit_row ).prop('checked', partner );
        }
    }
});

Bulk Edit radio field

add_action(
    'bulk_edit_custom_box',
    function ( $column_name, $post_type ) {           
        if ( $post_type != 'company_single' ) return;
        switch( $column_name ) :
            case 'partner': {
                ?> 
                    <fieldset class="inline-edit-col-right">
                        <div class="inline-edit-col">
                            <div class="inline-edit-group wp-clearfix">
                                <label class="alignleft">
                                    <input type="radio" id="partner" name="partner" class="partner" value="0">
                                    <label for="partner">Partner</label>
                                    <input type="radio" id="non_partner" name="partner" class="partner" value="1">
                                    <label for="non_partner" >Non-partner</label>
                                </label>
                            </div>
                        </div>
                    </fieldset>
                <?php
                break;
            }
        endswitch;
    }, 10, 2
);

Bulk Edit save function

function company_bulk_edit_save_hook() {
    if( empty( $_POST[ 'post_ids' ] ) ) {
        die();
    }
    foreach( $_POST[ 'post_ids' ] as $id ) {

        if ( isset( $_POST['partner'] ) ) {
            update_post_meta( $id, 'partner', $_POST['partner'] );
        } else {
            update_post_meta( $id, 'partner', '0' );
        }

    }
    wp_die();
}
add_action( 'wp_ajax_company_bulk_edit_save', 'company_bulk_edit_save_hook' );

AJAX for Bulk Edit

jQuery(function($){
    $( 'body' ).on( 'click', 'input[name="bulk_edit"]', function() {

        $( this ).after('<span class="spinner is-active"></span>');
 
        var bulk_edit_row = $( 'tr#bulk-edit' ),
            post_ids = new Array(),
            partner = bulk_edit_row.find( '.partner:checked' ).val();
 
        bulk_edit_row.find( '#bulk-titles' ).children().each( function() {
            post_ids.push( $( this ).attr( 'id' ).replace( /^(ttle)/i, '' ) );
        });
 
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            async: false,
            cache: false,
            data: {
                action: 'company_bulk_edit_save',
                post_ids: post_ids,
                partner: partner
            }
        });
    });
});
Share Improve this question edited Nov 7, 2020 at 14:48 GeorgeP asked Nov 7, 2020 at 11:06 GeorgePGeorgeP 3571 silver badge10 bronze badges 6
  • Is this not default behaviour? The point of quick edit is to make a change to multiple posts quickly, not to avoid a refresh. E.g. set the author of 10 posts – Tom J Nowell Commented Nov 7, 2020 at 11:22
  • You are confusing Quick Edit with Bulk edit. – GeorgeP Commented Nov 7, 2020 at 11:24
  • The only difference between quick edit and bulk edit is the left most pane – Tom J Nowell Commented Nov 7, 2020 at 11:25
  • Infact they use the same code github/WordPress/WordPress/blob/master/wp-admin/js/… – Tom J Nowell Commented Nov 7, 2020 at 11:26
  • Saving the 'Bulk Edit' data is a bit different, see this: wordpress.stackexchange/a/238307/160985. However, the point here is not Bulk Edit or how similar it is with Quick Edit. The problem here is after a Quick Edit, columns should update on the spot and they are not even though post_meta data is saved. See the gif in the previous link for the default behavior I am looking for. – GeorgeP Commented Nov 7, 2020 at 11:33
 |  Show 1 more comment

1 Answer 1

Reset to default 0

When the Update button is clicked in Quick Edit the post_meta are properly updated, values saved in database, but column's content is not updated by Ajax.

Indeed, the Quick Edit feature makes no attempt to update or reload individual admin columns. It instead replaces the row with whatever the AJAX endpoint returned.

Here is the implementation:

https://github/WordPress/WordPress/blob/master/wp-admin/js/inline-edit-post.js#L386-L451

    /**
     * Saves the changes made in the quick edit window to the post.
     * Ajax saving is only for Quick Edit and not for bulk edit.
     *
     * @since 2.7.0
     *
     * @param {number} id The ID for the post that has been changed.
     * @return {boolean} False, so the form does not submit when pressing
     *                   Enter on a focused field.
     */
    save : function(id) {
        var params, fields, page = $('.post_status_page').val() || '';

        if ( typeof(id) === 'object' ) {
            id = this.getId(id);
        }

        $( 'table.widefat .spinner' ).addClass( 'is-active' );

        params = {
            action: 'inline-save',
            post_type: typenow,
            post_ID: id,
            edit_date: 'true',
            post_status: page
        };

        fields = $('#edit-'+id).find(':input').serialize();
        params = fields + '&' + $.param(params);

        // Make Ajax request.
        $.post( ajaxurl, params,
            function(r) {
                var $errorNotice = $( '#edit-' + id + ' .inline-edit-save .notice-error' ),
                    $error = $errorNotice.find( '.error' );

                $( 'table.widefat .spinner' ).removeClass( 'is-active' );

                if (r) {
                    if ( -1 !== r.indexOf( '<tr' ) ) {
                        $(inlineEditPost.what+id).siblings('tr.hidden').addBack().remove();
                        $('#edit-'+id).before(r).remove();
                        $( inlineEditPost.what + id ).hide().fadeIn( 400, function() {
                            // Move focus back to the Quick Edit button. $( this ) is the row being animated.
                            $( this ).find( '.editinline' )
                                .attr( 'aria-expanded', 'false' )
                                .focus();
                            wp.a11y.speak( wp.i18n.__( 'Changes saved.' ) );
                        });
                    } else {
                        r = r.replace( /<.[^<>]*?>/g, '' );
                        $errorNotice.removeClass( 'hidden' );
                        $error.html( r );
                        wp.a11y.speak( $error.text() );
                    }
                } else {
                    $errorNotice.removeClass( 'hidden' );
                    $error.text( wp.i18n.__( 'Error while saving the changes.' ) );
                    wp.a11y.speak( wp.i18n.__( 'Error while saving the changes.' ) );
                }
            },
        'html');

        // Prevent submitting the form when pressing Enter on a focused field.
        return false;
    },

The function that handles this is function wp_ajax_inline_save() {

https://github/WordPress/WordPress/blob/0e3147c40e91f6eb1f57585724be173e3c04a719/wp-admin/includes/ajax-actions.php#L1981

Which is the same that powers post updates in the classic editor.

So I tested a custom column with this code:

<?php
/**
 * Plugin Name: Custom columns
 */

add_filter(
    'manage_post_posts_columns',
    function( $columns ) {
        return array_merge( $columns, [ 'tomcol' => 'Toms Awesome Column' ] );
    }
);

add_action(
    'manage_post_posts_custom_column',
    function ( $column_key, $post_id ) {
        if ( $column_key === 'tomcol' ) {
            $meta = get_post_meta( $post_id, 'tomcol', true );
            echo esc_html( $meta );
        }
    },
    10,
    2
);

add_action(
    'quick_edit_custom_box',
    function ( $column_name, $post_type ) {
        if ( 'tomcol' !== $column_name ) {
            return;
        }
        $meta = get_post_meta( $post_id, 'tomcol', true );
        ?>
        <fieldset class="inline-edit-col-right">
            <div class="inline-edit-col">
                <div class="inline-edit-group wp-clearfix">
                    <label class="alignleft">
                        <span class="title">Toms Column</span>
                        <input type="text" name="tomcol" value="<?php echo esc_html( $meta ); ?>">
                    </label>
                </div>
            </div>
        </fieldset>
        <?php
    },
    10,
    2
);

add_action(
    'admin_footer',
    function () {
        ?>
        <script>
        jQuery( function( $ ) {
            var wp_inline_edit_function = inlineEditPost.edit;
            inlineEditPost.edit = function( post_id ) {
                wp_inline_edit_function.apply( this, arguments );
                var id = 0;
                if ( typeof( post_id ) == 'object' ) {
                    id = parseInt( this.getId( post_id ) );
                }

                if ( id > 0 ) {
                    var specific_post_edit_row = $( '#edit-' + id );
                    var specific_post_row = $( '#post-' + id );
                    var url = $( '.column-tomcol', specific_post_row ).text();
                    $( ':input[name="tomcol"]', specific_post_edit_row ).val( url );
                }
            }
        });
        </script>
        <?php
    }
);

add_action(
    'save_post',
    function ( $post_id ){
        global $post;
        if ( empty( $_POST ) ) {
            return $post_id;
        }
        if ( ! current_user_can( 'edit_post', $post_id ) ) {
            return $post_id;
        }
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return $post_id;
        }
        if ( isset( $post->post_type ) && $post->post_type == 'revision' ) {
            return $post_id;
        }

        if ( isset( $_POST['tomcol'] ) ) {
            update_post_meta( $post_id, 'tomcol', sanitize_text_field( wp_unslash( $_POST['tomcol'] ) ) );
        }
    }
);

And it worked. The column updated on AJAX refresh. So I can only conclude that your column is indeed being updated, but with stale values, or a silly mistake/typo has been made somewhere

The important distinction though, is that the column was not updated, but rather the row was replaced completely

发布评论

评论列表(0)

  1. 暂无评论