Deprecating functions in a plugin class

I’m updating one of my plugins and I’m a little stuck with deprecating functions.

Originally, my plugin had a global variable and the plugin’s main class was instantiated and stored in the global variable. This way users could use the global to access functions in the plugin class.

Read More
$GLOBALS['my_custom_plugin'] = new my_custom_plugin();

Then, for example, in my FAQ I had code that showed how to remove one of my class’ functions from a specific hook and add to to a different hook:

function move_input(){ 
    global $my_custom_plugin;
    remove_action( 'before_main_content', array( $my_custom_plugin, 'display_input') );
    add_action( 'after_main_content', array( $my_custom_plugin, 'display_input' ) );
}
add_action( 'wp_head' , 'move_input' );

Now, in my update the display_input() function has been moved to another class and I want to let people know how to access it. I tried replacing the original function (in the main plugin class) with the following deprecation notice:

public function display_input() { 
    _deprecated_function( 'display_price', '2.0', 'my_custom_plugin()->display->display_input' );
    return $this->display->display_input();
}

However, the add_action and remove_action functions don’t seem to trigger the deprecation notice. Weirdly, completely removing the function doesn’t cause an error either even though array( $my_custom_plugin, 'display_input') doesn’t exist.

If someone tries to access the function directly:

$my_custom_plugin->display_input();

Then I do see the debug notices. Is this the expected outcome for _deprecated_function()? or am I missing something? Is it possible to show a debug notice when someone tries to remove or add an action using a deprecated function?

Update

I realized that I was simply not seeing the debug message for the add_action as I was adding it pretty low on the page. #facepalm! However, I am still not seeing any debug notice for the remove_action.

Related posts

1 comment

  1. Non existing Callbacks

    One of the nice things is, that neither do_action(), nor apply_filters() do trigger an error if a callback isn’t present. This means that its the safest way to insert plugin data into templates: If a plugin is turned off and do_action()/apply_filters() don’t find the callback in the global $wp_filters array, nothing happens.

    Error Output

    Now when you’re calling remove_filter() in the function/method that originally hooked the callback, the callback simply will be removed from the global array, which means that the callback will never be executed as it’s not registered anymore.

    The solution is simple: Remove the callback after it was triggered, by removing it from within the callback itself.

    Removing Callbacks

    We all know that WPs plugin “API” is a pain when it comes to removing. The problem mainly is the strange construct to add “unique” names to keys in the global $wp_filter; array. A very simple solution is to just use __METHOD__ and call filters that you want to remove in static context:

    class FOoooo
    {
        public function __construct()
        {
            add_filter( 'hook', array( __CLASS__, 'bar' ) );
        }
        public static function bar( $baz )
        {
            remove_filter( current_filter(), __METHOD__ );
    
            return $baz;
        }
    }
    

    While this isn’t nice, it’s … sort of a solution for some use cases. But don’t even think about removing a closure.

    Above just removes the callback, still executes it. Still you can go further and use remove_all_actions() (or remove_all_filters()).

    // Check if a callback is attached and tell about the deprecated stuff
    if ( has_action( 'before_main_content' ) )
        _deprecated_function( 'display_price', '2.0', 'my_custom_plugin()->display->display_input' );
    // Remove the callback
    remove_all_actions( 'before_main_content' );
    

    You maybe could even go further, extract the callback from the global filters array and re-attach it to the new hook/filter (if they’re compatible).

Comments are closed.