Is it possible to replace a function within a PHP class of a WordPress plugin?

I read that “unless the original function is meant to be overridden, no. This is basic PHP.”

But I am trying to edit the WooCommerce plugin without editing the plugin files, so that the plugin can be updated without losing changes.

Read More

I have set up a child theme and done the following in the functions.php but it does not work…

functions.php – child theme

<?php
require_once(WP_PLUGIN_DIR . '/woocommerce/includes/class-wc-form-handler.php');

class child_WC_Form_Handler extends WC_Form_Handler {

    public function process_login() {

        parent::process_login();
       .
       .
       .
       if ( is_email( $_POST['username'] ) && apply_filters( 'woocommerce_get_username_from_email', true ) ) {
           $user = get_user_by( 'email', $_POST['username'] );

           if ( isset( $user->user_login ) ) {
               $creds['user_login']     = $user->user_login;
           } else {
               throw new Exception( '<strong>' . __( 'Error', 'woocommerce' ) . ':</strong> ' . __( 'MESSAGE TO BE REPLACED', 'woocommerce' ) );
           }

       } else {
           $creds['user_login']     = $_POST['username'];
       }
       .
       .
       .
    }

}
?>

class-wc-form-handler.php – where the original function lies

<?php
class WC_Form_Handler {
.
.
.
    public function process_login() {
       .
       .
       .
       if ( is_email( $_POST['username'] ) && apply_filters( 'woocommerce_get_username_from_email', true ) ) {
           $user = get_user_by( 'email', $_POST['username'] );

           if ( isset( $user->user_login ) ) {
               $creds['user_login']     = $user->user_login;
           } else {
               throw new Exception( '<strong>' . __( 'Error', 'woocommerce' ) . ':</strong> ' . __( 'A user could not be found with this email address.', 'woocommerce' ) );
           }

       } else {
           $creds['user_login']     = $_POST['username'];
       }
       .
       .
       .
    }
.
.
.
}
?>

Is there any way around this? I want to change the exception message of a login error. I have highlighted the message I want to change with ‘MESSAGE TO BE REPLACED’.

Related posts

Leave a Reply

2 comments

  1. Inside the process_login function, you should be able to see a try {} catch {} block which then calls wc_add_notice like this:

    ...
    wc_add_notice( apply_filters('login_errors', $e->getMessage() ), 'error' );
    ...
    

    So, we should be able to add a filter and intercept just that message:

    function replace_email_error($message) {
    
        $emailError = '<strong>' . __( 'Error', 'woocommerce' ) . ':</strong> ' . __( 'A user could not be found with this email address.', 'woocommerce');
    
        if ($message == $emailError) {
            $message = 'MESSAGE TO BE REPLACED';
        }
    
        return $message;
    
    }
    
    add_filter('login_errors', 'replace_email_error');
    

    I have not tested this – please try it out, if you have any problems with it I am happy to debug.

    Alternatively, you should be able to see that the error message is passed to WordPress’s localization functions – so you can also add a filter to the gettext function and then check the domain and the text and return a different value if they match.

  2. Even though you have your answer this could come in handy down the track.

    According to the following Github thread it hasn’t been implemented in WooCommerce directly: https://github.com/woothemes/woocommerce/issues/3687

    You can however still extend their core classes but most likely will have to do cleanup behind them which can be annoying. Here is an example of the WC_Form_Handler that I had extended for my own needs:

    class WC_BI_Form_Handler extends WC_Form_Handler {
        public function __construct() {
            parent::__construct();
    
            remove_filters_for_anonymous_class( 'init', 'WC_Form_Handler', 'process_login', 10 );
            add_action( 'init', array( $this, 'process_login' ) );
        }
    
        public function process_login() {
            if ( ! empty( $_POST['login'] ) && ! empty( $_POST['_wpnonce'] ) ) {
                # code
            }
        }
    }
    
    new WC_BI_Form_Handler;
    

    I’ve used the following plugin which gave me access to the remove_filters_for_anonymous_class function. This allowed me to unhook class specific actions which wouldn’t be otherwise possible: https://github.com/herewithme/wp-filters-extras/blob/master/wp-filters-extras.php