Как сделать плагин обязательным для темы WordPress без использования условных операторов PHP при вызове отдельных функций?

19 янв. 2012 г., 08:45:28
Просмотры: 19.8K
Голосов: 14

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

Обычно я вызывал функции сторонних плагинов, используя условные операторы, например:

    if(function_exist('plugin_function')) {
             plugin_function() // выполнить что-то
    }

Предположим, мне нужно интенсивно использовать один плагин во многих файлах моей темы... Я хотел бы избежать использования множества условий IF... Есть ли правильный способ сделать определенный плагин обязательным для установки в WordPress или, что еще лучше, установить его автоматически, если он отсутствует, перед активацией темы?

Спасибо

0
Все ответы на вопрос 4
7

is_plugin_active() довольно ненадежна: она перестанет работать, если автор плагина переименует основной файл или если пользователь переименует директорию плагина или его основной файл. Лучше проверять, существует ли определенная публичная функция.

Чтобы избежать необходимости делать эту проверку каждый раз, когда вам нужна функциональность плагина, вы можете показывать сообщение в админ-панели:

add_action( 'admin_notices', 'my_theme_dependencies' );

function my_theme_dependencies() {
  if( ! function_exists('plugin_function') )
    echo '<div class="error"><p>' . __( 'Внимание: Для работы темы необходим плагин X', 'my-theme' ) . '</p></div>';
}

Другой вариант - использовать что-то вроде http://tgmpluginactivation.com/

19 янв. 2012 г. 13:31:01
Комментарии

Если автор плагина изменит имя функции, которую вы проверяете с помощью function_exists, то обычный пользователь просто получит сообщение о том, что у него не установлен плагин, от которого зависит другой плагин. Проблема в том, что пользователь на самом деле будет иметь этот плагин установленным и просто не поймёт, почему он не работает. О, и я не собираюсь ставить вам минус за это.

kaiser kaiser
19 янв. 2012 г. 14:27:21

Если вам важны голоса, то вам стоит поставить плюс самому вопросу, так как он хороший.

kaiser kaiser
19 янв. 2012 г. 14:32:42

Если автор плагина изменит имя функции, он получит жалобы от гораздо большего числа пользователей, чем если бы он изменил имя файла.

scribu scribu
19 янв. 2012 г. 15:47:15

Я поставил вашему ответу минус, потому что, на мой взгляд, он не отвечает на вопрос. Или вы предпочли бы, чтобы я минусовал скрытно, без объяснения причин?

scribu scribu
19 янв. 2012 г. 15:50:20

Я говорил именно о минусе, а не о комментарии. Сам комментарий вполне уместен, так как эта тема требует обсуждения. Я добавлю ещё один ответ, так как мои мысли по этому поводу выходят за рамки длины комментария. Пожалуйста, просто отредактируйте ответ, чтобы мы могли сохранить результаты обсуждения в истории правок для всех. Спасибо.

kaiser kaiser
19 янв. 2012 г. 16:28:29

Думаю, вопрос в том, уместно ли ставить минус ответу и затем публиковать свой собственный. Хотя это тема для обсуждения на Meta.

scribu scribu
19 янв. 2012 г. 16:51:36

Мне всё равно. Просто было интересно. Единственное, что меня действительно интересует — это ваше мнение по теме. Смотрите новый ответ и, пожалуйста, прочитайте комментарий вверху (и оставьте его для других).

kaiser kaiser
19 янв. 2012 г. 16:59:45
Показать остальные 2 комментариев
1

Хотя это не предотвратит поломку темы при отключении плагина, я бы рекомендовал ознакомиться с этой полезной статьей о "Как отображать уведомление в админке для обязательных тем". Мне никогда не нравилась идея, когда тема принудительно требует установки плагина, поэтому этот вариант кажется следующим лучшим решением.

Еще одна быстрая мысль: я никогда не пробовал этого, но интересно, можно ли придумать хитрый способ разместить несколько хуков в одном условии. Возможно, можно вынести все условные функции в отдельный файл и подключать его только если if( function_exists( 'plugin_function' ) ) возвращает true (с пониманием, что это не идеальная проверка).

11 мая 2012 г. 19:38:22
Комментарии

Ссылка не работает...

Alex Alex
21 сент. 2021 г. 14:07:19
1

Если вам нужно проверить активность плагина только на странице плагина, используйте функцию is_plugin_active(). Если проверка требуется за пределами админки, лучше скопировать/вставить основную функцию в вашу тему и затем использовать её:

if ( ! is_admin() )
{
/**
 * Проверяет, активен ли плагин, проверяя список active_plugins.
 *
 * @since 2.5.0
 *
 * @param string $plugin Базовый путь к плагину из директории plugins.
 * @return bool True, если плагин в списке активных. False, если нет.
 */
function is_plugin_active( $plugin ) {
    return in_array( $plugin, (array) get_option( 'active_plugins', array() ) ) || is_plugin_active_for_network( $plugin );
}
}

Условное выражение предотвращает ошибки с двойным определением функции.

19 янв. 2012 г. 09:16:48
Комментарии

Это не совсем отвечает на вопрос. Это просто заменяет if(function_exist('plugin_function')) на if(is_plugin_active('plugin-file.php'))

scribu scribu
19 янв. 2012 г. 13:32:30
3

Примечание: Этот ответ здесь только для облегчения обсуждения между @scribu и @kaiser. Модераторы: Пожалуйста, не удаляйте. Пользователи/читатели: Пожалуйста, не голосуйте. Если вы хотите следить за обсуждением, посмотрите историю правок. Если хотите присоединиться к обсуждению, отредактируйте ответ. Если обсуждение приведёт к результату, он будет отмечен соответствующим образом. Спасибо.


Сценарии

Существуют также различные сценарии, которые имеют разный вес, когда у вас может быть зависимость плагина. (Примеры вымышленные). Слово "(родительский) Плагин" можно заменить на "Тема" с точки зрения родителя.

  1. (жёсткая) Дочерний плагин, который только расширяет функциональность или изменяет отображение (и подобное) существующего плагина и поэтому не может существовать без родителя. Пример: BuddyPress » BuddyPress-FunkyCommentDisplay
  2. (обычная) Плагин, который имеет расширенную функциональность при активации дочернего плагина. Пример: jQueryAttachmentCarousel » jQuerySlideDeck
  3. (мягкая) Плагин, который просто добавляет функцию. Пример: DisneyWonderlandTheme » MickeysSocialLinks

Далее я попытаюсь набросать, что происходит, когда вы обновляете "другой" плагин, и проверка перестаёт работать.

  • Пункт 1) Плагин не может существовать без активированного BuddyPress » Всё полностью ломается.
  • Пункт 2) Плагин не может предложить опцию переключения с Carousel на SlideDeck » Отображается странно (предполагаю, что стили изменены под SlideDeck).
  • Пункт 3) MickeysSocialLinks исчезают.

Проверка

На мой взгляд, есть три возможности проверить, активен ли плагин:

  • A. Существует ли папка?
  • B. Существует ли основной файл — опция 'active_plugins'?
  • C. Существует ли конкретная функция?

Если я возьму в качестве примера мой Плагин проверки внутренних ссылок, который не предлагает публичного API и не предназначен для расширения, то я не вижу причин (как автор) не изменять названия внутренних функций по желанию или просто так. Так что если кто-то попытается прицепиться к этому плагину, то всё просто сломается (в зависимости от функциональности и тесноты связывания) при обновлении. То же самое касается имён файлов. У меня не было бы реальной причины (кроме того, что плагин будет деактивирован при обновлении) не изменять имя файла. Единственное, что удержало бы меня от изменения имени папки, — это то, что проверка обновлений и уведомления работают против имени файла — если он размещён в официальном репозитории.

Так что я бы сказал, от самого слабого (легко изменить) до самого крепкого (многое говорит против изменения) компонента (родительского) плагина:

функция » имя основного файла » папка


Когда я сказал, что проверка функции менее хрупка, чем использование is_plugin_active(), я предполагал, что функция в вопросе — это та, которую автор плагина явно поощряет. Идеальным примером этого был бы теговый шаблон wp_pagenavi(), предлагаемый плагином WP-PageNavi.

Сложность в определении зависимостей заключается в том, что нет стандартного способа однозначно идентифицировать плагины, который не включал бы имена файлов.

Дополнительные размышления по теме:

http://wordpress.org/support/topic/plugin-plugin-dependencies-unreliable-plugin-namingidentifying-scheme


Полагаю, мы можем пока суммировать это в трёх пунктах:

  • Мы говорили о несколько разных темах
  • Мы согласны, что нет пуленепробиваемого способа обойти то, что я считал темой
  • С вашего понимания вопроса, вы предложили один верный способ

Самый (пока) умный способ, который я могу придумать, и который уже видел в некоторых (слишком мало) плагинах:

// внутри файла плагина:
add_action( 'plugin_custom_hook', 'plugin_trigger' );
// внутри какого-нибудь шаблона:
do_action( 'plugin_custom_hook' );

Не вдаваясь слишком в детали, но, думаю, вы могли бы подключить ваше уведомление к проверке на фильтре 'all' и проверить внутри текущего фильтра, был ли он вызван, когда вы находитесь на хуке shutdown...?


Использование хуков хорошо работало бы для 'обычных' и 'слабых' зависимостей. Единственный недостаток в том, что вам всё равно нужно использовать function_exists() или is_plugin_active(), если вы хотите остановиться, если зависимость не выполнена. Использование фильтра 'all' для этого было бы слишком затратным, ИМХО.

@scibu Это было направлено на "вашу" тему. (Я уже перестал говорить о своей). :)

Так что, в основном, если вам нужна зависимость — и у вас хороший автор — то он мог бы предложить хук вместо/в дополнение к теговому шаблону. Потому что плагин будет подключаться к нему, только если хук будет присутствовать, или просто ничего не делать. А с другой стороны, у вас не будет ошибки, когда плагин отсутствует.

Вот сложная часть (или скорее вопрос): Чтобы написать уведомление в админке, чтобы проинформировать пользователя о зависимости "Вам нужно установить »DisneyWonderLinks«", вы могли бы проверить array_keys( $GLOBALS['wp_filter']['template_tag_like_hook'] ). Я не уверен, сработает ли это, но насколько я знаю, массив должен быть доступен с обеих (публичной/админской) сторон.


Это не сработает. Только потому, что колбэк зарегистрирован на хук, не означает, что хук будет вызван, когда ожидается. Единственное, что могло бы работать вроде как, — это использование хука 'shutdown', который вы упомянули ранее:

add_action( 'shutdown', function() {
  if ( !did_action( 'template_tag_like_hook' ) )
    echo 'Проблема.';
} );

Конечно, это будет выведено в самом низу, после тега </html>, на фронтенде (поскольку там обычно используются теговые шаблоны), что не очень полезно.

Вы могли бы попытаться сохранить сообщение в wp_options и затем отобразить его в админке, но это открыло бы целую новую банку червей: инвалидация, плагины кеширования и т.д.

19 янв. 2012 г. 16:58:29
Комментарии

Для справки, это довольно нестандартный способ использования функционала сайта. Напоминает мне http://c2.com/cgi/wiki

scribu scribu
19 янв. 2012 г. 17:23:50

Да, это так. Но я не представлял, как мы могли бы продолжить обсуждение, не скрывая его от будущих читателей.

kaiser kaiser
19 янв. 2012 г. 18:27:40

Я не ожидал, что публикация вопроса вызовет столь активное обсуждение :) Но это действительно интересно, и я благодарю вас обоих за усилия и время, потраченные на советы и содержательную дискуссию. Думаю, совет scribu (один из многих) использовать класс TGM Activation может предложить решение моего вопроса хотя бы с чисто практической точки зрения, я изучу этот вариант. Тем не менее, я продолжаю следить за всей дискуссией, потому что другие предложенные методы также имеют смысл в определенных сценариях, и мне очень интересно читать об этом, спасибо!

unfulvio unfulvio
20 янв. 2012 г. 19:43:24