Ошибка PHP с обработчиком шорткода из класса
В настоящее время я использую следующий общий подход для добавления шорткода для плагина.
class MyPlugin {
private $myvar;
function baztag_func() {
print $this->myvar;
}
}
add_shortcode( 'baztag', array('MyPlugin', 'baztag_func') );
Теперь, когда вызывается этот класс и его метод, я получаю следующую ошибку.
Fatal error: Using $this when not in object context in ...
(Номер строки там, где я вывожу $this->myvar
)
Это проблема на стороне WordPress или я делаю что-то неправильно? Похоже, что это что-то очень простое.

Как указано в ошибке, для использования $this
необходим экземпляр класса. Есть как минимум три варианта решения:
Сделать всё статическим
class My_Plugin
{
private static $var = 'foo';
static function foo()
{
return self::$var; // никогда не используйте echo или print в шорткоде!
}
}
add_shortcode( 'baztag', array( 'My_Plugin', 'foo' ) );
Но это уже не настоящий ООП, а просто пространство имён.
Создать реальный объект сначала
class My_Plugin
{
private $var = 'foo';
public function foo()
{
return $this->var; // никогда не используйте echo или print в шорткоде!
}
}
$My_Plugin = new My_Plugin;
add_shortcode( 'baztag', array( $My_Plugin, 'foo' ) );
Это... работает. Но вы столкнётесь с неочевидными проблемами, если кто-то захочет заменить шорткод.
Поэтому добавьте метод для предоставления экземпляра класса:
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; // возвращаем объект
}
public function foo()
{
return $this->var; // никогда не используйте echo или print в шорткоде!
}
}
add_shortcode( 'baztag', [ new My_Plugin, 'foo' ] );
Теперь, если кому-то нужно получить экземпляр объекта, достаточно написать:
$shortcode_handler = apply_filters( 'get_my_plugin_instance', NULL );
if ( is_a( $shortcode_handler, 'My_Plugin ' ) )
{
// делаем что-то с этим экземпляром
}
Старое решение: создать объект внутри класса
class My_Plugin
{
private $var = 'foo';
protected static $instance = NULL;
public static function get_instance()
{
// создаём объект
NULL === self::$instance and self::$instance = new self;
return self::$instance; // возвращаем объект
}
public function foo()
{
return $this->var; // никогда не используйте echo или print в шорткоде!
}
}
add_shortcode( 'baztag', array( My_Plugin::get_instance(), 'foo' ) );

спасибо, чувак ... это бесценная информация, так как на wordpress.org в документации к add_shortcode об этом не сказано так много. Я уже нашел решение, но раз ты указал, что это плохая практика, и у тебя есть лучшее решение, я помечаю проблему как решенную :)

Очень извиняюсь, что поднимаю этот старый вопрос, но не мог бы ты подробнее объяснить, что делает эта строка: NULL === self::$instance and self::$instance = new self;
? Я немного запутался, потому что здесь используются ===
и and
, но без if
, если ты понимаешь, о чем я.

@Sven Это проверка, чтобы предотвратить создание второго экземпляра. Она делает этот класс синглтоном... Сейчас я бы так не делал. Я перепишу этот ответ.

Спасибо за это! Думаю, сейчас я на правильном пути, хотя поражает, насколько сложным может быть использование WordPress и ООП ;-)

@Sven Ядро WordPress написано практически максимально анти-ООП образом. Даже новый код игнорирует все, что остальной PHP-мир узнал за последние десять лет, например, dependency injection. Так что да, ООП в плагинах и темах WordPress всегда выглядит костыльно. :/

add_shortcode
— это инструмент из тёмной стороны! Этот код просто огонь. +1 к тому, что WordPress нужно портировать или депортировать $#ANTIOOP;. Для устаревания функционала нужны серьёзные планы миграции.

add_filter( 'get_my_plugin_instance', [ $this, 'get_instance' ] );
Как передать параметры в 'get_instance'? В виде 'get_instance[params]'? Спасибо.

@b_dubb О, подождите, теперь я понял ваш вопрос. Вы вообще не передаете параметры туда.

Можно использовать вот так, шорткод внутри класса
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>Содержимое шорткода</h1>' ;
}
}
$object=new stockData();
Если нужно получить доступ к содержимому шорткода из другого класса. Можно сделать так:
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>Содержимое шорткода</h1>' ;
}
}
$Customobject = new CustomHandlerClass();
$Plugin = new my_PluginClass( $Customobject );

Убедитесь, что вы создаете экземпляр вашего класса перед его использованием, если только вы не уверены, что метод должен вызываться статически. При статическом вызове метода вы не используете экземпляры, поэтому у метода нет доступа к переменным или методам класса.
