Przekazywanie parametru do funkcji filtrowania i działania

52

To sposób na przekazanie własnych parametrów do funkcji w add_filterlub add_action. Na przykład spójrz na następujący kod:

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

Czy mogę przekazać własny parametr? coś jak:

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

lub

add_filter('the_content', 'my_content', 10, 1, $my_param)
Aakash Chakravarthy
źródło

Odpowiedzi:

78

Domyślnie nie jest to możliwe. Istnieją obejścia, jeśli robisz to w sposób OOP.
Możesz utworzyć klasę do przechowywania wartości, których chcesz użyć później.

Przykład:

/**
 * 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 )
            )
        );
    }
}

Teraz możesz wywołać klasę za pomocą dowolnej funkcji - jeśli funkcja gdzieś istnieje, zostanie wywołana z zapisanymi parametrami.

Utwórzmy funkcję demonstracyjną…

/**
 * 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>';
}

… I użyj go raz…

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

… i znowu …

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

Wynik:

wprowadź opis zdjęcia tutaj

Kluczem jest możliwość ponownego użycia : możesz ponownie wykorzystać klasę (aw naszych przykładach także funkcję).

PHP 5.3+

Jeśli można użyć wersji PHP 5.3 lub nowsze zamknięcia sprawi, że znacznie łatwiej:

$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>";
}

Minusem jest to, że nie można pisać testów jednostkowych dla zamknięć. 

fuxia
źródło
17
Nie tylko dostajesz głos za dobrą odpowiedzią na problem, który powinien mieć wbudowane rozwiązanie w rdzeniu WP , ale także dostajesz taki za powrót pięć miesięcy później, aby zaktualizować swoją odpowiedź na przykładzie zamknięcia PHP 5.3+.
Adam
1
Doskonała odpowiedź! Ale jak mogę później usunąć ten filtr utworzony przez tę anonimową funkcję?
Vinicius Tavares,
2
@ViniciusTavares Nie możesz. Zastanów się, zanim go użyjesz. :)
fuxia
5
Pamiętaj jednak, że jeśli zapiszesz funkcję anonimową w zmiennej (np. $func = function() use ( $param1 ) { $param1; };I add_action( $func, 11);), możesz ją usunąć za pośrednictwemremove_action( $func, 11 );
bonger
1
Ale nie zaleca się używania anonimowych funkcji we wtyczkach lub motywach, które udostępniasz światu (możesz ich używać do własnych projektów). Problem polega na tym, że nie będziesz w stanie ich odczepić. Każde podejście, z którego zdecydujesz się pójść, powinno być później niemożliwe.
Mueyiwa Moses Ikomi
1

Utwórz funkcję z niezbędnymi argumentami, które zwracają funkcję. Przekaż tę funkcję (funkcję anonimową, znaną również jako zamknięcie) do haka wp.

Pokazane tutaj dla powiadomienia administratora w backendie 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
źródło
1

Użyj anonimowych funkcji php :

$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
źródło
1

Wiem, że czas minął, ale miałem problem z przekazaniem własnego parametru, dopóki nie odkryłem, że czwarty parametr w add_filter to liczba przekazanych parametrów, w tym zawartość do zmiany. Więc jeśli przekażesz 1 dodatkowy parametr, liczba powinna wynosić 2, a nie 1 w twoim przypadku

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

i za pomocą

function my_content($content, $my_param) {...}
giacoder
źródło
1

Prawidłowy, naprawdę krótki i najbardziej wydajny sposób przekazywania dowolnej liczby argumentów do filtrów i działań WP pochodzi z @Wesam Alalem tutaj , który używa zamknięcia.

Dodałbym tylko, że można uczynić to jeszcze jaśniejszym i znacznie bardziej elastycznym, oddzielając rzeczywistą metodę wykonywania od anonimowego zamknięcia. W tym celu wystarczy wywołać metodę z zamknięcia w następujący sposób (zmodyfikowany przykład z odpowiedzi @Wesam Alalem).

W ten sposób możesz napisać tak długą lub skomplikowaną logikę, jak chcesz leksykalnie poza zamknięciem, którego używasz, aby zadzwonić do faktycznego użytkownika.

// ... 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
źródło
0

jeśli utworzysz własny hak, oto przykład.

// 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
}

następnie zaimplementuj hak:

// [ https://codex.wordpress.org/Function_Reference/apply_filters ]
echo apply_filters( 'filter_name', $first, $second, $third );
T.Todua
źródło
To nie przekazuje informacji z rejestracji do oddzwaniania. Mówi tylko, ile parametrów może zaakceptować wywołanie zwrotne.
fuxia
@fuxia, czy możesz zasugerować prostą zmianę, aby informacje zostały przekazane? Czy można po prostu zastosować wartości param po 3?
SherylHohman
0

Zawsze możesz używać globalnego, prawda?

  global $my_param;
samjco
źródło
To nie daje odpowiedzi na pytanie. Gdy zdobędziesz wystarczającą reputację , będziesz mógł komentować dowolny post ; zamiast tego podaj odpowiedzi, które nie wymagają wyjaśnienia od pytającego . - Z recenzji
cjbj
@cjbj Właściwie to robi. Pytanie brzmi, czy parametry mogą być przekazywane do „funkcji”, która znajduje się w add_filter lub add activity. Nie było jasne, czy użytkownik chce przekazać go w samej funkcji add_filter lub w funkcji add Działalności, chociaż takie jest założenie. :)
samjco,
0

Pomimo bezpośredniego wywoływania funkcji, zrób to w bardziej elegancki sposób: przekaż anonimową funkcję jako wywołanie zwrotne.

Na przykład:

Mam jedną funkcję do przetłumaczenia tytułu, treści i fragmentu moich postów. Muszę więc przekazać tej głównej funkcji kilka argumentów mówiących, kto dzwoni.

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' );
});

Tak więc funkcja główna translate_textotrzymuje tyle parametrów, ile chcę, tylko dlatego, że przekazałem funkcję anonimową jako wywołanie zwrotne.

Marcos Rezende
źródło
-1

Miałem nadzieję zrobić to samo, ale ponieważ nie jest to możliwe, prostym obejściem jest wywołanie innej funkcji, takiej jak add_filter('the_content', 'my_content_filter', 10, 1);

wtedy my_content_filter () może po prostu wywołać my_content () przekazując dowolny żądany argument.

Pierre-Verthume Larivière
źródło