Error de PHP con el manejador de shortcode desde una clase
Actualmente estoy usando el siguiente flujo genérico para agregar el shortcode para un plugin.
class MyPlugin {
private $myvar;
function baztag_func() {
print $this->myvar;
}
}
add_shortcode( 'baztag', array('MyPlugin', 'baztag_func') );
Ahora cuando esta clase y su método son llamados obtengo el siguiente error.
Fatal error: Using $this when not in object context in ...
(El número de línea es donde he impreso $this->myvar
)
¿Es esto un problema de WordPress o hay algo que estoy haciendo mal? Parece ser algo realmente simple.

Como indica el error, necesitas una instancia de la clase para usar $this
. Hay al menos tres posibilidades:
Hacer todo estático
class My_Plugin
{
private static $var = 'foo';
static function foo()
{
return self::$var; // ¡nunca uses echo o print en un shortcode!
}
}
add_shortcode( 'baztag', array( 'My_Plugin', 'foo' ) );
Pero esto ya no es realmente POO, solo es un espacio de nombres.
Crear un objeto real primero
class My_Plugin
{
private $var = 'foo';
public function foo()
{
return $this->var; // ¡nunca uses echo o print en un shortcode!
}
}
$My_Plugin = new My_Plugin;
add_shortcode( 'baztag', array( $My_Plugin, 'foo' ) );
Esto... funciona. Pero puedes encontrarte con problemas oscuros si alguien quiere reemplazar el shortcode.
Así que añade un método para proporcionar la instancia de la clase:
final class My_Plugin
{
private $var = 'foo';
public function __construct()
{
add_filter( 'get_my_plugin_instance', [ $this, 'get_instance' ] );
}
public function get_instance()
{
return $this; // devuelve el objeto
}
public function foo()
{
return $this->var; // ¡nunca uses echo o print en un shortcode!
}
}
add_shortcode( 'baztag', [ new My_Plugin, 'foo' ] );
Ahora, cuando alguien quiera obtener la instancia del objeto, solo tiene que escribir:
$shortcode_handler = apply_filters( 'get_my_plugin_instance', NULL );
if ( is_a( $shortcode_handler, 'My_Plugin ' ) )
{
// hacer algo con esa instancia.
}
Solución antigua: crear el objeto en tu clase
class My_Plugin
{
private $var = 'foo';
protected static $instance = NULL;
public static function get_instance()
{
// crear un objeto
NULL === self::$instance and self::$instance = new self;
return self::$instance; // devuelve el objeto
}
public function foo()
{
return $this->var; // ¡nunca uses echo o print en un shortcode!
}
}
add_shortcode( 'baztag', array( My_Plugin::get_instance(), 'foo' ) );

gracias hombre... esa información no tiene precio ya que wordpress.org no menciona tanto en su página de documentación de add_shortcode. Había encontrado la solución pero como has descartado eso como una mala práctica y tienes una mejor solución, marco este problema como resuelto :)

Lamento mucho desenterrar esta antigua pregunta, pero ¿podrías explicar qué hace esta línea: NULL === self::$instance and self::$instance = new self;
? Estoy un poco confundido porque se usan ===
y and
, pero sin un if
, si sabes a lo que me refiero.

@Sven Esto es una verificación para evitar una segunda instancia. Hace que esta clase sea un Singleton... No lo haría hoy en día. Voy a reescribir esta respuesta.

¡Gracias por eso! Creo que ahora voy por el camino correcto, aunque es asombroso lo complicado que puede ser usar WordPress y POO ;-)

@Sven El núcleo de WordPress está escrito de la manera más anti-POO posible. Incluso el código nuevo ignora todo lo que el resto del mundo PHP ha aprendido en los últimos diez años, como la inyección de dependencias. Así que sí, la POO en plugins y temas de WordPress siempre es un poco chapucera. :/

¡El dispositivo add_shortcode
es del lado oscuro! Este código es bastante genial. +1 en el hecho de que WordPress necesita portar o deportar el $#ANTIOOP;. La depreciación necesita planes de migración de manera importante.

add_filter( 'get_my_plugin_instance', [ $this, 'get_instance' ] );
¿Cómo puedo pasar parámetros en 'get_instance'? ¿Como 'get_instance[params]'? Gracias.

@b_dubb Ah, espera, ahora entiendo tu pregunta. No pasas parámetros a eso en absoluto.

Puedes usarlo así, shortcode dentro de la Clase
class stockData{
function __construct() {
add_shortcode( 'your_shortcode_name', array( $this, 'showData' ) );
//add_action('login_enqueue_scripts', array( $this,'my_admin_head'));
}
function showData(){
return '<h1>Mi contenido del shortcode</h1>' ;
}
}
$object=new stockData();
Si deseas acceder al contenido del shortcode desde otra clase. Puedes hacerlo así.
class my_PluginClass {
public function __construct( $Object ) {
$test = add_shortcode( 'your_shortcode_name', array( $Object, 'your_method_name' ) );
}
}
class CustomHandlerClass{
public function your_method_name( $atts, $content ) {
return '<h1>Mi contenido del shortcode</h1>' ;
}
}
$Customobject = new CustomHandlerClass();
$Plugin = new my_PluginClass( $Customobject );

Asegúrate de crear una instancia de tu clase antes de usarla, a menos que estés seguro de que debe llamarse estáticamente. Cuando llamas a un método de forma estática, no utilizas ninguna instancia y, por lo tanto, no tiene acceso a ninguna variable o método miembro.
