Я обновлял пример страницы кодекса для хуков действий, играя, чтобы сделать некоторые повторно используемые функции (первоначально для некоторого Q здесь @WA). Но затем я столкнулся с проблемой, о которой раньше не знал: после подключения к функции для изменения вывода переменной я больше не могу решить, хочу ли я повторить вывод или просто вернуть его.
Проблема: я могу изменять переменные, которые я передаю в do_action
хук с помощью функции обратного вызова. Все, что я изменяю/добавляю с помощью переменной, доступно только внутри функции обратного вызова, но не после do_action
вызова внутри исходной функции.
ДЛЯ ВАШЕГО УДОВОЛЬСТВИЯ: Я переделал его в рабочий пример, так что вы можете просто скопировать/вставить его в какой -нибудь functions.php
файл и увидеть/протестировать проблему без каких-либо усилий.
Пример:
Функция обработки данных
Это handle_data_fn. Немного задокументировано, так как должно служить руководством о том, как анализировать и объединять default с другими аргументами.
Вы можете увидеть проблему в конце функции сразу после вызова do_action().
/**
* The "global" data handle function
*
* This function can serve a lot of different purposes.
* Incl. merging db values from an options entry with input arguments.
*
* Throws a fully translateable Error if no database option name was specified.
* Tells you from which file the Error was triggered and in which line you should search it.
* Also tells you the "hook_data_handle_$args['UID']" name of the action hook where the Error occured.
*
* Uses of external function calls in order of their appearance inside the function:
* @uses: isset() - @link: http://php.net/manual/en/function.isset.php
* @uses: wp_die() - @link: http://codex.wordpress.org/Function_Reference/wp_die
* @uses: printf() - @link: http://php.net/manual/en/function.printf.php
* @uses: _e() - @link: http://codex.wordpress.org/Function_Reference/_e (i18n function)
* @uses: apply_filters() - @link: http://codex.wordpress.org/Function_Reference/apply_filters
* @uses: wp_parse_args() - @link: http://codex.wordpress.org/Function_Reference/wp_parse_args
* @uses: extract() - @link: http://php.net/manual/en/function.extract.php
* @uses: get_option() - @link: http://codex.wordpress.org/Function_Reference/get_option
* @uses: do_action() - @link: http://codex.wordpress.org/Function_Reference/do_action
* @uses: return - @link: http://php.net/manual/en/function.return.php
*
* @param: (array) mixed $args | array of arguments - `$args['UID']` is always a must have
* @param: $database | true if you want to get and modify some db-option - `$args['name']` then is a must have
* @param: $output | result from the function - @internal: should not get set
*/
function handle_data_fn( $args = array() )
{
// abort if we ain't got some unique identifier as argument
if ( !isset( $args['UID']) )
return;
// Trigger Error if an option should get retrieved from the database,
// but no option name was specified
if ( !isset( $args['name'] ) )
wp_die(
printf(
_e(
'You have to specify the "name" of a db-entry as argument inside a handle_data_fn at for the action hook: %1$s.'."\n".
'Error triggered inside: file name %2$s (line number %3$s)'
)
,'some_textdomain'
)
,'hook_data_handle_'.$args['UID'].'`'
,__FILE__
,__LINE__
);
// setup default arguments
$defaults = (
array(
'UID' => null // DB/css: #id | used to identify the data inside your database - $name[$ID] - can be used as css #id too
,'name' => null // name of DB field, should be a constant when fn get's triggered - just here for completeness, not needed
,'args' => array( // $arguments the function can handle - put default arguments in here as array data
// 'classes' => null // css: .class - example
)
,'output' => ''
,'echo' => false // if you want to echo the output or just save it in a var for later modifying
)
);
// filter defaults
$defaults = apply_filters( 'filter_defaults_'.$args['UID'], $defaults );
// merge defaults with input arguments
$args = wp_parse_args( $args, $defaults );
extract( $args, EXTR_SKIP );
// in case you want to call the global function again,
// but for some reason need to modify the merged result of defaults & arguments
$args = apply_filters( 'filter_args_'.$args['UID'], $args );
// retrieve the database option
if ( isset( $args['name'] ) )
$options = get_option( $args['name'] );
# >>> start building $output
// if true, echo the $output
if ( isset( $args['echo'] ) )
{
if ( $args['echo'] === true )
{
// do stuff here - your argument is the initial array
do_action( 'hook_data_handle_'.$args['UID'], $args, $options );
// Test output inside handle_fn:
echo '<pre>From inside handle_fn: ';
print_r($args);
echo '</pre>';
return;
}
}
// else just return the $output
// HOW CAN I NOT ECHO THE DATA HERE.
// STORING THE do_action return VALUE DOESN'T WORK.
// NEITHER DOES JUST returnING IT INSIDE THE CALLBACK FN 'modify_args_fn' BELOW
do_action( 'hook_data_handle_'.$args['UID'], $args, $options );
return;
# <<< end building $output
}
Функции обратного вызова
Они используются для а) построения исходного массива и б) изменения вывода.
/**
* EXAMPLE for how to add initial data to the handle_data_fn function.
*
* @param (array) mixed $args
*/
function build_args_fn ( $args ) {
// build initial array
$args = array(
'UID' => 'whatever_UID'
,'name' => 'some_options_name'
,'args' => array(
'class' => 'example-wrap'
)
,'echo' => true
);
handle_data_fn( $args );
}
// 'some_hook' is some hook in a template file where the output should get echoed.
add_action( 'some_hook', 'build_args_fn', 0, 1 );
/**
* EXAMPLE for how to add content and modify the options from the DB inside a handle_data_fn function.
*
* @param (array) mixed $args
* @param (array) mixed $options | db-options retrieved inside the oxo_parse function
*/
function modify_args_fn ( $args, $options )
{
$args['output'] .= '<div class="container">';
$args['output'] .= '<div class="'.$args['args']['class'].'">';
$args['output'] .= $options;
$args['output'] .= '</div>';
$args['output'] .= '</div>';
// Test output inside callback fn
echo '<pre>From inside callback: ';
print_r($args);
echo '</pre>';
// HERE'S THE PROBLEM. I CAN'T SIMPLE return IT, BECAUSE IT WOULDN'T BE AVAILABLE INSIDE MY 'data_handle_fn'.
# return $args['output'];
// I HAVE TO PRINT IT TO GET SOME OUTPUT. THE $args['output'] IS NOT AVAILABLE INSIDE THE 'handle_data_fn' AFTER THE do_action CALL.
return print $args['output'];
}
// Name of the hook comes from 'UID' argument in 'build_args_fn' combined with 'hook_data_handle_'
add_action ( 'hook_data_handle_whatever_UID', 'modify_args_fn', 10, 2 );
Спасибо за любую информацию и помощь по этому вопросу.
Действия предназначены не для изменения данных, они представляют собой моменты времени для получения дополнительных результатов, фильтры предназначены для изменения данных до того, как с ними произойдет что-то конкретное. Если хук хочет, чтобы данные были изменены, это обычно фильтр, если хуки хотят, чтобы дополнительный вывод происходил в определенном месте, это действие… обычно
@ t31os — я часто использую действия для изменения данных в глобальных переменных, потому что часто нет другого способа выполнить конкретное требование клиента. JMTCW.
@Mike — Конечно, вы можете использовать его для изменения глобальных переменных, я просто сказал, что обычно действия не предназначены для изменения данных, хотя в некоторых случаях они могут быть.
@ t31os — Согласен. Единственная причина, по которой я упомянул, заключается в том, что некоторые люди воспринимают то, что они читают от таких людей, как вы, которых они уважают, как догму. В то время как вы знаете, когда нарушать директиву, многие, как правило, будут ее придерживаться.
@MikeSchinkel @t31os Я проголосовал за оба ваших комментария. Хорошо, что это упомянуто здесь (что они
generally
не предназначены для изменения данных) под этим Q. Сама Q/функция достаточно абстрактна, чтобы вызвать некоторую путаницу. (Судя по самому коду основной функции, нет реальной разницы междуdo_action
иapply_filters
.)Итак, вы бы предложили заменить второй
do_action
наapply_filters
? Это заставит меня отказаться от аргумента эха и решить, хочу ли я использовать фильтр или вызов действия, который я бы тоже назвал «менее элегантным» :). Более того, я не знал бы, как передать$args
и$options
в один фильтр и работать с ним. Не могли бы вы обновить свой ответ и привести какой-нибудь (краткий) пример? Спасибо.@Kaiser — взгляните на wordpress.stackexchange.com/questions/12470/… там есть простой пример работы с apply_filters.
@Bainternet: Извините, но это не ответ на вопрос. Это некоторое объяснение того, как работают хуки и фильтры. Я уже знаю, как работает концепция. — Если вы хотите рассказать мне о каком-то чередующемся понятии: не стесняйтесь учить меня.
Обновленный ответ.
Так было у меня сначала, до того, как я попытался использовать крючок, и это не сработало. Я хотел сказать вам это, но я только что попробовал это снова, и это сработало. Я предполагаю, что я написал что-то с опечаткой или подобную глупость. Итак, спасибо за ваше время и ответ. +1
Если вы хотите вернуть данные, лучшим решением является использование apply_filters() и указание обратному вызову всегда возвращать:
Менее элегантным решением было бы использование буферизации вывода.