En una situación en la que un complemento ha encapsulado sus métodos dentro de una clase y luego ha registrado un filtro o acción contra uno de esos métodos, ¿cómo elimina la acción o el filtro si ya no tiene acceso a la instancia de esa clase?
Por ejemplo, suponga que tiene un complemento que hace esto:
class MyClass {
function __construct() {
add_action( "plugins_loaded", array( $this, 'my_action' ) );
}
function my_action() {
// do stuff...
}
}
new MyClass();
Teniendo en cuenta que ahora no tengo forma de acceder a la instancia, ¿cómo puedo cancelar el registro de la clase? Esto: remove_action( "plugins_loaded", array( MyClass, 'my_action' ) );
no parece ser el enfoque correcto, al menos, no parece funcionar en mi caso.
Respuestas:
Lo mejor que puedes hacer aquí es usar una clase estática. El siguiente código debe ser instructivo:
Si ejecuta este código desde un complemento, debe notar que el método de StaticClass y la función se eliminarán de wp_footer.
fuente
remove_action
función, de lo contrario no funcionará ... es por eso que tuve que escribir mi propia función para manejar cuando no es una clase estática. Esta respuesta sólo sería el mejor si su pregunta fue sobre su propio código, de lo contrario se intenta eliminar otro filtro / acción por parte de otra persona código base y no se puede cambiar a la electricidad estáticaCada vez que un complemento crea un
new MyClass();
, debe asignarlo a una variable con un nombre único. De esa manera, la instancia de la clase es accesible.Entonces, si él estaba haciendo
$myclass = new MyClass();
, entonces podrías hacer esto:Esto funciona porque los complementos se incluyen en el espacio de nombres global, por lo que las declaraciones de variables implícitas en el cuerpo principal de un complemento son variables globales.
Si el complemento no guarda el identificador de la nueva clase en algún lugar , técnicamente, eso es un error. Uno de los principios generales de la Programación Orientada a Objetos es que los objetos a los que no hace referencia alguna variable en algún lugar están sujetos a limpieza o eliminación.
Ahora, PHP en particular no hace esto como lo haría Java, porque PHP es una implementación de OOP a medias. Las variables de instancia son solo cadenas con nombres de objeto únicos, algo así. Solo funcionan debido a la forma en que la interacción del nombre de la función variable funciona con el
->
operador. Tan solo hacernew class()
puede funcionar perfectamente, solo estúpidamente. :)Entonces, en resumen, nunca lo hagas
new class();
. Haga$var = new class();
y haga que $ var sea accesible de alguna manera para que otros bits lo hagan referencia.Editar: años después
Una cosa que he visto hacer muchos complementos es usar algo similar al patrón "Singleton". Crean un método getInstance () para obtener la única instancia de la clase. Esta es probablemente la mejor solución que he visto. Plugin de ejemplo:
La primera vez que se llama a getInstance (), crea una instancia de la clase y guarda su puntero. Puede usar eso para enganchar acciones.
Un problema con esto es que no puede usar getInstance () dentro del constructor si usa tal cosa. Esto se debe a que el nuevo llama al constructor antes de establecer la instancia $, por lo que llamar a getInstance () desde el constructor conduce a un bucle infinito y lo rompe todo.
Una solución alternativa es no usar el constructor (o, al menos, no usar getInstance () dentro de él), sino tener explícitamente una función "init" en la clase para configurar sus acciones y demás. Me gusta esto:
Con algo como esto, al final del archivo, después de que la clase se haya definido y tal, crear instancias del complemento se vuelve tan simple como esto:
Init comienza a agregar sus acciones, y al hacerlo llama a getInstance (), que crea una instancia de la clase y se asegura de que solo exista una de ellas. Si no tiene una función init, debería hacer esto para instanciar la clase inicialmente en su lugar:
Para abordar la pregunta original, eliminar ese gancho de acción desde el exterior (también conocido como, en otro complemento) se puede hacer así:
Ponga eso en algo conectado al
plugins_loaded
gancho de acción y deshacerá la acción que está siendo enganchada por el complemento original.fuente
wp_loaded
, noplugins_loaded
, lo que puede llamarse demasiado pronto.plugins_loaded
sería el lugar correcto. Lawp_loaded
acción ocurre después de lainit
acción, por lo que si su complemento realiza alguna accióninit
(y la mayoría lo hace), entonces desea inicializar el complemento y configurarlo antes de eso. Elplugins_loaded
gancho es el lugar adecuado para esa fase de construcción.2 pequeñas funciones PHP para permitir la eliminación de filtro / acción con clase "anónima": https://github.com/herewithme/wp-filters-extras/
fuente
Aquí hay una función ampliamente documentada que creé para eliminar filtros cuando no tiene acceso al objeto de clase (funciona con WordPress 1.2+, incluyendo 4.7+):
https://gist.github.com/tripflex/c6518efc1753cf2392559866b4bd1a53
fuente
Las soluciones anteriores parecen anticuadas, tuve que escribir las mías ...
fuente
Esta función se basa en la respuesta @Digerkam. Se agregó comparar si
$def['function'][0]
es una cadena y finalmente funcionó para mí.También el uso
$wp_filter[$tag]->remove_filter()
debería hacerlo más estable.Ejemplo de uso:
Coincidencia exacta
Cualquier prioridad
Cualquier clase y cualquier prioridad
fuente
Esta no es una respuesta genérica, sino una específica para el tema Avada y WooCommerce , que creo que otras personas pueden encontrar útil:
fuente