Search code examples
phpjquerywordpresswoocommercemetadata

Add custom fields to admin products Quick Edit in WooCommerce 3.2+


I'm following this tutorial by Misha Rudrastyh to add "Custom Fields in WordPress Quick Edit" feature. I have made it though most of the tutorial successfully (step 1, 2 and 3), but I am having trouble on the final step 4, which involves adding a script to populate the fields.

add_action( 'admin_footer', 'min_max_step_desc_quick_edit_populate');
function min_max_step_desc_quick_edit_populate(){
    ?>
    <script>
    jQuery( function($){
        console.log('min max step code is enabled');

        const wp_inline_edit_function = inlineEditPost.edit;

        // we overwrite the it with our own
        inlineEditPost.edit = function( post_id ) {

            // let's merge arguments of the original function
            wp_inline_edit_function.apply( this, arguments );

            // get the post ID from the argument
            if ( typeof( post_id ) == 'object' ) { // if it is object, get the ID number
                post_id = parseInt( this.getId( post_id ) );
            }

            // add rows to variables
            const edit_row = $( '#edit-' + post_id )
            const post_row = $( '#post-' + post_id )

            const minQty = $( '.column-min', post_row ).text().substring() //  remove $ sign
            const maxQty = $( '.column-max', post_row ).text().substring() //  remove $ sign
            const stepQty = $( '.column-step', post_row ).text().substring() //  remove $ sign
            const productDesc = $( '.column-desc', post_row ).text().substring() //  remove $ sign

            // populate the inputs with column data
            $( ':input[name="min"]', edit_row ).val( minQty );
            $( ':input[name="max"]', edit_row ).val( maxQty );      
            $( ':input[name="step"]', edit_row ).val( stepQty );        
            $( ':input[name="desc"]', edit_row ).val( productDesc );        
        }
    });
    </script>
    <?php
}

I keep getting the following error on the final lines

Syntax error, unexpected 'min' (T_STRING), expecting ';' or ','.

What am I doing wrong?


Edit (all other working related functions):

// add new columns
add_filter( 'manage_edit-product_columns', 'min_max_step_desc_columns' );
// the above hook will add columns only for default 'post' post type, for CPT:
// manage_{POST TYPE NAME}_posts_columns
function min_max_step_desc_columns( $column_array ) {
    $column_array[ 'min' ] = 'Min';
    $column_array[ 'max' ] = 'Max';
    $column_array[ 'step' ] = 'Step';
    $column_array[ 'desc' ] = 'Description';
    // the above code will add columns at the end of the array
    // if you want columns to be added in another order, use array_slice()
    return $column_array;
}

// Populate our new columns with data
add_action( 'manage_product_posts_custom_column', 'populate_custom_columns', 10, 2 );
function populate_custom_columns( $column_name, $post_id ) {
    // if you have to populate more that one columns, use switch()
    switch( $column_name ) {
        case 'min': {
            $min = get_post_meta( $post_id, '_alg_wc_pq_min', true );
            echo $min;
            break;
        }
        case 'max': {
            $max = get_post_meta( $post_id, '_alg_wc_pq_max', true );
            echo $max;
            break;
        }
        case 'step': {
            $step = get_post_meta( $post_id, '_alg_wc_pq_step', true );
            echo $step;
            break;
        }
        case 'desc': {
            echo get_post_field( 'post_content', $post_id );
            break;
        }
    }
}

// quick_edit_custom_box allows to add HTML in Quick Edit
add_action( 'quick_edit_custom_box',  'mix_max_step_desc_quick_edit_fields', 10, 2 );

function mix_max_step_desc_quick_edit_fields( $column_name, $post_type ) {

    switch( $column_name ) {
        case 'min': {
            ?>
            <fieldset class="inline-edit-col-left">
            <div class="inline-edit-col">
                <label>
                    <span class="title">Min</span>
                    <input type="text" name="min">
                </label>
            </div>
            <?php
            break;
        }
        case 'max': {
            ?>
            <div class="inline-edit-col">
                <label>
                    <span class="title">Max</span>
                    <input type="text" name="max">
                </label>
            </div>
            <?php
            break;
        }
        case 'step': {
            ?>
            <div class="inline-edit-col">
                <label>
                    <span class="title">Step</span>
                    <input type="text" name="step">
                </label>
            </div>
            <?php
            break;
        }
        case 'desc': {
            ?>
            <div class="inline-edit-col">
                <label>
                    <span class="title">Description</span>
                    <input type="text" name="desc">
                </label>
            </div>
            </fieldset>
            <?php
            break;
        }
    }
}

// save fields after quick edit
add_action( 'save_post', 'min_max_step_desc_quick_edit_save' );
function min_max_step_desc_quick_edit_save( $post_id ){
    // check inlint edit nonce
    if ( ! wp_verify_nonce( $_POST[ '_inline_edit' ], 'inlineeditnonce' ) ) {
        return;
    }

    // update the price
    $min = ! empty( $_POST[ 'min' ] ) ? absint( $_POST[ 'min' ] ) : '';
    update_post_meta( $post_id, '_alg_wc_pq_min', $min );

    $max = ! empty( $_POST[ 'max' ] ) ? absint( $_POST[ 'max' ] ) : '';
    update_post_meta( $post_id, '_alg_wc_pq_max', $max );
    
    $step = ! empty( $_POST[ 'step' ] ) ? absint( $_POST[ 'step' ] ) : '';
    update_post_meta( $post_id, '_alg_wc_pq_step', $step );
    
    $desc = ! empty( $_POST[ 'desc' ] ) ? absint( $_POST[ 'desc' ] ) : '';
    update_post_meta( $post_id, 'post_content', $desc );
}

Related: Add custom fields to admin products Bulk Edit in WooCommerce 3.2+


Solution

  • Update:

    You don't really need to add those fields values as additional columns to be able to use them via jQuery to populate the form fields in product "Quick Edit" feature.

    Instead, we can add the field values as hidden data to populate the fields in Quick Edit. Also In WooCommerce there are dedicated hooks to display and save Quick edit custom fields.

    The code:

    // Min Max Step fields settings
    function get_alg_wc_pq_fields() {
        return array(
            '_alg_wc_pq_min'  => __('Min'), 
            '_alg_wc_pq_max'  => __('Max'), 
            '_alg_wc_pq_step' => __('Step')
        );
    }
    
    // Add hidden custom field data to admin product list
    add_action( 'manage_product_posts_custom_column', 'admin_product_list_hidden_custom_field_data', 100, 2 );
    function admin_product_list_hidden_custom_field_data( $column, $post_id ) {
        global $product;
    
        if( $column === 'name' ) {
            echo '<div class="hidden" id="cfields_inline_'.$post_id.'">';
    
            // Loop through custom fields settings array
            foreach ( get_alg_wc_pq_fields() as $key => $title ) {
                printf('<div class="%s">%s</div>', 
                $key, $product->get_meta($key));
            }
    
            // For the product description
            printf('<div class="description">%s</div></div>', $product->get_description());
        }
    }
    
    // Add custom fields HTML in product Quick Edit
    add_action( 'woocommerce_product_quick_edit_end',  'mix_max_step_desc_quick_edit_fields' );
    function mix_max_step_desc_quick_edit_fields() {
        echo '<br class="clear"><br><fieldset class="inline-edit-col-wide">
        <div class="inline-edit-col">';
    
        // Loop through custom fields settings array
        foreach ( get_alg_wc_pq_fields() as $key => $title ) {
           
            printf('<label><span class="title">%s %s</span>
            <span class="input-text-wrap">
                <input id="%s" type="text" name="%s" class="text" value="" />
            </span></label><br class="clear">', $title, __('Qty'), $key, $key );
        }
    
        // For the product description
        printf('<label><span class="title">%s</span>
        <span class="textarea-wrap">
            <textarea id="%s" name="%s" class="textarea" cols="22" rows="1"></textarea>
        </span></label>', __('Description'), 'description', 'description' );
    
        echo '</div></fieldset>';
    }
    
    // Save quick edit custom fields values
    add_action( 'woocommerce_product_quick_edit_save', 'min_max_step_desc_quick_edit_save' );
    function min_max_step_desc_quick_edit_save( $product ){
        $updated = false;
    
        // Loop through custom fields settings array
        foreach ( get_alg_wc_pq_fields() as $key => $title ) {
            if ( isset($_REQUEST[$key]) ) {
                $product->update_meta_data($key, (!empty($_REQUEST[$key]) ? intval($_REQUEST[$key]) : ''));
                $updated = true;
            }
        }
    
        // For the product description
        if ( isset($_REQUEST['description']) ) {
            $product->set_description(!empty($_REQUEST['description']) ? sanitize_textarea_field($_REQUEST['description']) : '');
            $updated = true;
        }
    
        if ( $updated ) {
            $product->save(); // save product meta data
        }
    }
    
    // Javascript: Populate quick edit additional fields
    add_action( 'admin_footer', 'min_max_step_desc_quick_edit_js');
    function min_max_step_desc_quick_edit_js(){
        global $pagenow, $typenow;
    
        if( 'edit.php' === $pagenow && 'product' === $typenow ) :
        ?>
        <script id="woocommerce-quickedit-custom">
        jQuery( function($){
            $('#the-list').on('click', '.editinline', function(){
                inlineEditPost.revert();
                var post_id = $(this).closest('tr').attr('id');
                post_id = post_id.replace('post-', '');
        <?php $i = 0; 
            // Loop through custom fields settings array
            foreach ( get_alg_wc_pq_fields() as $key => $title ) : $i++; ?>
                const value<?php echo $i; ?> = $('#cfields_inline_'+post_id+' .<?php echo $key; ?>').text();
                $('input[name="<?php echo $key; ?>"]', '.inline-edit-row').val(value<?php echo $i; ?>);
        <?php endforeach; ?>
                // For the product description
                const value4 = $('#cfields_inline_'+post_id+' .description').text();
                $('textarea[name="description"]', '.inline-edit-row').val(value4);
            });
        });
        </script>
        <?php
        endif;
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and works.


    To display the fields at the beginning in Quick edit, use:

    • woocommerce_product_quick_edit_start

    instead of:

    • woocommerce_product_quick_edit_end

    If you still want to display the data in additional columns, also add the following:

    // Add new columns to admin products list
    add_filter( 'manage_edit-product_columns', 'add_min_max_step_desc_columns' );
    function add_min_max_step_desc_columns( $columns ) {
        // Merge fields settings with product description 
        $fields_data = array_merge( get_alg_wc_pq_fields(), array('description' => __('Description')) );
    
        // Loop through custom fields settings array
        foreach ( $fields_data as $key => $title ) {
            $columns[$key] = $title;
        }
        return $columns;
    }
    
    // Display values in admin products list new columns
    add_action( 'manage_product_posts_custom_column', 'show_min_max_step_desc_column_values', 10, 2 );
    function show_min_max_step_desc_column_values( $column, $post_id ) {
        global $product;
    
        // Loop through custom fields settings array
        foreach ( get_alg_wc_pq_fields() as $key => $title ) {
            if( $column === $key ) {
                echo $product->get_meta($key);
            }
        }
        // For the product description
        if( $column === 'description' ) {
            echo $product->get_description();
        }
    }