Passando um parâmetro para filtrar e funções de ação

52

É uma maneira de passar meus próprios parâmetros para a função em add_filterou add_action. Por exemplo, dê uma olhada no seguinte código:

function my_content($content, $my_param)
{
do something...
using $my_param here ...
return $content;
}
add_filter('the_content', 'my_content', 10, 1);

Posso passar meu próprio parâmetro? algo como:

add_filter('the_content', 'my_content($my_param)', 10, 1)

ou

add_filter('the_content', 'my_content', 10, 1, $my_param)
Aakash Chakravarthy
fonte

Respostas:

78

Por padrão, isso não é possível. Existem soluções alternativas se você fizer da maneira OOP.
Você pode criar uma classe para armazenar os valores que deseja usar posteriormente.

Exemplo:

/**
 * Stores a value and calls any existing function with this value.
 */
class WPSE_Filter_Storage
{
    /**
     * Filled by __construct(). Used by __call().
     *
     * @type mixed Any type you need.
     */
    private $values;

    /**
     * Stores the values for later use.
     *
     * @param  mixed $values
     */
    public function __construct( $values )
    {
        $this->values = $values;
    }

    /**
     * Catches all function calls except __construct().
     *
     * Be aware: Even if the function is called with just one string as an
     * argument it will be sent as an array.
     *
     * @param  string $callback Function name
     * @param  array  $arguments
     * @return mixed
     * @throws InvalidArgumentException
     */
    public function __call( $callback, $arguments )
    {
        if ( is_callable( $callback ) )
            return call_user_func( $callback, $arguments, $this->values );

        // Wrong function called.
        throw new InvalidArgumentException(
            sprintf( 'File: %1$s<br>Line %2$d<br>Not callable: %3$s',
                __FILE__, __LINE__, print_r( $callback, TRUE )
            )
        );
    }
}

Agora você pode chamar a classe com qualquer função que desejar - se a função existir em algum lugar, ela será chamada com seus parâmetros armazenados.

Vamos criar uma função de demonstração ...

/**
 * Filter function.
 * @param  array $content
 * @param  array $numbers
 * @return string
 */
function wpse_45901_add_numbers( $args, $numbers )
{
    $content = $args[0];
    return $content . '<p>' . implode( ', ', $numbers ) . '</p>';
}

... e use uma vez ...

add_filter(
    'the_content',
    array (
        new WPSE_Filter_Storage( array ( 1, 3, 5 ) ),
        'wpse_45901_add_numbers'
    )
);

… e de novo …

add_filter(
    'the_content',
    array (
        new WPSE_Filter_Storage( array ( 2, 4, 6 ) ),
        'wpse_45901_add_numbers'
    )
);

Resultado:

insira a descrição da imagem aqui

A chave é a reutilização : você pode reutilizar a classe (e em nossos exemplos também a função).

PHP 5.3 ou superior

Se você pode usar um PHP versão 5.3 ou fechamentos mais recentes, será muito mais fácil:

$param1 = '<p>This works!</p>';
$param2 = 'This works too!';

add_action( 'wp_footer', function() use ( $param1 ) {
        echo $param1;
    }, 11 
);
add_filter( 'the_content', function( $content ) use ( $param2 ) {
        return t5_param_test( $content, $param2 );
    }, 12
);

/**
 * Add a string to post content
 *
 * @param  string $content
 * @param  string $string This is $param2 in our example.
 * @return string
 */
function t5_param_test( $content, $string )
{
    return "$content <p><b>$string</b></p>";
}

A desvantagem é que você não pode escrever testes de unidade para fechamentos. 

fuxia
fonte
17
Não apenas você obtém uma votação positiva para uma resposta de qualidade para um problema que deveria ter uma solução embutida no núcleo do WP , mas também recebe uma para voltar cinco meses depois para atualizar sua resposta com o exemplo de fechamento do PHP 5.3+.
Adam
11
Excelente resposta! Mas como posso fazer para remover esse filtro criado por essa função anônima posteriormente?
Vinicius Tavares
2
@ViniciusTavares Você não pode. Pense antes de usá-lo. :)
fuxia
5
Nota no entanto, que se você salvar a função anônima a uma variável (por exemplo, $func = function() use ( $param1 ) { $param1; };e add_action( $func, 11);), então você pode removê-lo viaremove_action( $func, 11 );
Bonger
11
Mas não é aconselhável usar funções anônimas em plugins ou temas que você está lançando para o mundo (você pode usá-los em seus próprios projetos). O problema é que você não será capaz de soltá-los. Qualquer que seja a abordagem que você decida seguir deve ser desabilitada mais tarde.
Mueyiwa Moses Ikomi 22/02
1

Crie uma função com os argumentos necessários que retornam uma função. Passe esta função (função anônima, também conhecida como fechamento) para o gancho wp.

Mostrado aqui para um aviso de administrador no back-end do wordpress.

public function admin_notice_func( $message = '')
{
$class = 'error';
    $output = sprintf('<div class="%s"><p>%s</p></div>',$class, $message);
    $func = function() use($output) { print $output; };
    return $func;
}
$func = admin_notice_func('Message');
add_action('admin_notices', $func);
hornament
fonte
1

Use funções php Anonymous :

$my_param = 'my theme name';
add_filter('the_content', function ($content) use ($my_param) {
    //$my_param is available for you now
    if (is_page()) {
        $content = $my_param . ':<br>' . $content;
    }
    return $content;
}, 10, 1);
wesamly
fonte
1

Sei que o tempo passou, mas tive algum problema ao passar meu próprio parâmetro até descobrir que o quarto parâmetro no add_filter é o número de parâmetros passados, incluindo o conteúdo a ser alterado. Portanto, se você passar 1 parâmetro adicional, o número deve ser 2 e não 1 no seu caso

add_filter('the_content', 'my_content', 10, 2, $my_param)

e usando

function my_content($content, $my_param) {...}
giacoder
fonte
1

A maneira correta, realmente curta e mais eficiente de passar qualquer número de argumentos para os filtros e ações do WP é de @Wesam Alalem aqui , que usa o fechamento.

Gostaria apenas de acrescentar que você poderia torná-lo ainda mais claro e muito mais flexível, separando o método real do realizador do fechamento anônimo. Para isso, basta chamar o método a partir do fechamento da seguinte forma (exemplo modificado da resposta @Wesam Alalem).

Dessa forma, você pode escrever a lógica longa ou complicada que desejar lexicamente fora do fechamento que usa para chamar o agente real.

// ... inside some class

private function myMethod() {
    $my_param = 'my theme name';
    add_filter('the_content', function ($content) use ($my_param) {
        // This is the anonymous closure that allows to pass 
        // whatever number of parameters you want via 'use' keyword.
        // This is just oneliner.
        // $my_param is available for you now via 'use' keyword above
        return $this->doThings($content, $my_param);
    }, 10, 2);
}

private function doThings($content, $my_param) {
    // Call here some other method to do some more things
    // however complicated you want.
    $morethings = '';
    if ($content = 'some more things') {
        $morethings = (new MoreClass())->get();
    }
    return $my_param . ':<br>' . $content . $morethings;
}
bob-12345
fonte
0

se você criar seu próprio gancho, aqui está um exemplo.

// lets say we have three parameters  [ https://codex.wordpress.org/Function_Reference/add_filter ]
add_filter( 'filter_name', 'my_func', 10, 3 );
my_func( $first, $second, $third ) {
  // code
}

então implemente o gancho:

// [ https://codex.wordpress.org/Function_Reference/apply_filters ]
echo apply_filters( 'filter_name', $first, $second, $third );
T.Todua
fonte
Isso não passa informações do registro para o retorno de chamada. Apenas diz quantos parâmetros o retorno de chamada pode aceitar.
fuxia
@uxuxia, você pode sugerir uma alteração simples para que as informações sejam passadas? Será que alguém simplesmente aderiu aos valores dos parâmetros após o 3?
SherylHohman
0

Você sempre pode usar global, não é?

  global $my_param;
samjco
fonte
Isso não fornece uma resposta para a pergunta. Depois de ter reputação suficiente, você poderá comentar qualquer postagem ; em vez disso, forneça respostas que não exijam esclarecimentos do solicitante . - Resenha
cjbj
@cjbj Na verdade, sim. A questão é se os parâmetros podem ser passados ​​para a "função" que está em add_filter ou add_action. Não ficou claro se o usuário queria passá-lo na própria função add_filter ou add_action, mesmo que essa seja a suposição. :)
samjco 25/08
0

Apesar de chamar uma função diretamente, faça isso de uma maneira mais elegante: passe uma função anônima como retorno de chamada.

Por exemplo:

Eu tenho uma única função para traduzir o título, o conteúdo e o trecho das minhas postagens. Então, eu preciso passar para esta função principal alguns argumentos dizendo quem está chamando.

add_filter( 'the_title', function( $text ) { 
    return translate_text( $text, 'title', 'pl' );
});

add_filter( 'the_content', function( $text ) { 
    return translate_text( $text, 'content', 'pl' );
});

add_filter( 'the_excerpt', function( $text ) { 
    return translate_text( $text, 'excerpt', 'pl' );
});

Portanto, a função principal translate_textrecebe tantos parâmetros quanto eu quero, apenas porque eu passei uma função anônima como um retorno de chamada.

Marcos Rezende
fonte
-1

Eu esperava fazer o mesmo, mas como não é possível, acho que uma solução alternativa simples é chamar uma função diferente, como add_filter('the_content', 'my_content_filter', 10, 1);

então my_content_filter () pode chamar my_content () passando o argumento que quiser.

Pierre-Verthume Larivière
fonte