I don't understand how this parameter works..?

Ok, I’ve got this simple code for a simple plugin which prepends post titles with the word TESTING.. I’m really unclear how the parameter works here. I understand how parameters work in PHP, but nothing has been passed inside this parameter for WordPress to know the variable is the title.. if that makes sense?? Don’t get how it’s working.

I’m still fairly crap at WordPress development – I always seem to start, get stuck and don’t get very far.

add_filter('the_title', 'cm_title');

/**
* Modify the title prepending the article title with the word 'TESTING'
*/

function cm_title($text) {

return 'TESTING  ' . $text;

}

Solutions Collecting From Web of "I don't understand how this parameter works..?"

Let’s see if we can break it down so it’s easy to understand.

You have a PHP function named ‘cm_title’:

function cm_title($text) {
   return 'TESTING  ' . $text;
}

It only does 1 thing. It takes what it is given, ‘$text’, and returns that $text with the words ‘Testing ‘ prepended to it.

How does WordPress know what ‘$text’ is?

It knows/assigns data to the $text parameter because of this WP filter:

add_filter('the_title', 'cm_title');

This filter is checked by WP when it is building ‘the_title’. So just before WP spits out ‘the_title’ it checks to see if there is a filter to use. In this case we are telling WP to apply this filter (the function ‘cm_title’) before spitting out the title.

All that to say WP sends what it has so far for ‘the_title’ (ie. ‘This is a Post About me’) and runs it through this filter before spitting it out.

So in this case, ‘This is a Post About me’ is the data in the $text parameter in the cm_title function.

Your end result becomes ‘TESTING This is a Post About me’.

Does that help clear it up?

WordPress uses hooks to help developers do what they need to do in a relatively easy way. Some of these hooks are apply_filter() and do_action() which is defined by WordPress. Let’s see exactly what happens when we call the_title() all the way up until it hits the hook you defined.

<?php the_title(); ?>

Developer Resources – the_title()

function the_title($before = '', $after = '', $echo = true) {
    $title = get_the_title();

    if ( strlen($title) == 0 )
        return;

    $title = $before . $title . $after;

    if ( $echo )
        echo $title;
    else
        return $title;
}

Right at the top it calls get_the_title() which is where we’ll find our filter. Let’s take a look at that:

Developer Resources – get_the_title()

function get_the_title( $post = 0 ) {
    $post = get_post( $post );

    $title = isset( $post->post_title ) ? $post->post_title : '';
    $id = isset( $post->ID ) ? $post->ID : 0;

    if ( ! is_admin() ) {
        if ( ! empty( $post->post_password ) ) {

            /**
             * Filter the text prepended to the post title for protected posts.
             *
             * The filter is only applied on the front end.
             *
             * @since 2.8.0
             *
             * @param string  $prepend Text displayed before the post title.
             *                         Default 'Protected: %s'.
             * @param WP_Post $post    Current post object.
             */
            $protected_title_format = apply_filters( 'protected_title_format', __( 'Protected: %s' ), $post );
            $title = sprintf( $protected_title_format, $title );
        } else if ( isset( $post->post_status ) && 'private' == $post->post_status ) {

            /**
             * Filter the text prepended to the post title of private posts.
             *
             * The filter is only applied on the front end.
             *
             * @since 2.8.0
             *
             * @param string  $prepend Text displayed before the post title.
             *                         Default 'Private: %s'.
             * @param WP_Post $post    Current post object.
             */
            $private_title_format = apply_filters( 'private_title_format', __( 'Private: %s' ), $post );
            $title = sprintf( $private_title_format, $title );
        }
    }

    /**
     * Filter the post title.
     *
     * @since 0.71
     *
     * @param string $title The post title.
     * @param int    $id    The post ID.
     */
    return apply_filters( 'the_title', $title, $id );
}

You’ll notice directly at the bottom of the function it calls apply_filters() and passes in a function_name as string, $title as string and $id as int then returns whatever apply_fitlers() returns, which is your hook. Let’s take a look at apply_filters():

Developer Resources – apply_filters()

function apply_filters( $tag, $value ) {
    global $wp_filter, $merged_filters, $wp_current_filter;

    $args = array();

    // Do 'all' actions first.
    if ( isset($wp_filter['all']) ) {
        $wp_current_filter[] = $tag;
        $args = func_get_args();
        _wp_call_all_hook($args);
    }

    if ( !isset($wp_filter[$tag]) ) {
        if ( isset($wp_filter['all']) )
            array_pop($wp_current_filter);
        return $value;
    }

    if ( !isset($wp_filter['all']) )
        $wp_current_filter[] = $tag;

    // Sort.
    if ( !isset( $merged_filters[ $tag ] ) ) {
        ksort($wp_filter[$tag]);
        $merged_filters[ $tag ] = true;
    }

    reset( $wp_filter[ $tag ] );

    if ( empty($args) )
        $args = func_get_args();

    do {
        foreach( (array) current($wp_filter[$tag]) as $the_ )
            if ( !is_null($the_['function']) ){
                $args[1] = $value;
                $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
            }

    } while ( next($wp_filter[$tag]) !== false );

    array_pop( $wp_current_filter );

    return $value;
}

It looks complex but before we jump into that let’s get to the most important piece of this function, $wp_filter. Now this little bugger contains ALL the filters added by both you AND WordPress. You can print it out right underneath your wp_head() to see the full list. It looks something like this ( tons more, I just picked the_title since it’s on topic! )

[the_title] => Array
    (
        [10] => Array
            (
                [wptexturize] => Array
                    (
                        [function] => wptexturize
                        [accepted_args] => 1
                    )

                [convert_chars] => Array
                    (
                        [function] => convert_chars
                        [accepted_args] => 1
                    )

                [trim] => Array
                    (
                        [function] => trim
                        [accepted_args] => 1
                    )

            )

        [11] => Array
            (
                [capital_P_dangit] => Array
                    (
                        [function] => capital_P_dangit
                        [accepted_args] => 1
                    )

            )

    )

So it’s a multi-dimensional array of filters, indexed by tag, then by priority and finally by function name. Pretty neat I think! The filter you added, since you didn’t pass a priority, is defaulted to index 10 and would be added right underneath trim and then further indexed by function name cm_title.

Let’s go back a little bit. If we look at the end of get_the_title() function above we see it passing three variables into the apply_filters function but as we can clearly see it only accepts two parameters! I had to look into this a little bit and it looks like this little function, func_get_args() we see littered inside apply_filters() actually will grab anything and everything passed to it. Here’s an example, the Codepen is also nice. Now even though anything can be passed, if we look back up at our mutlidimensional array there’s an accepted_args parameters so technically, you kinda can’t even though it allows you to.

PHEW

Finally, it loops through each one of these filters using the $wp_filters array:

do {
    foreach( (array) current($wp_filter[$tag]) as $the_ )
        if ( !is_null($the_['function']) ){
            $args[1] = $value;
            $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
        }

} while ( next($wp_filter[$tag]) !== false );

So, let’s bring it all together!

  • the_title() calls get_the_title()
  • get_the_title() returns apply_filters(), passing in: ‘the_title’ (function name), $title (string post title), $id (int post id).
  • apply_filters() looks through a global array that holds all filters added then runs them passing in the information that was passed to it ( $title, and $id ).

The function you call add_filter actually adds your function name, priority, and args to the global $wp_filters array. You can see that below:

Developer Resources – add_filter()

function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
    global $wp_filter, $merged_filters;

    $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
    $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
    unset( $merged_filters[ $tag ] );
    return true;
}

Really, this is called before the_title() ever gets called. Your functions are loaded with wp_head() and thus any filters you add through plugins or functions.php will also be added to this global array.


That was lengthy but hopefully it makes a little more sense now, if you have any questions ask in the comments!