remove_action oder remove_filter mit externen Klassen?
-
-
N/P.Funktioniert unten Afür Sie?N/P. Does below A work for you?
- 0
- 2011-12-09
- kaiser
-
7 Antworten
- Stimmen
-
- 2011-12-10
Ambesten verwenden Sie hiereine statische Klasse. Derfolgende Code sollteeine Anleitung sein:
class MyClass { function __construct() { add_action( 'wp_footer', array( $this, 'my_action' ) ); } function my_action() { print '<h1>' . __class__ . ' - ' . __function__ . '</h1>'; } } new MyClass(); class MyStaticClass { public static function init() { add_action( 'wp_footer', array( __class__, 'my_action' ) ); } public static function my_action() { print '<h1>' . __class__ . ' - ' . __function__ . '</h1>'; } } MyStaticClass::init(); function my_wp_footer() { print '<h1>my_wp_footer()</h1>'; } add_action( 'wp_footer', 'my_wp_footer' ); function mfields_test_remove_actions() { remove_action( 'wp_footer', 'my_wp_footer' ); remove_action( 'wp_footer', array( 'MyClass', 'my_action' ), 10 ); remove_action( 'wp_footer', array( 'MyStaticClass', 'my_action' ), 10 ); } add_action( 'wp_head', 'mfields_test_remove_actions' );
Wenn Sie diesen Code überein Plugin ausführen,sollten Siebeachten,dass die Methode der StaticClass sowie die Funktion aus wp_footerentfernt werden.
The best thing to do here is to use a static class. The following code should be instructional:
class MyClass { function __construct() { add_action( 'wp_footer', array( $this, 'my_action' ) ); } function my_action() { print '<h1>' . __class__ . ' - ' . __function__ . '</h1>'; } } new MyClass(); class MyStaticClass { public static function init() { add_action( 'wp_footer', array( __class__, 'my_action' ) ); } public static function my_action() { print '<h1>' . __class__ . ' - ' . __function__ . '</h1>'; } } MyStaticClass::init(); function my_wp_footer() { print '<h1>my_wp_footer()</h1>'; } add_action( 'wp_footer', 'my_wp_footer' ); function mfields_test_remove_actions() { remove_action( 'wp_footer', 'my_wp_footer' ); remove_action( 'wp_footer', array( 'MyClass', 'my_action' ), 10 ); remove_action( 'wp_footer', array( 'MyStaticClass', 'my_action' ), 10 ); } add_action( 'wp_head', 'mfields_test_remove_actions' );
If you run this code from a plugin you should notice that the method of the StaticClass as well as the function will removed from wp_footer.
-
Punktgenommen,abernicht alle Klassen könneneinfachin statische konvertiert werden.Point taken, but not all classes can simply be converted to be static.
- 8
- 2012-02-29
- Geert
-
Ich habe diese Antwort akzeptiert,weil sie die Frage am direktestenbeantwortet,obwohl Ottos Antwort diebeste Vorgehensweiseist.Ich stelle hierfest,dass Siemeiner Meinungnachnichtexplizit statisch deklarierenmüssen.Ich habe die Erfahrunggemacht (obwohlichmichirren könnte),dass Sie die Funktioneinfach sobehandeln können,als wäre sieein statisches Array ('MyClass','member_function'),und siefunktioniert oft ohne das Schlüsselwort 'static'.I accepted this answer because it answers the question most directly, though Otto's response is the best practice. I note here that I don't think you need to explicitly declare static. It's been my experience (though I could be wrong) that you can just treat the function as though it were static array( 'MyClass', 'member_function' ) and it often works without the 'static' keyword.
- 0
- 2012-04-24
- Tom Auger
-
@ TomAugernein,das kannst dunicht,NUR wennes als statische Klasse hinzugefügt wird,kannst du die Funktion `remove_action` verwenden,sonstfunktioniertesnicht ... deshalbmussteichmeine eigene Funktion schreiben,um damit umzugehen,wennes keine statische Klasseist.Diese Antwortistnur dann diebeste,wenn Ihre Frage Ihreneigenen Codebetrifft. Andernfalls versuchen Sie,einen anderen Filter/eine andere Aktion aus der Codebasiseines anderen zuentfernen,und könnenihnnichtin statisch ändern@TomAuger no you can't, ONLY if it's added as a static class can you use the `remove_action` function, otherwise it will not work...that's why I had to write my own function to handle when it's not a static class. This answer would only be the best if your question was regarding your own code, otherwise you will be trying to remove another filter/action from someone else's codebase and can't change it to static
- 0
- 2016-09-20
- sMyles
-
- 2011-12-10
Immer wennein Plugineine
new MyClass();
erstellt,sollteeseinereindeutigbenannten Variablen zugewiesen werden. Auf diese Weise kann auf die Instanz der Klasse zugegriffen werden.Wenner also
$myclass = new MyClass();
ausführt,können Sie Folgendestun:global $myclass; remove_action( 'wp_footer', array( $myclass, 'my_action' ) );
Diesfunktioniert,weil Pluginsim globalen Namespaceenthalten sind. Implizite Variablendeklarationenim Hauptteileines Plugins sind alsoglobale Variablen.
Wenn das Plugin die Kennung derneuen Klasse nichtirgendwo speichert,ist dastechnischgesehenein Fehler. Eines der allgemeinen Prinzipien der objektorientierten Programmierungist,dass Objekte,auf dienichtirgendwo voneiner Variablen verwiesen wird,bereinigt oderentfernt werdenmüssen.
Nun,insbesondere PHPmacht diesnicht wie Java,da PHPeine halbherzige OOP-Implementierungist. Die Instanzvariablen sindnur Zeichenfolgenmit eindeutigen Objektnamen. Siefunktionierennur aufgrund der Funktionsweise der Interaktionmit dem Namen der variablen Funktionmit dem Operator
->
. Nurnew class()
zumachen,kannin der Tatperfektfunktionieren,nur dumm. :)Unterm Strich alsoniemals
new class();
. Führen Sie$var = new class();
aus undmachen Sie $ var aufirgendeine Weise zugänglich,damit andere Bits darauf verweisen können.Bearbeiten: Jahre später
Ich habe viele Pluginsgesehen,dieetwas Ähnliches wie das "Singleton" -Muster verwenden. Sieerstelleneine getInstance () -Methode,um dieeinzelne Instanz der Klasse abzurufen. Diesist wahrscheinlich diebeste Lösung,dieichgesehen habe. Beispiel-Plugin:
class ExamplePlugin { protected static $instance = NULL; public static function getInstance() { NULL === self::$instance and self::$instance = new self; return self::$instance; } }
Beimersten Aufruf vongetInstance () wird die Klasseinstanziiert undihr Zeigergespeichert. Damit können Sie Aktioneneinbinden.
Ein Problem dabeiist,dass SiegetInstance ()nichtim Konstruktor verwenden können,wenn Sie soetwas verwenden. Dies liegt daran,dass derneue den Konstruktor aufruft,bevor die $ -Instanzfestgelegt wird. Das Aufrufen vongetInstance () vom Konstruktor ausführt zueiner Endlosschleife und unterbricht alles
Eine Problemumgehungbesteht darin,den Konstruktornicht zu verwenden (oder zumindestgetInstance ()nicht darin zu verwenden),sondernexpliziteine "init" -Funktionin der Klasse zu haben,um Ihre Aktionen und dergleicheneinzurichten. So:
public static function init() { add_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) ); }
Mit soetwas wird am Ende der Datei,nachdem die Klasse vollständig definiert wurde,das Instanziieren des Plugins soeinfach:
ExamplePlugin::init();
Initbeginnt mit dem Hinzufügen Ihrer Aktionen und ruft dabeigetInstance () auf,wodurch die Klasseinstanziiert und sichergestellt wird,dassnureine davon vorhandenist. Wenn Sie keine Init-Funktion haben,würden Sie diestun,um die Klasse zunächst zuinstanziieren:
ExamplePlugin::getInstance();
Um die ursprüngliche Frage zubeantworten,können Sie diesen Aktions-Hook von außen (auchbekannt alsin einem anderen Plugin) wiefolgtentfernen:
remove_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) );
Fügen Sie diesin etwasein,dasmit dem Aktionshaken
plugins_loaded
verknüpftist,undesmacht die Aktion rückgängig,die vom ursprünglichen Plugin verknüpft wird.Whenever a plugin creates a
new MyClass();
, it should assign it to a uniquely named variable. That way, the instance of the class is accessible.So if he was doing
$myclass = new MyClass();
, then you could do this:global $myclass; remove_action( 'wp_footer', array( $myclass, 'my_action' ) );
This works because plugins are included in the global namespace, so implicit variable declarations in the main body of a plugin are global variables.
If the plugin doesn't save the identifier of the new class somewhere, then technically, that's a bug. One of the general principles of Object Oriented Programming is that objects which are not being referenced by some variable somewhere are subject to cleanup or elimination.
Now, PHP in particular doesn't do this like Java would, because PHP is sorta a half-arsed OOP implementation. The instance variables are just strings with unique object names in them, sort of thing. They only work because of the way the variable function name interaction works with the
->
operator. So just doingnew class()
can indeed work perfectly, just stupidly. :)So, bottom line, never do
new class();
. Do$var = new class();
and make that $var accessible in some way for other bits to reference it.Edit: years later
One thing I've seen a lot of plugins doing is to use something similar to the "Singleton" pattern. They create a getInstance() method to get the single instance of the class. This is probably the best solution I've seen. Example plugin:
class ExamplePlugin { protected static $instance = NULL; public static function getInstance() { NULL === self::$instance and self::$instance = new self; return self::$instance; } }
The first time getInstance() is called, it instantiates the class and saves its pointer. You can use that to hook in actions.
One problem with this is that you can't use getInstance() inside the constructor if you use such a thing. This is because the new calls the constructor before setting the $instance, so calling getInstance() from the constructor leads to an infinite loop and breaks everything.
One workaround is to not use the constructor (or, at least, not to use getInstance() within it), but to explicitly have an "init" function in the class to set up your actions and such. Like this:
public static function init() { add_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) ); }
With something like this, at the end of the file, after the class has been all defined and such, instantiating the plugin becomes as simple as this:
ExamplePlugin::init();
Init starts to add your actions, and in so doing it calls getInstance(), which instantiates the class and makes sure only one of them exists. If you don't have an init function, you would do this to instantiate the class initially instead:
ExamplePlugin::getInstance();
To address the original question, removing that action hook from the outside (aka, in another plugin) can then be done like so:
remove_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) );
Put that in something hooked to the
plugins_loaded
action hook and it'll undo the action being hooked by the original plugin.-
+1 Tru dat.Diesisteindeutigeine bewährte Methode.Wir sollten uns allebemühen,unseren Plugin-Code so zu schreiben.+1 Tru dat. This is clearly a best practice. We should all endeavour to write our plugin code that way.
- 3
- 2012-04-24
- Tom Auger
-
+1 Diese Anweisungen habenmir wirklichgeholfen,einen Filterin einer Singleton-Musterklasse zuentfernen.+1 these instructions really helped me to remove a filter in a singleton pattern class.
- 3
- 2014-03-28
- Devin Walker
-
+1,aberich denke,Sie solltengenerell "wp_loaded" undnicht "plugins_loaded" verwenden,wasmöglicherweise zufrüh aufgerufen wird.+1, but I think you should generally hook to `wp_loaded`, not `plugins_loaded`, which may be called too early.
- 0
- 2015-04-28
- EML
-
Nein,"plugins_loaded" wäre der richtige Ort.Die Aktion "wp_loaded"erfolgtnach der Aktion "init". Wenn Ihr Plugin also Aktionenfür "init" ausführt (und diemeistentun dies),möchten Sie das Plugininitialisieren und vorhereinrichten.Der `plugins_loaded` Hookist der richtige Ortfür diese Bauphase.No, `plugins_loaded` would be the correct place. The `wp_loaded` action happens after the `init` action, so if your plugin takes any actions on `init` (and most do), then you want to initialize the plugin and set it up before that. The `plugins_loaded` hook is the right place for that construction phase.
- 4
- 2015-04-28
- Otto
-
Dies kannetwas spät sein,um zu antworten.Aber dankefür diesen Beitrag.Nachdem wir stundenlanggesucht hatten,stellten wirfest,dass wir die allgemeinen Prinzipien der objektorientierten Programmierungnichtbeachteten,wonach Objekte,auf dienichtirgendwo voneiner Variablen verwiesen wird,bereinigt oderbeseitigt werdenmüssen.This might be a little late to respond. But thank you for this input. After looking for hours we found out that we did not respect the general principles of Object Oriented Programming which is saying objects which are not being referenced by some variable somewhere are subject to cleanup or elimination.
- 0
- 2020-01-21
- NME New Media Entertainment
-
- 2012-11-06
2 kleine PHP-Funktionen zum Entfernen von Filtern/Aktionenmit der Klasse "anonym": https://github.com/herewithme/wp-filters-extras/
2 small PHP functions for allow removing filter/action with "anonymous" class : https://github.com/herewithme/wp-filters-extras/
-
Sehr coole Funktionen.Danke,dass du das hiergepostet hast!Very cool functions. Thanks for posting that here!
- 0
- 2012-11-06
- Tom Auger
-
Wiebereitsin meinem Beitrag untenerwähnt,werden diesein WordPress 4.7 kaputtgehen (es sei denn,das Repo wird aktualisiert,aber seit 2 Jahrennichtmehr).As mentioned be others in my post below, these will break in WordPress 4.7 (unless the repo gets updated, but hasn't in 2 years)
- 0
- 2016-09-20
- sMyles
-
Nur zubeachten,dass das Repo wp-filter-extrastatsächlichfür v4.7 und die WP_Hook-Klasse aktualisiert wurde.Just noting that the wp-filters-extras repo has indeed been updated for v4.7 and the WP_Hook class.
- 1
- 2017-05-04
- Dave Romsey
-
- 2017-12-25
Die obengenannten Lösungen sehen veraltet aus,musstenmeine eigenen schreiben ...
function remove_class_action ($action,$class,$method) { global $wp_filter ; if (isset($wp_filter[$action])) { $len = strlen($method) ; foreach ($wp_filter[$action] as $pri => $actions) { foreach ($actions as $name => $def) { if (substr($name,-$len) == $method) { if (is_array($def['function'])) { if (get_class($def['function'][0]) == $class) { if (is_object($wp_filter[$action]) && isset($wp_filter[$action]->callbacks)) { unset($wp_filter[$action]->callbacks[$pri][$name]) ; } else { unset($wp_filter[$action][$pri][$name]) ; } } } } } } } }
Above solutions look like outdated, had to write my own...
function remove_class_action ($action,$class,$method) { global $wp_filter ; if (isset($wp_filter[$action])) { $len = strlen($method) ; foreach ($wp_filter[$action] as $pri => $actions) { foreach ($actions as $name => $def) { if (substr($name,-$len) == $method) { if (is_array($def['function'])) { if (get_class($def['function'][0]) == $class) { if (is_object($wp_filter[$action]) && isset($wp_filter[$action]->callbacks)) { unset($wp_filter[$action]->callbacks[$pri][$name]) ; } else { unset($wp_filter[$action][$pri][$name]) ; } } } } } } } }
-
- 2019-11-13
In solchen Fällenfügt Wordpress dem Funktionsnameneinen Hash (eindeutige ID) hinzu und speichertihnin derglobalen Variablen
$wp_filter
. Wenn Sie also die Funktionremove_filter
verwenden,passiertnichts. Auch wenn Sie dem Funktionsnamen den Klassennamen wieremove_filter('plugins_loaded', ['MyClass', 'my_action'])
hinzufügen. Sie können lediglich allemy_action
-Hooksmanuell aus derglobalen Variablen$wp_filter
entfernen.Hierist die Funktion,um dies zutun:
function my_remove_filter($tag, $function_name, $priority = 10){ global $wp_filter; if( isset($wp_filter[$tag]->callbacks[$priority]) and !empty($wp_filter[$tag]->callbacks[$priority]) ){ $wp_filter[$tag]->callbacks[$priority] = array_filter($wp_filter[$tag]->callbacks[$priority], function($v, $k) use ($function_name){ return ( stripos($k, $function_name) === false ); }, ARRAY_FILTER_USE_BOTH ); } }
Verwenden Siees wiefolgt:
my_remove_filter('plugins_loaded', 'my_action');
In cases like this the Wordpress adds a hash (unique id) to the function name and stores it in the global
$wp_filter
variable. So if you useremove_filter
function nothing will happen. Even if you add the class name to the function name likeremove_filter('plugins_loaded', ['MyClass', 'my_action'])
. All you can is to remove all themy_action
hooks from the global$wp_filter
variable manually.Here is the function to do this:
function my_remove_filter($tag, $function_name, $priority = 10){ global $wp_filter; if( isset($wp_filter[$tag]->callbacks[$priority]) and !empty($wp_filter[$tag]->callbacks[$priority]) ){ $wp_filter[$tag]->callbacks[$priority] = array_filter($wp_filter[$tag]->callbacks[$priority], function($v, $k) use ($function_name){ return ( stripos($k, $function_name) === false ); }, ARRAY_FILTER_USE_BOTH ); } }
use it like:
my_remove_filter('plugins_loaded', 'my_action');
-
- 2019-05-29
Diese Funktionbasiert auf der Antwort von @Digerkam. Vergleich hinzugefügt,wenn
$def['function'][0]
ein Stringist undesendlichfürmichfunktioniert hat.Auch die Verwendung von
$wp_filter[$tag]->remove_filter()
sollte die Stabilitäterhöhen.function remove_class_action($tag, $class = '', $method, $priority = null) : bool { global $wp_filter; if (isset($wp_filter[$tag])) { $len = strlen($method); foreach($wp_filter[$tag] as $_priority => $actions) { if ($actions) { foreach($actions as $function_key => $data) { if ($data) { if (substr($function_key, -$len) == $method) { if ($class !== '') { $_class = ''; if (is_string($data['function'][0])) { $_class = $data['function'][0]; } elseif (is_object($data['function'][0])) { $_class = get_class($data['function'][0]); } else { return false; } if ($_class !== '' && $_class == $class) { if (is_numeric($priority)) { if ($_priority == $priority) { //if (isset( $wp_filter->callbacks[$_priority][$function_key])) {} return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } else { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } } else { if (is_numeric($priority)) { if ($_priority == $priority) { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } else { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } } } } } } } return false; }
Anwendungsbeispiel:
Genaue Übereinstimmung
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', 'MyClass', 'my_action', 0); });
Beliebige Priorität
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', 'MyClass', 'my_action'); });
Jede Klasse undjede Priorität
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', '', 'my_action'); });
This function based on @Digerkam answer. Added compare if
$def['function'][0]
is string and it's finally worked for me.Also using
$wp_filter[$tag]->remove_filter()
should make it more stable.function remove_class_action($tag, $class = '', $method, $priority = null) : bool { global $wp_filter; if (isset($wp_filter[$tag])) { $len = strlen($method); foreach($wp_filter[$tag] as $_priority => $actions) { if ($actions) { foreach($actions as $function_key => $data) { if ($data) { if (substr($function_key, -$len) == $method) { if ($class !== '') { $_class = ''; if (is_string($data['function'][0])) { $_class = $data['function'][0]; } elseif (is_object($data['function'][0])) { $_class = get_class($data['function'][0]); } else { return false; } if ($_class !== '' && $_class == $class) { if (is_numeric($priority)) { if ($_priority == $priority) { //if (isset( $wp_filter->callbacks[$_priority][$function_key])) {} return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } else { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } } else { if (is_numeric($priority)) { if ($_priority == $priority) { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } else { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } } } } } } } return false; }
Example usage:
Exact match
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', 'MyClass', 'my_action', 0); });
Any priority
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', 'MyClass', 'my_action'); });
Any Class and any priority
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', '', 'my_action'); });
-
- 2019-08-06
Diesist keinegenerische Antwort,sonderneine spezifische Antwort auf Avada-Thema und WooCommerce ,diemeiner Meinungnachfür andere hilfreich sein könnten:
function remove_woo_commerce_hooks() { global $avada_woocommerce; remove_action( 'woocommerce_single_product_summary', array( $avada_woocommerce, 'add_product_border' ), 19 ); } add_action( 'after_setup_theme', 'remove_woo_commerce_hooks' );
This is not a generic answer, but one specific to Avada theme and WooCommerce, which I think other people may find helpful:
function remove_woo_commerce_hooks() { global $avada_woocommerce; remove_action( 'woocommerce_single_product_summary', array( $avada_woocommerce, 'add_product_border' ), 19 ); } add_action( 'after_setup_theme', 'remove_woo_commerce_hooks' );
Wie können Siein einer Situation,in derein Plugin seine Methodenin einer Klassegekapselt und danneinen Filter odereine Aktionfüreine dieser Methoden registriert hat,die Aktion oder den Filterentfernen,wenn Sie keinen Zugriffmehr auf die Instanz dieser Klasse haben?
Angenommen,Sie habenein Plugin,das diestut:
Wie kannich die Registrierung der Klasse aufheben,daichjetzt keine Möglichkeit habe,auf die Instanz zuzugreifen?Dies:
remove_action( "plugins_loaded", array( MyClass, 'my_action' ) );
scheintnicht der richtige Ansatz zu sein - zumindest schienesin meinem Fallnicht zufunktionieren.