Search code examples
phpwoocommercehook-woocommerce

How to add custom woocommerce admin field type


i has already add one custom field type to woocommerce admin fields, and has worked 100%.

but this code is in the woocommerce plugin (woocommerce/includes/admin/class-wc-admin-settings.php).

My problem now is how to exclude or hook or filter my custom woocommerce admin field type from woocoommerce plugin to my plugin. therefore, my custom field type still exists and worked when update woocommerce.

this is class-wc-admin-settings.php has customized

<?php
...
class WC_Admin_Settings {
...

public static function output_fields( $options ) {
...
switch ( $value['type'] ) {
    case 'productcategory' :

    $option_value = (array) self::get_option( $value['id'] );

    ?><tr valign="top">
        <th scope="row" class="titledesc">
            <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
            <?php echo $tooltip_html; ?>
        </th>
        <td class="forminp forminp-<?php echo sanitize_title( $value['type'] ) ?>">
            <fieldset>

                <ul class="" style="margin:0; padding:0;">
                <?php
                    $args = array(
                        'orderby' => 'name',
                        'hide_empty'=> 0,
                        'taxonomy' => 'product_cat' 
                    );

                    $all_categories = get_categories( $args );
                    $index = 0;
                    $count = count($all_categories);
                    $numItemsPerRow = ceil($count / 2);
                    $numItemsOffsetFix = $count % 2 == 1;

                    echo '<div class="columns" style="width:auto; display:inline-block; height:auto; float:left; padding:0; margin:0 25px 0 0;">';

                    foreach ($all_categories as $key => $val) {
                        if ($index > 0 and $index % $numItemsPerRow == 0) {
                            echo '</div><div class="columns">';
                            if ($numItemsOffsetFix) {
                                $numItemsPerRow--;
                                $numItemsOffsetFix = false;
                            }
                        }
                    //foreach ( $value['options'] as $key => $val ) {
                        ?>
                        <li style="">
                            <label><input type="checkbox" 
                                name="<?php echo esc_attr( $value['id'] ); ?>[]"
                                id="<?php echo esc_attr( $val->term_id )?>"
                                value="<?php echo esc_attr( $val->term_id )?>" 
                                <?php
                                    if ( in_array( $val->term_id,$option_value ) ) {
                                        echo ' checked="checked"';
                                    }
                                ?>
                                /> <?php echo $val->name; ?>
                            </label>
                        </li>
                        <?php
                        $index++;
                    }
                ?>
                </ul>
            </fieldset>
            <fieldset>
                <?php echo $description; ?>
            </fieldset>
        </td>
    </tr><?php
 break;
...
} //end switch

...
} //end output_fields function

public static function save_fields( $options ) {
...
    switch ( $option['type'] ) {
    ...
        case 'productcategory':
        $value = array_filter( array_map( 'wc_clean', (array) $raw_value ) );
        break;
    ...
    }
...
} //end save_fields function

...
} //end class
?>

thanks for advise.


Solution

  • There's a do_action as the default case in the switch statement. Meaning, that if nothing has matched yet in the core code it will see if anything is attached to the action hook. Similarly, you can sanitize via the woocommerce_admin_settings_sanitize_option_$option_name filter

    Therefore, here's my best guess:

    // handle output of new settings type
    add_action( 'woocommerce_admin_field_productcategory', 'output_productcategory_fields' );
    function output_productcategory_fields( $value ) {
    
        $option_value = (array) WC_Admin_Settings::get_option( $value['id'] );
    
        ?><tr valign="top">
            <th scope="row" class="titledesc">
                <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
                <?php echo $tooltip_html; ?>
            </th>
            <td class="forminp forminp-<?php echo sanitize_title( $value['type'] ) ?>">
                <fieldset>
    
                    <ul class="" style="margin:0; padding:0;">
                    <?php
                        $args = array(
                            'orderby' => 'name',
                            'hide_empty'=> 0,
                            'taxonomy' => 'product_cat' 
                        );
    
                        $all_categories = get_categories( $args );
                        $index = 0;
                        $count = count($all_categories);
                        $numItemsPerRow = ceil($count / 2);
                        $numItemsOffsetFix = $count % 2 == 1;
    
                        echo '<div class="columns" style="width:auto; display:inline-block; height:auto; float:left; padding:0; margin:0 25px 0 0;">';
    
                        foreach ($all_categories as $key => $val) {
                            if ($index > 0 and $index % $numItemsPerRow == 0) {
                                echo '</div><div class="columns">';
                                if ($numItemsOffsetFix) {
                                    $numItemsPerRow--;
                                    $numItemsOffsetFix = false;
                                }
                            }
                        //foreach ( $value['options'] as $key => $val ) {
                            ?>
                            <li style="">
                                <label><input type="checkbox" 
                                    name="<?php echo esc_attr( $value['id'] ); ?>[]"
                                    id="<?php echo esc_attr( $val->term_id )?>"
                                    value="<?php echo esc_attr( $val->term_id )?>" 
                                    <?php
                                        if ( in_array( $val->term_id,$option_value ) ) {
                                            echo ' checked="checked"';
                                        }
                                    ?>
                                    /> <?php echo $val->name; ?>
                                </label>
                            </li>
                            <?php
                            $index++;
                        }
                    ?>
                    </ul>
                </fieldset>
                <fieldset>
                    <?php echo $description; ?>
                </fieldset>
            </td>
        </tr><?php
    
    }
    
    // sanitize data for new settings type
    add_filter( 'woocommerce_admin_settings_sanitize_option_productcategory', 'sanitize_productcategory_option', 10, 3 );
    function sanitize_productcategory_option( $value, $option, $raw_value ){
        $value = array_filter( array_map( 'wc_clean', (array) $raw_value ) );
        return $value;
    }