Skip to content

Instantly share code, notes, and snippets.

@shadyvb
Forked from westonruter/example.php
Created April 2, 2016 17:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shadyvb/3be22b61cd693f7fc9a0529c3b6ff432 to your computer and use it in GitHub Desktop.
Save shadyvb/3be22b61cd693f7fc9a0529c3b6ff432 to your computer and use it in GitHub Desktop.
Some code we're using at XWP to make plugins easier and cleaner to write.
<?php
require_once __DIR__ . '/pluginception.php'
class ShoutPlugin {
use Pluginception;
function __construct() {
/*
* This method comes from the Pluginception trait,
* and will parse out @action/@filter tags from this
* object's methods' PhpDoc blocks, and then call
* add_action() and add_filter(). Note that the
* arg count is not passed, as the PHP_MAX_INT is
* used instead.
*/
$this->add_hooks_from_object_method_docblocks();
}
/**
* Make all post titles ¡SHOUT!
*
* @filter the_title
*
* @param string $title
* @return string
*/
function shoutify_title( $title ) {
$title = '¡' . strtoupper( $title ) . '!';
return $title;
}
/**
* This will get added to the very bottom (priority 100) of the footer.
*
* @action wp_footer, 100
*/
function show_props() {
?>
<p>Props Shady Sharaf for idea to use Reflection API to parse out the
<code>@filter</code>/<code>@action</code> tags from method PhpDoc.</p>
<?php
}
}
$shout_plugin = new ShoutPlugin();
<?php
/**
* Add improved add_filter/add_action methods to any class, and support for declaring
* filter/action callbacks via tags in PhpDoc comments. Props Shady Sharaf (@shadyvb)
* for this application of the Reflection API.
*/
trait Pluginception {
/**
* @var array
*/
protected $added_hooks = array();
/**
*
*/
function __destruct() {
$this->remove_all_hooks();
}
/**
* @param $name
* @param $callback
* @param array $args
*
* @return mixed
*/
function add_filter( $name, $callback, $args = array( 'priority' => 10, 'arg_count' => PHP_INT_MAX ) ) {
return $this->_add_hook( 'filter', $name, $callback, $args );
}
/**
* @param $name
* @param $callback
* @param array $args
*
* @return mixed
*/
function add_action( $name, $callback, $args = array( 'priority' => 10, 'arg_count' => PHP_INT_MAX ) ) {
return $this->_add_hook( 'action', $name, $callback, $args );
}
/**
* @param $type
* @param $name
* @param $callback
* @param array $args
*
* @return mixed
*/
protected function _add_hook( $type, $name, $callback, $args = array() ) {
$priority = isset( $args['priority'] ) ? $args['priority'] : 10;
$arg_count = isset( $args['arg_count'] ) ? $args['arg_count'] : PHP_INT_MAX;
$fn = sprintf( '\add_%s', $type );
$retval = \call_user_func( $fn, $name, $callback, $priority, $arg_count );
$this->added_hooks[] = compact( 'type', 'name', 'callback', 'priority' );
return $retval;
}
/**
* Add actions/filters from the methods of this class based on doc blocks
*/
function add_hooks_from_object_method_docblocks() {
$reflector = new \ReflectionObject( $this );
foreach ( $reflector->getMethods() as $method ) {
$doc = $method->getDocComment();
$arg_count = $method->getNumberOfParameters();
if ( preg_match_all( '#\* @(?P<type>filter|action)\s+(?P<name>\w+)(?:,\s+(?P<priority>\d+))?#', $doc, $matches, PREG_SET_ORDER ) ) {
foreach ( $matches as $match ) {
$type = $match['type'];
$name = $match['name'];
$priority = is_null( $match['priority'] ) ? 10 : intval( $match['priority'] );
$callback = array( $this, $method->getName() );
call_user_func( array( $this, "add_{$type}" ), $name, $callback, $priority, $arg_count );
}
}
}
}
/**
*
*/
function remove_all_hooks() {
foreach ( $this->added_hooks as $added_hook ) {
$fn = sprintf( 'remove_%s', $added_hook['type'] );
call_user_func( $fn, $added_hook['name'], $added_hook['callback'], $added_hook['priority'] );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment