W sytuacji, gdy wtyczka zamknęła swoje metody w klasie, a następnie zarejestrowała filtr lub akcję przeciwko jednej z tych metod, w jaki sposób usunąć akcję lub filtr, jeśli nie masz już dostępu do instancji tej klasy?
Załóżmy na przykład, że masz wtyczkę, która to robi:
class MyClass {
function __construct() {
add_action( "plugins_loaded", array( $this, 'my_action' ) );
}
function my_action() {
// do stuff...
}
}
new MyClass();
Biorąc pod uwagę, że nie mam teraz dostępu do instancji, jak mogę wyrejestrować klasę? To: remove_action( "plugins_loaded", array( MyClass, 'my_action' ) );
nie wydaje się być właściwym podejściem - przynajmniej nie wydaje się, aby działało w moim przypadku.
Odpowiedzi:
Najlepszym rozwiązaniem jest użycie klasy statycznej. Poniższy kod powinien być instrukcją:
Jeśli uruchomisz ten kod z wtyczki, powinieneś zauważyć, że metoda StaticClass oraz funkcja zostaną usunięte z wp_footer.
źródło
remove_action
funkcji, w przeciwnym razie to nie zadziała ... dlatego musiałem napisać własną funkcję do obsługi, gdy nie jest to klasa statyczna. Ta odpowiedź byłaby najlepsza, gdyby twoje pytanie dotyczyło twojego kodu, w przeciwnym razie będziesz próbował usunąć inny filtr / akcję z bazy kodu innej osoby i nie możesz go zmienić na statycznyIlekroć wtyczka tworzy
new MyClass();
, powinna przypisać ją do zmiennej o unikalnej nazwie. W ten sposób instancja klasy jest dostępna.Więc jeśli to robił
$myclass = new MyClass();
, możesz to zrobić:Działa to, ponieważ wtyczki są zawarte w globalnej przestrzeni nazw, więc niejawne deklaracje zmiennych w głównej części wtyczki są zmiennymi globalnymi.
Jeśli wtyczka nie zapisuje gdzieś identyfikatora nowej klasy , technicznie to błąd. Jedną z ogólnych zasad programowania obiektowego jest to, że obiekty, do których nie odwołuje się jakaś zmienna, podlegają czyszczeniu lub eliminacji.
Teraz PHP w szczególności nie robi tego tak, jak zrobiłby to Java, ponieważ PHP jest w pewnym sensie implementacją OOP na wpół arse. Zmienne instancji to po prostu ciągi znaków z unikalnymi nazwami obiektów. Działają tylko ze względu na sposób, w jaki interakcja nazwy funkcji zmiennej działa z
->
operatorem. Więc samo robienienew class()
może naprawdę działać idealnie, po prostu głupio. :)Podsumowując, nigdy nie rób
new class();
. Zrób$var = new class();
i udostępnij ten $ var w jakiś sposób, aby inne bity mogły się do niego odwoływać.Edycja: lata później
Jedną z rzeczy, które widziałem wiele wtyczek, jest użycie czegoś podobnego do wzorca „Singleton”. Tworzą metodę getInstance (), aby uzyskać pojedyncze wystąpienie klasy. To chyba najlepsze rozwiązanie, jakie widziałem. Przykładowa wtyczka:
Przy pierwszym wywołaniu getInstance () tworzy instancję klasy i zapisuje jej wskaźnik. Możesz go użyć, aby włączyć działania.
Jednym z problemów jest to, że nie można używać getInstance () wewnątrz konstruktora, jeśli używa się takiej rzeczy. Wynika to z faktu, że nowe wywołuje konstruktor przed ustawieniem instancji $, więc wywołanie getInstance () z konstruktora prowadzi do nieskończonej pętli i psuje wszystko.
Jednym z obejść tego problemu jest nieużywanie konstruktora (lub przynajmniej nie używanie w nim getInstance ()), ale jawne posiadanie funkcji „init” w klasie do konfigurowania akcji i tym podobnych. Lubię to:
Z czymś takim na końcu pliku, po zdefiniowaniu całej klasy i utworzeniu instancji wtyczki staje się tak proste:
Init zaczyna dodawać twoje akcje, a tym samym wywołuje metodę getInstance (), która tworzy instancję klasy i upewnia się, że istnieje tylko jedna z nich. Jeśli nie masz funkcji init, zrób to, aby początkowo utworzyć instancję klasy:
Aby odpowiedzieć na pierwotne pytanie, można usunąć hak akcji z zewnątrz (inaczej w innej wtyczce) w następujący sposób:
Umieść to w czymś zaczepionym do
plugins_loaded
haka akcji, a cofnie akcję zaczepioną przez oryginalną wtyczkę.źródło
wp_loaded
, nieplugins_loaded
, co można nazwać zbyt wcześnie.plugins_loaded
byłoby właściwe miejsce.wp_loaded
Akcja dzieje się poinit
działaniu, więc jeśli plugin wykonuje żadnych czynności nainit
(i najbardziej zrobić), a następnie chcesz zainicjować wtyczki i ustawić go przed tym.plugins_loaded
Hak jest właściwym miejscem dla tego etapu budowy.2 małe funkcje PHP umożliwiające usunięcie filtru / akcji z klasą „anonimową”: https://github.com/herewithme/wp-filters-extras/
źródło
Oto obszernie udokumentowana funkcja, którą stworzyłem do usuwania filtrów, gdy nie masz dostępu do obiektu klasy (działa z WordPress 1.2+, w tym 4.7+):
https://gist.github.com/tripflex/c6518efc1753cf2392559866b4bd1a53
źródło
Powyższe rozwiązania wyglądają jak przestarzałe, musiałem napisać własne ...
źródło
Ta funkcja oparta jest na odpowiedzi @Digerkam. Dodano porównanie, jeśli
$def['function'][0]
jest łańcuchem i nareszcie zadziałało dla mnie.Również używanie
$wp_filter[$tag]->remove_filter()
powinno uczynić go bardziej stabilnym.Przykładowe użycie:
Dokładne dopasowanie
Dowolny priorytet
Każda klasa i każdy priorytet
źródło
To nie jest ogólna odpowiedź, ale jedna specyficzna dla motywu Avada i WooCommerce , które moim zdaniem mogą być pomocne dla innych osób:
źródło