Experimenting with magic return methods on WordPress filters

I was catching up on some of the specifics of the new default theme that shipped with WordPress 4.7, Twenty Seventeen.

When I saw this:

function mychild_sections() {
     return 6;
}
add_filter( 'twentyseventeen_front_page_sections', 'mychild_sections' );

We’ve all seen it a thousand times. There’s a filter that just needs a basic value, but since add_filter requires a callback function, we have to go out of our way to define one.

Annoying. Especially when you want to just return something basic, like an integer.

Have you ever done this before?

add_filter( 'twentyseventeen_front_page_sections', 6 );

No? Liar.

We’ve all done this by accident. Why? Because it’s intuitive! It’s a developer API that makes total sense when passing through simple values. Well, like it or not, WordPress wants a callback function – always.

Alright, so I thought I’d experiment a little with the callStatic magic method in PHP and see if I could create a pattern to expand on the helper functions that are already in WordPress for the sole purpose of  being used as filter callbacks.

And if you didn’t know about those yet, well, you’re welcome:

__return_true()
__return_false()
__return_null()
__return_zero()
__return_empty_string()
__return_empty_array()

So, I created a class called Returner where you can define the type and value you want to return directly in the method name itself:

add_filter( 'twentyseventeen_front_page_sections', 'Returner::int__6' );

Pretty cool!

Alright, time for the caveats.

You can’t use Returner unless you have PHP 5.3+, and if you have 5.3 then you might as well be using a closure, and if you’re using a closure… well, it’s only like 6 additional characters:

add_filter( 'twentyseventeen_front_page_sections', function() { return 6; } );

In the end, I don’t think my magical class is very practical, but it was still a fun experiment. I especially think the method for doing indexed array output was clever, though real-world application for that is probably pretty rare. Ha! Go figure.

Enjoy.

<?php

/**
 * This class is designed to return a basic value by parsing the dynamic
 * static method name you call to determine its type and value.
 *
 * It's useful for filtering values in WordPress quickly without having
 * to create a callback function. Think of this as a continuation of the
 * callback helpers already in WordPress: __return_true(), et al.
 *
 * EXAMPLES
 * add_filter( 'twentyseventeen_front_page_sections', 'Returner::int__4' );
 * add_filter( 'site_icon_sizes', 'Returner::array__256__128__64' );
 * add_filter( 'post_class', 'Returner::featured' );
 *
 * @author  Frankie Jarrett
 * @license https://www.gnu.org/licenses/gpl-2.0.html GPL-2.0
 */
class Returner {

	/**
	 * Magic value returner method.
	 *
	 * @access public
	 * @static
	 *
	 * @param  string $name
	 * @param  array  $args (unused)
	 *
	 * @return mixed
	 */
	public static function __callStatic( $name, $args ) {

		/**
		 * Return an integer.
		 *
		 * Returner::int__6() ==> 6
		 */
		if ( 0 === strpos( $name, 'int__' ) ) {

			return (int) self::value( $name );

		}

		/**
		 * Return a negative integer.
		 *
		 * Returner::nint__6() ==> -6
		 */
		if ( 0 === strpos( $name, 'nint__' ) ) {

			return (int) self::value( $name ) * -1;

		}

		/**
		 * Return a floating point number.
		 *
		 * Returner::float__1_234() ==> 1.234
		 */
		if ( 0 === strpos( $name, 'float__' ) ) {

			return (float) str_replace( '_', '.', self::value( $name ) );

		}

		/**
		 * Return a negative floating point number.
		 *
		 * Returner::nfloat__1_234() ==> -1.234
		 */
		if ( 0 === strpos( $name, 'nfloat__' ) ) {

			return (float) str_replace( '_', '.', self::value( $name ) ) * -1;

		}

		/**
		 * Return a one-dimensional indexed array.
		 *
		 * Returner::array__foo__bar_baz() ==> [ 'foo', 'bar baz' ]
		 * Returner::array__1__foo__3() ==> [ 1, 'foo', 3 ]
		 * Returner::array__foo__FALSE__bar ==> [ 'foo', false, 'baz' ]
		 */
		if ( 0 === strpos( $name, 'array__' ) ) {

			$array = [];

			foreach ( explode( '__', self::value( $name ) ) as $value ) {

				if ( 'TRUE' === $value ) {

					$array[] = true;

					continue;

				}

				if ( 'FALSE' === $value ) {

					$array[] = false;

					continue;

				}

				$value = trim( str_replace( '_', ' ', $value ) );

				$array[] = is_numeric( $value ) ? (int) $value : $value;

			}

			return $array;

		}

		/**
		 * Return a string.
		 *
		 * Returner::foo_bar_baz() ==> 'foo bar baz'
		 */
		return trim( str_replace( '_', ' ', $name ) );

	}

	/**
	 * Return the value portion of a method name.
	 *
	 * @access public
	 * @static
	 *
	 * @param  string $name
	 *
	 * @return string
	 */
	public static function value( $name ) {

		return preg_replace( '/^[a-z]+__/', '', $name );

	}

}

Link to Gist

Leave a Reply

Your email address will not be published. Required fields are marked *

Up Next:

Introducing the Strong Password Generator plugin for WordPress

Introducing the Strong Password Generator plugin for WordPress