Ошибка PHP с обработчиком шорткода из класса

10 авг. 2012 г., 10:28:39
Просмотры: 19.9K
Голосов: 16

В настоящее время я использую следующий общий подход для добавления шорткода для плагина.

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 или я делаю что-то неправильно? Похоже, что это что-то очень простое.

1
Комментарии

не по теме - сделайте функцию static.

kaiser kaiser
27 сент. 2012 г. 18:21:02
Все ответы на вопрос 3
11
37

Как указано в ошибке, для использования $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' ) );
10 авг. 2012 г. 10:45:10
Комментарии

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

xmaestro xmaestro
10 авг. 2012 г. 10:49:59

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

Sven Sven
3 янв. 2015 г. 14:17:03

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

fuxia fuxia
3 янв. 2015 г. 14:18:47

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

Sven Sven
3 янв. 2015 г. 14:38:57

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

fuxia fuxia
3 янв. 2015 г. 14:42:33

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

Nathan Powell Nathan Powell
17 февр. 2016 г. 07:57:59

add_filter( 'get_my_plugin_instance', [ $this, 'get_instance' ] );

Как передать параметры в 'get_instance'? В виде 'get_instance[params]'? Спасибо.

b_dubb b_dubb
10 дек. 2018 г. 20:33:57

@b_dubb Параметры передаются в конструктор.

fuxia fuxia
10 дек. 2018 г. 20:35:33

@fuxia и как это будет выглядеть...?

b_dubb b_dubb
12 дек. 2018 г. 18:18:25

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

fuxia fuxia
12 дек. 2018 г. 18:35:10

add_shortcode( 'baztag', [ new My_Plugin($params), 'foo' ] );

b_dubb b_dubb
28 дек. 2018 г. 06:46:42
Показать остальные 6 комментариев
1
10

Можно использовать вот так, шорткод внутри класса

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 );
25 июн. 2015 г. 10:57:51
Комментарии

Мне очень нравится это решение. Оно действительно чистое и понятное. Сторона во мне, как разработчика React.js, довольна этим.

AaronDancer AaronDancer
13 апр. 2017 г. 22:44:03
0

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

10 авг. 2012 г. 10:46:20