Генерация неактивных ссылок хуков

10

Похоже, что многие разработчики плагинов тратят время на добавление хуков фильтра / действия, чтобы позволить пользователям настраивать функциональность своих продуктов. Это здорово, но часто они не предоставляют список хуков и сколько аргументов они принимают.

Кто-нибудь нашел лучший автоматический способ указать на каталог плагина (или темы) и увидеть список всех доступных хуков?

Мне показалось, что некоторые плагины сканируют хуки, но, насколько я могу судить, они показывают, какие из них на самом деле вызываются для отображения данной страницы. Что я могу получить, может быть удобно. Но иногда, если я знаю, что я взаимодействую с определенным плагином, я хочу знать каждое место, где он может позволить мне подключить действие или фильтр.

Итак, что я действительно ищу, так это то, что, учитывая корневой каталог плагина, создаст список, в котором каждый элемент включает в себя:

  • тег
  • тип (действие или фильтр)
  • количество аргументов
  • где это называется (через do_action()или apply_filter()) в источнике

Сценарий был бы великолепен, так как он, по-видимому, мог бы красиво HTMLify целиком и показать его мне прямо в интерфейсе администратора для каждого плагина. Но даже сценарий командной строки, который выводит полезный статический файл, был бы великолепен.

yonatron
источник
так в чем вопрос? если вы ищете рекомендацию для плагина, то это не по теме
Марк Каплун
Извините, я не хочу слишком углубляться в мета- сорняки WordPress Development , но а) Я новичок здесь, поэтому я не осознавал, что запрашивать рекомендации по плагину - ОТ. Я мог бы иметь ... некоторые мнения ... по этому поводу, но, тем не менее, я должен был сначала это понять. б) OTOH, я просто пытаюсь найти какое-либо решение моего вопроса, будь то существующий плагин или сценарий оболочки, или что-то с нуля. Таким образом, вопрос строго по запросу плагинов!
Йонатрон
ну, похоже, что все остальные развлекаются, так что никакого вреда не причинено. Мое "возражение" против вопроса было на самом деле больше о том, что это вопрос разбора текста, который интересен для людей, которые любят писать программы в стиле компилятора, но имеют мало общего с реальным кодированием WordPress. Для записи, даже вопросы, связанные с wordpress.org, например, о том, как отправить плагин, обычно голосуют как не по теме.
Марк Каплун

Ответы:

6

Я не знаю сценарий или плагин, чтобы делать то, что вы хотите. Как вы сказали, есть сценарии ( даже глобальные переменные ), которые вы можете использовать для печати фильтров и используемых в настоящее время действий.

Что касается бездействующих фильтров и действий, я написал две очень основные функции ( с некоторой помощью здесь и там ), которые находят все apply_filtersи do_actionэкземпляры в файле, а затем распечатывают его

ОСНОВЫ

  • Мы будем использовать классы RecursiveDirectoryIterator, RecursiveIteratorIteratorи RegexIteratorPHP, чтобы получить все файлы PHP в каталоге. Как пример, на моем локальном хосте я использовалE:\xammp\htdocs\wordpress\wp-includes

  • Затем мы будем перебирать файлы, искать и возвращать ( preg_match_all) все экземпляры apply_filtersи do_action. Я настроил его для соответствия вложенных экземпляров скобок, а также для сопоставления возможных пробелов между apply_filters/ do_actionи первой скобкой

Мы просто создадим массив со всеми фильтрами и действиями, а затем пройдемся по массиву и выведем имя файла, фильтры и действия. Мы будем пропускать файлы без фильтров / действий

ВАЖНЫЕ ЗАМЕТКИ

  • Эти функции очень дороги. Запускайте их только при локальной тестовой установке.

  • Измените функции по мере необходимости. Вы можете записать вывод в файл, создать для этого специальную бэкэнд-страницу, опции не ограничены

ОПЦИЯ 1

Первая функция опций очень проста, мы будем возвращать содержимое файла в виде строки, используя file_get_contents, искать apply_filters/ do_actionэкземпляры и просто выводить имя файла и имена фильтров / действий

Я прокомментировал код для легкого следования

function get_all_filters_and_actions( $path = '' )
{
    //Check if we have a path, if not, return false
    if ( !$path ) 
        return false;

    // Validate and sanitize path
    $path = filter_var( $path, FILTER_SANITIZE_URL );
    /**
     * If valiadtion fails, return false
     *
     * You can add an error message of something here to tell
     * the user that the URL validation failed
     */
    if ( !$path ) 
        return false;

    // Get each php file from the directory or URL  
    $dir   = new RecursiveDirectoryIterator( $path );
    $flat  = new RecursiveIteratorIterator( $dir );
    $files = new RegexIterator( $flat, '/\.php$/i' );

    if ( $files ) {

        $output = '';
        foreach($files as $name=>$file) {
            /**
             * Match and return all instances of apply_filters(**) or do_action(**)
             * The regex will match the following
             * - Any depth of nesting of parentheses, so apply_filters( 'filter_name', parameter( 1,2 ) ) will be matched
             * - Whitespaces that might exist between apply_filters or do_action and the first parentheses
             */
            // Use file_get_contents to get contents of the php file
            $get_file_content =  file_get_contents( $file );
            // Use htmlspecialchars() to avoid HTML in filters from rendering in page
            $save_content = htmlspecialchars( $get_file_content );
            preg_match_all( '/(apply_filters|do_action)\s*(\([^()]*(?:(?-1)[^()]*)*+\))/', $save_content, $matches );

            // Build an array to hold the file name as key and apply_filters/do_action values as value
            if ( $matches[0] )
                $array[$name] = $matches[0];
        }
        foreach ( $array as $file_name=>$value ) {

            $output .= '<ul>';
                $output .= '<strong>File Path: ' . $file_name .'</strong></br>';
                $output .= 'The following filters and/or actions are available';
                foreach ( $value as $k=>$v ) {
                    $output .= '<li>' . $v . '</li>';
                }
            $output .= '</ul>';
        }
        return $output;
    }

    return false;
}

Вы можете использовать по шаблону, веб-интерфейсу или бэкэнду

echo get_all_filters_and_actions( 'E:\xammp\htdocs\wordpress\wp-includes' );

Это напечатает

введите описание изображения здесь

ВАРИАНТ 2

Этот вариант немного дороже в запуске. Эта функция возвращает номер строки, в которой можно найти фильтр / действие.

Здесь мы используем, fileчтобы взорвать файл в массив, затем мы ищем и возвращаем фильтр / действие и номер строки

function get_all_filters_and_actions2( $path = '' )
{
    //Check if we have a path, if not, return false
    if ( !$path ) 
        return false;

    // Validate and sanitize path
    $path = filter_var( $path, FILTER_SANITIZE_URL );
    /**
     * If valiadtion fails, return false
     *
     * You can add an error message of something here to tell
     * the user that the URL validation failed
     */
    if ( !$path ) 
        return false;

    // Get each php file from the directory or URL  
    $dir   = new RecursiveDirectoryIterator( $path );
    $flat  = new RecursiveIteratorIterator( $dir );
    $files = new RegexIterator( $flat, '/\.php$/i' );

    if ( $files ) {

        $output = '';
        $array  = [];
        foreach($files as $name=>$file) {
            /**
             * Match and return all instances of apply_filters(**) or do_action(**)
             * The regex will match the following
             * - Any depth of nesting of parentheses, so apply_filters( 'filter_name', parameter( 1,2 ) ) will be matched
             * - Whitespaces that might exist between apply_filters or do_action and the first parentheses
             */
            // Use file_get_contents to get contents of the php file
            $get_file_contents =  file( $file );
            foreach ( $get_file_contents as  $key=>$get_file_content ) {
                preg_match_all( '/(apply_filters|do_action)\s*(\([^()]*(?:(?-1)[^()]*)*+\))/', $get_file_content, $matches );

                if ( $matches[0] )
                    $array[$name][$key+1] = $matches[0];
            }
        }

        if ( $array ) {
            foreach ( $array as $file_name=>$values ) {
                $output .= '<ul>';
                    $output .= '<strong>File Path: ' . $file_name .'</strong></br>';
                    $output .= 'The following filters and/or actions are available';

                    foreach ( $values as $line_number=>$string ) {
                        $whitespaces = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
                        $output .= '<li>Line reference ' . $line_number . $whitespaces . $string[0] . '</li>';
                    }
                $output .= '</ul>';
            }
        }
        return $output;

    }

    return false;
}

Вы можете использовать по шаблону, веб-интерфейсу или бэкэнду

echo get_all_filters_and_actions2( 'E:\xammp\htdocs\wordpress\wp-includes' );

Это напечатает

введите описание изображения здесь

РЕДАКТИРОВАТЬ

Это в основном столько, сколько я могу сделать без тайм-аутов скриптов или нехватки памяти. С кодом в варианте 2 это так же просто, как перейти к указанному файлу и указанной строке в исходном коде, а затем получить все допустимые значения параметров фильтра / действия, а также, что важно, получить функцию и дополнительный контекст, в котором фильтр / действие используется

Питер Гусен
источник
1
у вас слишком много свободного времени;) но, в конце концов, никогда не достаточно знать, что такое фильтры, а также каковы ожидаемые значения параметров и результаты, и это не может быть достигнуто из источника без bactracking, чтобы получить блок doc в случае основных файлов и, вероятно, не доступны вообще в неосновных плагинах и темах.
Марк Каплун
1
@MarkKaplun это просто то, над чем я быстро поработал :-). Приведенные выше функции, по крайней мере, сообщают вам, где находятся фильтры и действия в определенных каталогах плагина / темы / ядра. По-прежнему очень важно вернуться к источнику и убедиться, что вы понимаете, что конкретно делает конкретный фильтр. Некоторые плагины и темы плохо документированы, поэтому вам все равно понадобятся какие-то знания и опыт, чтобы узнать или выяснить, что конкретный фильтр выполняет в определенной функции ;-)
Pieter Goosen
@PieterGoosen Да, я обычно в порядке, когда возвращаюсь, чтобы посмотреть на источник. Если я делаю это в первую очередь, это означает, что плагин имеет хуки, но не обязательно блоки документов для них. Но если я посмотрю, где они на самом деле используются, это поможет мне понять, насколько они ценны. В любом случае они выглядят так, как будто они могут быть великолепными. Я мог бы даже изменить их 2-й, чтобы просто записать в файл HTML, потому что тогда я мог бы просто вставить объявление функции в плагин MU на локальном сервере и запустить его из WP CLI.
Йонатрон
@yonatron Рад, что мои два цента как-то помогают. Если вы когда-нибудь захотите написать свою модификацию из моего кода, вы всегда можете добавить свой код и объяснение в ответ ( что будет здорово ) ;-). Наслаждайтесь
Питер Гусен
1
@PieterGoosen сколько времени вы потратили на написание этого сценария и на документирование, черт возьми, это
круто
6

Похоже, WP Parser делает то, что вы ищете. Он используется для генерации официальной ссылки разработчика . В нем перечислены параметры, теги @since и ссылки на источник. Он работает со всеми плагинами WordPress и доступен через командную строку:

wp parser create /path/to/source/code --user=<id|login>
Ян Бек
источник
1
Я не очень хорошо знаком с этим сценарием, но, похоже, ему нужен фильтр или действие, чтобы хорошо документировать. Буду признателен за отзыв от @Rarst ;-)
Питер Гусен
Я еще не пробовал, но, основываясь на описании, думаю, что проблема Питера в цели. Я хочу найти все хуки, а не только те, которым предшествуют хорошо отформатированные блоки документов. Я думаю, что люди, которые не торопятся комментировать свои хуки / функции с помощью соглашений WordPress, уже запускают этот вид скриптов и публикуют ссылки API на своих сайтах поддержки. Я понимаю, что в этом есть некоторый риск, так как, если разработчик публично не задокументирует фильтр, он может быть изменен / объявлен устаревшим без предупреждения, но для некоторых плагинов, которые я использую, я не могу дождаться, когда документы появятся в сети.
Йонатрон
Он также анализирует недокументированные хуки. Пример: developer.wordpress.org/reference/hooks/graceful_fail
Ян Бек
4

Быстрый и яростный

Хорошая старая *nixкомандная строка всегда удобна:

# grep  --line-number                                         \
        --exclude-dir=/path/to/some/directory                 \
        --include=*.php                                       \ 
        --recursive                                           \
        "add_filter\|do_action\|apply_filters"                \
        /path/to/wp-content/plugins/some-plugin               \ 
 | less

Многие другие варианты через #man grep.

Тогда мы можем даже создать простой скрипт bash wp-search.sh:

#!/bash/bin
grep --line-number                            \
    --exclude-dir=/path/to/some/directory     \
    --include=*.$1                            \
    --recursive $2 $3

и запустить его с.

 # bash wp-search.sh php "add_filter\|do_action\|apply_filters" /path/to/some-plugin

Симпатичный выход

Мы можем использовать --colorатрибут, чтобы раскрасить вывод grep, но учтите, что он не будет работать less.

Другой вариант - создать таблицу HTML для результатов поиска.

Вот awkпример, который я создал, который выводит результаты поиска в виде таблицы HTML в results.htmlфайл:

  | sed 's/:/: /2' \
  | awk ' \
        BEGIN { \
            print "<table><tr><th>Results</th><th>Location</th></tr>"  \
        } \
        { \
            $1=$1; location=$1; $1=""; print "<tr><td>" $0 "</td><td>" location "</td><tr>" \
        } \
        END {  \
           print "</table>" \
       }' \
 > results.html

где я использовал этот трюк для удаления всех начальных пробелов, а этот - для печати всех полей, кроме первого.

Я использую sedздесь только для добавления дополнительного пробела после второго двоеточия ( :), на случай, если там нет места.

скрипт

Мы могли бы добавить это в наш wp-search.shскрипт:

#!/bash/bin
grep   --with-filename \
       --line-number \
       --exclude-dir=/path/to/some/directory \
       --include=*.$1 \
       --recursive $2 $3 \
| sed 's/:/: /2' \
| awk ' BEGIN { \
        print "<table><tr><th>Results</th><th>Location</th></tr>"  \
    } \
    { \
        $1=$1; location=$1; $1=""; print "<tr><td>" $0 "</td><td>" location "</td><tr>" \
    } \
    END {  \
        print "</table>" \
    }' \
> /path/to/results.html

где вы должны настроить /path/to/some/directoryи /path/to/results.htmlв соответствии с вашими потребностями.

Пример - Поиск плагина

Если мы попробуем это на wordpress-importerплагине с:

bash wp-search.sh php "add_filter\|do_action" /path/to/wp-content/plugins/wordpress-importer/

тогда results.htmlфайл будет отображаться как:

полученные результаты

Пример - поиск в ядре

Я раз проверил это на ядро:

time bash wp-search.sh php "add_filter\|do_action" /path/to/wordpress/core/

real    0m0.083s
user    0m0.067s
sys     0m0.017s

и это быстро!

Заметки

Чтобы получить дополнительный контекст, мы могли бы использовать -C NUMBERgrep.

Мы могли бы изменить вывод HTML различными способами, но, надеюсь, вы сможете настроить его в соответствии со своими потребностями.

birgire
источник
Спасибо! Я использую grep в крайнем случае, но я такой новичок в оболочке, что я даже не удосужился использовать трубы для OR. Еще одна вещь, которую я хотел бы добавить, - это возможность немного ее напечатать. Вывод вышеупомянутой строки grep по-прежнему будет довольно сложным для просмотра.
Йонатрон
2
Я обновил ответ с примером симпатичной печати @yonatron
birgire