Andula
Andula

Reputation: 47

Setting a default value for a Woocommerce product field to all products

I created a custom field for my products using this tutorial, but I need to set a default value for this field. I have already created hundreds of products and I need to have this field updated at those as well. I'm then using this value to order the products.

Here is the whole code:

// Display Fields
    add_action('woocommerce_product_options_general_product_data', 'woocommerce_product_custom_fields');
    // Save Fields
    add_action('woocommerce_process_product_meta', 'woocommerce_product_custom_fields_save');
    function woocommerce_product_custom_fields()
    {
        global $woocommerce, $post;
        echo '<div class="product_custom_field">';
        // Custom Product Text Field
        woocommerce_wp_text_input(
            array(
                'id' => 'priority',
                'placeholder' => 'Priority of the product - values a>b',
                'label' => __('Priority of the product', 'woocommerce'),
                'desc_tip' => 'true',
                //'default' => '0',
            )
        );
        echo '</div>';
    }

    function woocommerce_product_custom_fields_save($post_id)
    {
        // Custom Product Text Field
        $woocommerce_custom_product_text_field = $_POST['priority'];
        if (!empty($woocommerce_custom_product_text_field))
            update_post_meta($post_id, 'priority', esc_attr($woocommerce_custom_product_text_field));
    }

    function cw_add_postmeta_ordering_args( $args_sort_cw ) {
      $cw_orderby_value = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) :
            apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
      switch( $cw_orderby_value ) {
           case 'priority':
                $args_sort_cw['orderby'] = 'meta_value';
                $args_sort_cw['order'] = 'asc';
                $args_sort_cw['meta_key'] = 'priority';
                break;
      }
      return $args_sort_cw;
    }
    add_filter( 'woocommerce_get_catalog_ordering_args', 'cw_add_postmeta_ordering_args' );
    function cw_add_new_postmeta_orderby( $sortby ) {
       $sortby['priority'] = __( 'Recommended', 'woocommerce' );
       return $sortby;
    }
    add_filter( 'woocommerce_default_catalog_orderby_options', 'cw_add_new_postmeta_orderby' );
    add_filter( 'woocommerce_catalog_orderby', 'cw_add_new_postmeta_orderby' );

I could't find a working solution, so I'm kindly asking you for an advice. What I expect is that every existing product will have this value set and when creating a new one the default value will be displayed. Then it should be sorted according to this value. Thanks for your help!

Edit according to the first answer: The data does't update in the database. In the front-end I can only see the products I have manually altered and not those to which the 0 was added using this function. When I try to change the altered value back to 0, it is not updated. Actually I just need a function which would refresh all the products so that the value is stored to the database.

Upvotes: 0

Views: 3776

Answers (2)

Andula
Andula

Reputation: 47

This is the solution which worked for me.

// Display Fields
add_action('woocommerce_product_options_general_product_data', 'woocommerce_product_custom_fields');
// Save Fields
add_action('woocommerce_process_product_meta', 'woocommerce_product_custom_fields_save');
    function woocommerce_product_custom_fields()
    {
        global $woocommerce, $post, $product_object;
        $value = $product_object->get_meta( 'priority', true );

        if ( ! $value ) {
            $value = 0;
        }
        
        echo '<div class="product_custom_field">';
        // Custom Product Text Field
        woocommerce_wp_text_input(
            array(
                'id' => 'priority',
                'placeholder' => 'Priority - number 1>0',
                'label' => __('Priority', 'woocommerce'),
                'type' => 'number',
                'desc_tip' => 'true',
                'value' => $value
            )
        );
        echo '</div>';
    }

    function woocommerce_product_custom_fields_save($post_id)
    {
        // Custom Product Text Field
        if (array_key_exists('priority', $_POST)) {
            update_post_meta($post_id, 'priority', intval($_POST['priority']));
        }
    }

    function cw_add_postmeta_ordering_args( $args_sort_cw ) {
      $cw_orderby_value = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) :
            apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
      switch( $cw_orderby_value ) {
           case 'priority':
                $args_sort_cw['orderby'] = 'meta_value';
                $args_sort_cw['order'] = 'desc';
                $args_sort_cw['meta_key'] = 'priority';
                break;
      }
      return $args_sort_cw;
    }
    add_filter( 'woocommerce_get_catalog_ordering_args', 'cw_add_postmeta_ordering_args' );
    function cw_add_new_postmeta_orderby( $sortby ) {
       $sortby['priority'] = __( 'Recommended', 'woocommerce' );
       return $sortby;
    }
    add_filter( 'woocommerce_default_catalog_orderby_options', 'cw_add_new_postmeta_orderby' );
    add_filter( 'woocommerce_catalog_orderby', 'cw_add_new_postmeta_orderby' );

I adjusted the woocommerce_product_custom_fields_save() function with array_key_exists() and it works fine now. Thanks helgatheviking for help!

Upvotes: 0

helgatheviking
helgatheviking

Reputation: 26329

What I would do is use the value argument in the woocommerce_wp_text_input parameters. You can then pass it the current value OR a default if nothing exists yet.

Also added new save routine via woocommerce_admin_process_product_object

// Display Fields
add_action('woocommerce_product_options_general_product_data', 'so_63588126_product_custom_fields');
// Save Fields
add_action('woocommerce_admin_process_product_object', 'so_63588126_product_custom_fields_save');


function so_63588126_product_custom_fields()
{
    global $product_object;

    $value = $product_object->get_meta( 'weight', true );

    if ( ! $value ) {
        $value = 0;
    }

    echo '<div class="product_custom_field">';
    // Custom Product Text Field
    woocommerce_wp_text_input(
        array(
            'id' => 'weight',
            'placeholder' => 'Weight of the product - values a>b',
            'label' => __('Weight of the product', 'your-textdomain'),
            'desc_tip' => 'true',
            'value' => $value 
        )
    );
    echo '</div>';
}

function so_63588126_product_custom_fields_save( $product )
{
    // Custom Product Text Field
    $woocommerce_custom_product_text_field = $_POST['weight'];
    if ( ! empty( $_POST['weight'] ) ) {
        $product->update_meta_data( 'weight', sanitize_text_field( wp_unslash( $_POST['weight'] ) ) );
    } else {
        $product->update_meta_data( 'weight', 0 );
    }

}

Additional explanation:

I used $product_object->update_meta_data() as WooCommerce (since 3.0) prefers to use CRUD (create, read, update, delete) methods on objects. update_post_meta() does still work, but CRUD will be future-proof if/when Woo ever decides to use custom tables for products and product meta.

Read more about CRUD: https://docs.woocommerce.com/document/developing-using-woocommerce-crud-objects/

And regarding text domains... This is custom code so in order for it to be properly translated you would need to use your own unique text domain that is not 'woocommerce'.

Read more about text domains: https://developer.wordpress.org/themes/functionality/internationalization/#text-domain

Finally, sanitize_text_field() may not be the right choice for sanitizing, but I didn't know what kind of data you were storing there. intval() would be better for numbers... and so would setting the input to be a numerical input type by setting the type parameter to 'number' in the woocommerce_wp_text_input() args.

Upvotes: 3

Related Questions