2

I am trying to override a WooCommerce function load_country_states(). I am creating a custom WordPress plugin to do it. I read in some answers that one can't simply override a function in PHP. Whats the best way to rewrite a function defined in WordPress theme/plugin in a plugin? I have read this.

The function to modify:

/**
 * Load the states.
 */
public function load_country_states() {
    global $states;

    // States set to array() are blank i.e. the country has no use for the state field.
    $states = array(
        'AF' => array(),
        'AT' => array(),
        'AX' => array(),
        'BE' => array(),
        'BI' => array(),
        'CZ' => array(),
        'DE' => array(),
        'DK' => array(),
        'EE' => array(),
        'FI' => array(),
        'FR' => array(),
        'IS' => array(),
        'IL' => array(),
        'KR' => array(),
        'NL' => array(),
        'NO' => array(),
        'PL' => array(),
        'PT' => array(),
        'SG' => array(),
        'SK' => array(),
        'SI' => array(),
        'LK' => array(),
        'SE' => array(),
        'VN' => array(),
    );

    // Load only the state files the shop owner wants/needs.
    $allowed = array_merge( $this->get_allowed_countries(), $this->get_shipping_countries() );

    if ( ! empty( $allowed ) ) {
        foreach ( $allowed as $code => $country ) {
            if ( ! isset( $states[ $code ] ) && file_exists( WC()->plugin_path() . '/i18n/states/' . $code . '.php' ) ) {
                include( WC()->plugin_path() . '/i18n/states/' . $code . '.php' );
            }
        }
    }

    $this->states = apply_filters( 'woocommerce_states', $states );
}

After modification it should work like:

/**
 * Load the states.
 */
public function load_country_states() {
    global $states;
    // Load only the state files the shop owner wants/needs.
    $allowed = array_merge( $this->get_allowed_countries(), $this->get_shipping_countries() );

    if ( ! empty( $allowed ) ) {
        foreach ( $allowed as $code => $country ) {
            if ( ! isset( $states[ $code ] ) && file_exists( WC()->plugin_path() . '/i18n/states/' . $code . '.php' ) ) {
                include( WC()->plugin_path() . '/i18n/states/' . $code . '.php' );
            }
        }
    }

    $this->states = apply_filters( 'woocommerce_states', $states );
}

2 Answers2

1

Actually you can't simply override a function. It's only possible if it's surrounded by a if ( ! function_exists() ) conditional. In your case it seems to be a class method and to override it (in plain PHP) you should extend the class and override the method. In your WordPress scenario it's simpler, because you can use a simple filter. Your code should be like:

public function so48005823_load_country_states( $states ) {
    // make your magic here and 
    // don't forget to return the $states var

    return $states;
}
add_filter( 'woocommerce_states', 'so48005823_load_country_states' );

Make sure to not simple copy/paste the code, because the $this variable is only available inside the class scope. You can put this function into a simple plugin and it'll start working.

Hope it helps!

Felipe Elia
  • 1,398
  • 2
  • 12
  • 24
0

I tried to read up more about this and came up with this solution that worked. We can use WordPress filter to add hack into specific events. I modified the code and it now works.

    /**
     * Load the states.
     */
function load_country_states_modified() {
        global $states;
        // Load only the state files the shop owner wants/needs.
        $foobar = new WC_Countries;  // correct
        $allowed = array_merge( $foobar->get_allowed_countries(), $foobar->get_shipping_countries() );
        if ( ! empty( $allowed ) ) {
            foreach ( $allowed as $code => $country ) {
                if ( ! isset( $states[ $code ] ) && file_exists( WC()->plugin_path() . '/i18n/states/' . $code . '.php' ) ) {
                    include( WC()->plugin_path() . '/i18n/states/' . $code . '.php' );
                }
            }
        }

        //$this->states = apply_filters( 'woocommerce_states', $states );
    }
    add_filter( 'woocommerce_states', 'load_country_states_modified' );
  • Please, just note that WordPress filters expect something as return (for hooks without return we use actions instead). I'm happy to see that your code do work, but in general cases the `states` property of the original class would probably not receive the right value ;) If you face some problem as a consequence of that, you can just add a parameter to your function and return it without changing it's value. – Felipe Elia Dec 30 '17 at 13:59