Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

add_action() and add_filter() are major functions. However in some scenarios add one more function and hook it somewhere approach gets bulky and inconvenient.

I had determined for myself several use cases that can streamline code with wrappers on top of add_* functions. Things that are better handled with single-liner than extra function each and every time.

  1. Add arbitrary filter return. There is already __return_* functions but they are very limited by definition. Why not just pass what you want returned in filter. Saves from myriad function return_stuff(){return 'stuff';}

  2. Replace X with Y in filter. Saves from myriad function replace_stuff(){return str_replace();}

  3. Add action with arbitrary arguments. Actions fire with arguments, passed in hook. But sometimes you don't care about that and just want ot run your function with your own arguments at specific hook. Saves from myriad function echo_stuff(){echo 'stuff'}; and more.

So...

  • Are there any other use cases you want and/or use in practice?

  • How would you implement such wrappers? There are a lot of possible approaches (closures, global variables to keep additional arguments, passing objects in callback, etc).

PS I have couple different implementations for (1) and (3) already and (as suggested) will post bits of my code some time later so I don't spoil the fun. :)

Example

Current way:

add_filter('wp_feed_cache_transient_lifetime', 'change_transient_lifetime', 10);

function change_transient_lifetime($lifetime) {

    return 3600;
}

Wrapper:

add_filter_return('wp_feed_cache_transient_lifetime', 10, 3600);
share|improve this question
1  
Since this will have multiple 'correct' answers, i think you should make it a community-wiki question? –  wyrfel Mar 5 '11 at 17:43
    
@wyrfel makes sense, but I have no capability to - by current mechanics only moderators can create wiki questions. One of them will most likely convert it to wiki down the road, Saturday is slow day. :) –  Rarst Mar 5 '11 at 17:51
add comment

5 Answers

For simple cases like quick one-liner returns one should remember that it's possible to hook an anonymous function directly in the add filter call, e.g:

add_filter('some_filter_hook', function($v){return str_replace('..', '.', $v);});

add_action('some_action_hook', function(){echo '....';});
share|improve this answer
    
Yep, but it doesn't really make code considerably more compact or easier to read - it merely packs about same amount in single line. Also it requires PHP 5.3+ (older anonymous functions with create_function() suck), which is sadly not always available. –  Rarst Mar 5 '11 at 17:48
    
It does yield a slight advantage, though, in that it doesn't pollute namespaces, particularly when your functions are not within a class for whatever reason. –  wyrfel Mar 5 '11 at 18:09
add comment

You might want to look into magic class methods and overloading in PHP which will have the function name called passed as a parameter. Then you can make decisions based on the function name like return__some_string I pin-up some exemplary and untested code:

class magiCall {
    public static function __callStatic ( string $name , array $arguments ) {
        // your code here, $name is the function name called.
    }
}

add_filter('hookname', 'magiCall::return__the_string');

I think that example pretty much shows the idea.

This one is PHP 5.3.x you can make this PHP 5.2 compatible by using the __call magic method and if you have a static public function to return the callback, then you might be able to write it comparable simplified. See the link to the php manual above.

share|improve this answer
    
Interesting, will look into it. –  Rarst Mar 6 '11 at 20:07
add comment
up vote 4 down vote accepted

I had released my code as Advanced Hooks API plugin in official repository.

View source in trac.

Some examples:

add_action_with_arguments('test', 'printf', 10, 'boo%s', '<br />');
do_action('test');
// boo

add_filter_return('test2',10,'boo');
echo apply_filters('test2','not boo') . '<br />';
// boo

add_filter_append('test3',10,' and boo');
echo apply_filters('test3','boo') . '<br />';
// boo and boo

add_filter_prepend('test4',10,'boo and ');
echo apply_filters('test4','boo') . '<br />';
// boo and boo

add_filter_replace('test5','boo','you thought...');
echo apply_filters('test5','boo');
// you thought...
share|improve this answer
    
I'd rename it to add_action_with_args() as users have to write this more than once :) –  kaiser Aug 14 '11 at 14:16
add comment

For simple return values you don’t need a lot of extra functions. There is the handy current_filter(). You can use that inside of your own functions.

Example

<?php # -*- coding: utf-8 -*-
/*
Plugin Name: Filter System From Mail
Description: Sets the WP from mail address to the first admin’s mail and the from name to blog name.
Version:     1.1
Author:      Thomas Scholz
Author URI:  http://toscho.de
License:     GPL
*/

if ( ! function_exists( 'filter_system_from_mail' ) )
{
    /**
     * First admin's e-mail address or blog name depending on current filter.
     *
     * @return string
     */
    function filter_system_from_mail()
    {
        return get_option( 'wp_mail_from' == current_filter()
            ? 'admin_email' : 'blogname' );
    }

    add_filter( 'wp_mail_from',      'filter_system_from_mail' );
    add_filter( 'wp_mail_from_name', 'filter_system_from_mail' );
}

Or … did I misread your question?

share|improve this answer
    
Yep, meant a bit different approach. Added example. –  Rarst Mar 5 '11 at 14:14
add comment

Ad anonymous or lambda functions) In every case I would avoid these, as you won't know the name or get a pretty cryptic output if you inspect a hook later. Debugging would be a pain.

Ad your A) The approach looks nice and offers a pretty simple API (+1).

Ad @hakre A) I use pretty much the same function[1] in my frameworks core - extended by "set_" & an exception - to set and get variables on the fly. This way I only have to extend this class with a child class that looks like a "variable only"-interface (those which shall be available). It's a nice and organized approach that only keeps stuff in the files that serves a single task. With something like this you can maybe avoid writing specific functions for each and every taks like "_replace", etc.

[1] Code - I run this all the time so you can call it "tested - and works"

/**
 * Magic getter/setter method
 * Guesses for a class variable & calls/fills it or throws an exception.
 * Note: Already defined methods override this method.
 * 
 * Original @author Miles Keaton <mileskeaton@gmail.com> 
 * on {@link http://www.php.net/manual/de/language.oop5.overloading.php#48440}
 * The function was extended to also allow 'set' tasks/calls and throws an exception.
 * 
 * @param (string) $name | Name of the property
 * @param unknown_type $args | arguments the function can take
 */
function __call( $name, $args )
{
    $_get = false;

    // See if we're calling a getter method & try to guess the variable requested
    if( substr( $val, 0, 4 ) == 'get_' )
    {
        $_get = true;
        $varname = substr( $val, 4 );
    }
    elseif( substr( $val, 0, 3 ) == 'get' )
    {
        $_get = true;
        $varname = substr( $val, 3 );
    }

    // See if we're calling a setter method & try to guess the variable requested
    if( substr( $val, 0, 4 ) == 'set_' )
    {
        $varname = substr( $val, 4 );
    }
    elseif( substr( $val, 0, 3 ) == 'set' )
    {
        $varname = substr( $val, 3 );
    }

    if ( ! isset( $varname ) )
        return new Exception( sprintf( __( "The method %1$s doesn't exist" ), "<em>{$val}</em>" ) );

    // Now see if that variable exists:
    foreach( $this as $class_var => $class_var_value )
    {
        if ( strtolower( $class_var ) == strtolower( $varname ) )
        {
            // GET
            if ( $_get )
            {
                return $this->{$class_var};
            }
            // SET
            else 
            {
                return $this->{$class_var} = $x[0];
            }
        }
    }

    return false;
}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.