Skip to content

Instantly share code, notes, and snippets.

@tivnet
Created November 2, 2016 17:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tivnet/e0e35282865b2c4ee43509b08c8f230f to your computer and use it in GitHub Desktop.
Save tivnet/e0e35282865b2c4ee43509b08c8f230f to your computer and use it in GitHub Desktop.
Generate list of hooks (for WPGlobus)
<?php
/**
* File: apigen-hooks.php
*
* NOTE: this code is used internally in WPGlobus project.
* It's a W.I.P. - please use it, but do not forget to adapt for your project.
*
* @package WPGlobus\APIGen
* @author Gregory Karpinsky (@tivnet)
*/
/**
* Generate documentation for hooks.
* Idea borrowed from:
* @link https://github.com/woothemes/woocommerce/blob/master/apigen/hook-docs.php
*/
class WPGlobus_APIGen_Hooks {
protected static $current_file = '';
protected static $custom_hooks_found = array();
protected static $base_path = 'app/plugins/wpglobus/'; // TODO.
public static function process_hooks() {
$class_files = self::get_files( self::$base_path . 'includes/' );
/*
$template_files = self::get_files( '*.php', GLOB_MARK, '../templates/' );
$template_files[] = '../includes/wc-template-functions.php';
$template_files[] = '../includes/wc-template-hooks.php';
$shortcode_files = self::get_files( '*.php', GLOB_MARK, '../includes/shortcodes/' );
$widget_files = self::get_files( '*.php', GLOB_MARK, '../includes/widgets/' );
$admin_files = self::get_files( '*.php', GLOB_MARK, '../includes/admin/' );
$other_files = array(
'../woocommerce.php'
);*/
$files_to_scan = array(
'Class Hooks' => $class_files,
/*
'Template Hooks' => $template_files,
'Shortcode Hooks' => $shortcode_files,
'Widget Hooks' => $widget_files,
'Admin Hooks' => $admin_files,
'Other Hooks' => $other_files,*/
);
$scanned = array();
ob_start();
foreach ( $files_to_scan as $heading => $files ) {
self::$custom_hooks_found = array();
/** @var array $files */
foreach ( $files as $f ) {
self::$current_file = basename( $f );
$tokens = token_get_all( file_get_contents( $f ) );
$token_type = false;
$current_class = '';
$current_function = '';
/* @noinspection DisconnectedForeachInstructionInspection */
if ( in_array( self::$current_file, $scanned, true ) ) {
continue;
}
$scanned[] = self::$current_file;
foreach ( $tokens as $index => $token ) {
if ( is_array( $token ) ) {
$trimmed_token_1 = trim( $token[1] );
if ( T_CLASS === $token[0] ) {
$token_type = 'class';
} elseif ( T_FUNCTION === $token[0] ) {
$token_type = 'function';
} elseif ( 'do_action' === $token[1] ) {
$token_type = 'action';
} elseif ( 'apply_filters' === $token[1] ) {
$token_type = 'filter';
} elseif ( $token_type && ! empty( $trimmed_token_1 ) ) {
switch ( $token_type ) {
case 'class' :
$current_class = $token[1];
break;
case 'function' :
$current_function = $token[1];
break;
case 'filter' :
case 'action' :
$hook = trim( $token[1], "'" );
$loop = 0;
/* @noinspection SubStrUsedAsArrayAccessInspection */
if ( '_' === substr( $hook, '-1', 1 ) ) {
$hook .= '{';
$open = true;
// Keep adding to hook until we find a comma or colon
while ( 1 ) {
$loop ++;
$next_hook = trim( trim( is_string( $tokens[ $index + $loop ] ) ? $tokens[ $index + $loop ] : $tokens[ $index + $loop ][1], '"' ), "'" );
if ( in_array( $next_hook, array( '.', '{', '}', '"', "'", ' ' ), true ) ) {
continue;
}
/* @noinspection SubStrUsedAsArrayAccessInspection */
$hook_first = substr( $next_hook, 0, 1 );
/* @noinspection SubStrUsedAsArrayAccessInspection */
$hook_last = substr( $next_hook, - 1, 1 );
if ( in_array( $next_hook, array( ',', ';' ), true ) ) {
if ( $open ) {
$hook .= '}';
/* @noinspection PhpUnusedLocalVariableInspection */
$open = false;
}
break;
}
if ( '_' === $hook_first ) {
$next_hook = '}' . $next_hook;
$open = false;
}
if ( '_' === $hook_last ) {
$next_hook .= '{';
$open = true;
}
$hook .= $next_hook;
}
}
if ( isset( self::$custom_hooks_found[ $hook ] ) ) {
self::$custom_hooks_found[ $hook ]['file'][] = self::$current_file;
} else {
self::$custom_hooks_found[ $hook ] = array(
'line' => $token[2],
'class' => $current_class,
'function' => $current_function,
'file' => array( self::$current_file ),
'type' => $token_type,
'path' => $f,
);
}
break;
}
$token_type = false;
}
}
}
}
foreach ( self::$custom_hooks_found as $hook => $details ) {
if (
false === strpos( $hook, 'wpglobus_' )
) {
unset( self::$custom_hooks_found[ $hook ] );
}
}
ksort( self::$custom_hooks_found );
if ( ! empty( self::$custom_hooks_found ) ) {
echo '<!DOCTYPE html>';
?>
<html>
<head>
<title>WPGlobus Hooks</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous" />
</head>
<body>
<div class="container">
<h1>WPGlobus Action and Filter Hooks</h1>
<p>Updated: <?php echo esc_html( date( 'r' ) ); ?></p>
<!-- <h2>--><?php //echo esc_html( $heading ); ?><!--</h2>-->
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Hook</th>
<th>Type</th>
<th>File(s)</th>
</tr>
</thead>
<tbody>
<?php
foreach ( self::$custom_hooks_found as $hook => $details ) {
$_hook_link = self::get_hook_link( $hook, $details );
?>
<tr>
<td><?php echo $_hook_link; // WPCS: XSS ok. ?></td>
<td><?php echo esc_html( $details['type'] ); ?></td>
<td><?php echo esc_html( implode( ', ', array_unique( $details['file'] ) ) ); ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
<div>
<hr/>
Copyright &copy; 2014-<?php echo esc_html( date( 'Y' ) ); ?>
<a href="http://www.wpglobus.com/">WPGlobus</a>
</div>
</div>
</body>
</html>
<?php
}
}
// echo ob_get_clean(); // WPCS: XSS ok.
file_put_contents( 'C:\var\www\u\qa.wpglobus.com\wpglobus-api-docs\docs\wpglobus-hooks.html', ob_get_clean() ); // TODO.
}
/**
* @param string $hook
* @param array $details
*
* @return string
*/
protected static function get_hook_link( $hook, array $details = array() ) {
if ( ! empty( $details['path'] ) ) {
$relative_url = str_replace( self::$base_path, '', $details['path'] );
$link = 'https://github.com/WPGlobus/WPGlobus/blob/develop/' . $relative_url . '#L' . $details['line']; // TODO.
} else {
$link = 'https://github.com/WPGlobus/WPGlobus/search?q=' . $hook;
}
return '<a href="' . $link . '">' . $hook . '</a>';
}
/**
* Find all PHP files in a folder.
*
* @param string $folder Folder to scan.
*
* @return array Array of files found.
*/
public static function get_files( $folder ) {
$iterator_php = new RegexIterator(
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator( $folder )
), '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH
);
$found_files = array();
foreach ( $iterator_php as $path ) {
$found_files[] = str_replace( '\\', '/', $path[0] );
}
return $found_files;
}
}
if ( ! function_exists( 'esc_html' ) ) {
/**
* Escaping for HTML blocks.
*
* @since 2.8.0
*
* @param string $text
*
* @return string
*/
function esc_html( $text ) {
return htmlentities( $text );
}
}
WPGlobus_APIGen_Hooks::process_hooks();
/* EOF */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment