, repo: https://github.com/alexkovalevv * @author Webcraftic , site: https://webcraftic.com * * @since 1.0.0 * @package factory-core */ class Wbcr_Factory480_Base { use WBCR\Factory_480\Options; /** * Обязательное свойство. Префикс, используется для создания пространство имен. * Чаще всего используется на именования опций в базе данных. Также может быть * использован для именования полей html форм, создания уникальных имен, хуков. * Пример: wrio_ * * Для префикса всегда используете нижнее подчеркивание справа! * * @var string */ protected $prefix; /** * Обязательное свойство. Заголовок плагина. Используете в интерфейсе плагина, * может быть использован в уведомлениях для администратора, чтобы пользователь * мог понять, с каким плагином он ведет коммуникацию. Пример: Robin image optimizer * * @var string */ protected $plugin_title; /** * Обязательное свойство. Имя плагина. Используется аналогично префиксу, но с небольшим * отличием. Имя плагина имеет человеку понятную строку, которую можно использовать в * именовании хуков, созданию условной логики. Допустимые символы [A-z0-9_]. * Пример: wbcr_clearfy * * @var string */ protected $plugin_name; protected $plugin_slug; /** * Обязательное свойство. Версия плагина в формате 0.0.0. Допустимые символы [0-9.] * * @var string */ protected $plugin_version; /** * Обязательное свойство. Текстовый домен плагина, используется для подключения файлов * переводов. Рекомендуется использовать slug плагина, идентичный slug в репозитории * Wordpress.org * * @since 4.1.1 * @var string */ protected $plugin_text_domain; /** * Обязательное свойство. Информация для поддержки клиента. Для начала работы плагина, * достаточно только указать адрес лендинга в атрибут url. На лендинге должны быть * созданы страницы features, pricing, support, docs. Если страницы (features, pricing, * support, docs) не могут иметь такие же адреса, вы можете наложить карту адресов в * атрибуте pages_map. К примеру: я создал страницу "Pro Features" и она имеет адрес * {site}/premium-features, для pages_map в атрибуте features, я указал, что адрес * страницы со списком функций имеет слаг premium-features. Теперь плагин будет понимать, * что адрес страницы со списком функций будет таким: * https://robin-image-optimizer.webcraftic.com/premium-features. * * Это свойство заполняется для того, чтобы в процессе разработки вы могли использовать * экземпляр класса \WBCR\Factory_480\Entities\Support, для получения информации о сайте плагина. * Тем самым вы избавляете себя от жесткого прописывания ссылок на лендинг плагина и * можете изменить все ссылки в одном месте. * * @var array */ protected $support_details; /** * Включение/отключение обновлений для бесплатного плагина. Если вашего плагина нет в репозитори * Wordpress.org, вы можете включить собственный режим обновлений, например через GitHub или * собственный репозиторий. Если установлено true, плагин будет проверять наличие обновлений * для этого плагина. * * @var bool */ protected $has_updates = false; /** * Настройка обновлений для бесплатного плагина. Если вы хотите настроить обновления для * бесплатного плагина через собственный репозиторий (например: github), вам нужно указать имя * репозитория и slug плагина. Slug может быть идентичен имени репозитория в github. Для Wordpress.org * эти настройки не обязательны, так как в wordpress ядре есть встроенные функции для обновлений * плагинов и тем. * * @var array */ protected $updates_settings = []; /** * Включение/отключение премиум версии для плагина. Если вы создаете бесплатный плагин и хотите * реализовать для него премиум версию, вам нужно начать с этого свойства. Если свойство установлено, * как true, при инициализации плагина будут подключены функции лицензирования, проверки обновлений * для премиум версии. * * @var bool */ protected $has_premium = false; /** * Настройки лицензирования * * Лицензирование плагина может быть реализовано для любого провайдера, * к примеру: freemius, codecanyon, templatemonster, вам нужно указать только настройки для * взаимодействия с выбранным вами провайдером. Каждая реализация провайдера лицензий может иметь * индивидуальный настройки, в этом примере приведены настройки для freemius провайдера * WBCR\Factory_480\Premium\Provider > WBCR\Factory_Freemius_000\Premium\Provider * * На текущий момент существует только реализация для freemius провайдера. * * Для премиум плагина вы должны также указать настройки обновлений. Атрибут has_updates * включает/отключает обновления для премиум плагина, в атрибуте updates_settings вы указываете * дополнительные настройки обновлений. * * @var array */ protected $license_settings = []; /** * Переключатель внутренней рекламы в плагине * * Если установить true, то плагин будет показывать рекламу компании в интерфейсе Wordpress. * Рекламный модуль может отображать рекламу внутри инрефейса плагина, на странице dashboard * и создавать сквозные уведомления на всех страницах админ панели Wordpress. * * @author Alexander Kovalev * @since 4.1.9 * @var bool */ protected $render_adverts = false; /** * Настройки внутренней рекламы компании * * @author Alexander Kovalev * @since 4.1.9 * @var array */ protected $adverts_settings = []; /** * Обязательное свойство. Подключаемые модули фреймворка. * * Модули фреймворка позволяют расширять его функциональность. * * @var array { * Array with information about the loadable module * {type} string $module [0] Relative path to the module directory * {type} string $module [1] Module name with prefix 000 * {type} string $module [2] Scope: * admin - Module will be loaded only in the admin panel, * public - Module will be loaded only on the frontend * all - Module will be loaded everywhere * } */ protected $load_factory_modules = [ ['libs/factory/bootstrap', 'factory_bootstrap_482', 'admin'], ['libs/factory/forms', 'factory_forms_480', 'admin'], ['libs/factory/pages', 'factory_pages_480', 'admin'], ]; /** * Не обязательное свойство. Список подключаемых компонентов плагина. * * Компоненты плагина, это независимые плагины, которые расширяют возможности текущего плагина. * Вы должны указать файл для автозагрузки компонента и префикс плагина, чтобы фреймворк * мог обращаться к классам и константам компонентов. * * * @author Alexander Kovalev * @since 4.2.0 Добавлен * @var array Пример данных * array( * 'component_ID' => array( * 'autoload' => 'relative_path/autoload_filename.php', * 'plugin_prefix' => 'WPRFX_' * ), * // Реальный пример * 'cyrlitera' => array( * 'autoload' => 'components/cyrlitera/clearfy.php', * 'plugin_prefix' => 'WCTR_' * ), * ) */ protected $load_plugin_components = []; /** * Экземпляр класса \WBCR\Factory_480\Entities\Support используется для получения информации * о сайте плагина. Чаще всего используется для получения ссылки на страницу с тарифами или * ссылки на форму обратной связи. Встроен механизм отслеживания по utm меткам. * * @var \WBCR\Factory_480\Entities\Support */ protected $support; /** * Экземпляр класса \WBCR\Factory_480\Entities\Paths используется для получения информации о * путях плагина. Часто используется для получения путей или ссылок на место хранения плагина * или его входного файла. * * @var \WBCR\Factory_480\Entities\Paths */ protected $paths; /** * Абсолютный путь к входному файлу плагина: C://server/site.dev/wp-content/plugins/plugin_name/plugin_name.php * * @var string */ private $plugin_file; /** * Свойство хранит сырые настройки плагина, а также дополнительные настройки, которые не описаны * в интерфейсе класса. * * @var array */ private $plugin_data; /** * Конструктор: * - Заполняет свойства класса из сырых данных плагина * - Выполняет проверку на обязательные настройки * - Инициализирует сущности support и paths * * @param string $plugin_file * @param array $data * * @throws Exception * @since 4.0.8 - добавлена дополнительная логика * * @since 4.1.1 - добавил две сущности support, paths. Удалил свойства, plugin_build * plugin_assembly, main_file, plugin_root, relative_path, plugin_url */ public function __construct($plugin_file, $data) { $this->plugin_file = $plugin_file; $this->plugin_data = $data; foreach((array)$data as $option_name => $option_value) { if( property_exists($this, $option_name) ) { $this->$option_name = $option_value; } } if( empty($this->prefix) || empty($this->plugin_name) || empty($this->plugin_title) || empty($this->plugin_version) || empty($this->plugin_text_domain) ) { throw new Exception('One of the required attributes has not been passed (prefix, plugin_title, plugin_name, plugin_version, plugin_text_domain).'); } $this->support = new \WBCR\Factory_480\Entities\Support($this->support_details); $this->paths = new \WBCR\Factory_480\Entities\Paths($plugin_file); // used only in the module 'updates' $this->plugin_slug = !empty($this->plugin_name) ? $this->plugin_name : basename($plugin_file); } /** * При обновлении фреймворка, некоторые свойства класса были удалены. Однако плагины на старом * фреймворке по прежнему используют удаленные свойства. С помощью этого магического метода мы * добавляем совместимость со старыми плагинами, но при этом выводим предупреждение, что нужно * обновить некоторые свойства. * * @param string $name Имя свойства класса. * * @return mixed */ public function __get($name) { $deprecated_props = [ 'plugin_build', 'plugin_assembly', 'main_file', 'plugin_root', 'relative_path', 'plugin_url' ]; if( in_array($name, $deprecated_props) ) { $deprecated_message = 'In version 4.1.1 of the Factory framework, the class properties '; $deprecated_message .= '(' . implode(',', $deprecated_props) . ')'; $deprecated_message .= 'have been removed. To get plugin paths, use the new paths property.' . PHP_EOL; $backtrace = debug_backtrace(); if( !empty($backtrace) && isset($backtrace[1]) ) { $deprecated_message .= 'BACKTRACE:('; $deprecated_message .= 'File: ' . $backtrace[1]['file']; $deprecated_message .= 'Function: ' . $backtrace[1]['function']; $deprecated_message .= 'Line: ' . $backtrace[1]['line']; $deprecated_message .= ')'; } _deprecated_argument(__METHOD__, '4.1.1', $deprecated_message); switch( $name ) { case 'plugin_build': return null; break; case 'plugin_assembly': return null; break; case 'main_file': return $this->get_paths()->main_file; break; case 'plugin_root': return $this->get_paths()->absolute; break; case 'relative_path': return $this->get_paths()->basename; break; case 'plugin_url': return $this->get_paths()->url; break; } } return null; } /** * При обновлении фреймворка, некоторые методы класса были удалены. Однако плагины на старом фреймворке * по прежнему используют удаленные методы. С помощью этого магического метода мы добавляем совместимость * со старыми плагинами, но при этом выводим предупреждение, что нужно обновить некоторые методы. * * @param string $name Имя метода класса. * @param array $arguments Массив аргументов метода класса. * * @return stdClass|null * @throws Exception */ public function __call($name, $arguments) { $deprecated_methods = [ 'getPluginBuild', 'getPluginAssembly', 'getPluginPathInfo' ]; if( in_array($name, $deprecated_methods) ) { $deprecated_message = 'In version 4.1.1 of the Factory framework, methods (' . implode(',', $deprecated_methods) . ') have been removed.'; $backtrace = debug_backtrace(); if( !empty($backtrace) && isset($backtrace[1]) ) { $deprecated_message .= 'BACKTRACE:('; $deprecated_message .= 'File: ' . $backtrace[1]['file']; $deprecated_message .= 'Function: ' . $backtrace[1]['function']; $deprecated_message .= 'Line: ' . $backtrace[1]['line']; $deprecated_message .= ')'; } _deprecated_argument(__METHOD__, '4.1.1', $deprecated_message); if( 'getPluginPathInfo' == $name ) { $object = new stdClass; $object->main_file = $this->get_paths()->main_file; $object->plugin_root = $this->get_paths()->absolute; $object->relative_path = $this->get_paths()->basename; $object->plugin_url = $this->get_paths()->url; return $object; } } throw new Exception("Method {$name} does not exist"); } /** * Проверяет, включен ли премиум для этого плагина или нет. * * @return bool Возвращает true, если премиум пакет включен для этого плагина. * См. Wbcr_Factory480_Base::has_premium */ public function has_premium() { return $this->has_premium; } /** * Позволяет получить заголовок плагина. * * @return string Возвращает заголовок плагина. См. Wbcr_Factory480_Base::plugin_title */ public function getPluginTitle() { return apply_filters('wbcr/factory/plugin_title', $this->plugin_title, $this->getPluginName()); } /** * Позволяет получить префикс плагина. * * @return string Возвращает префикс плагина.См. Wbcr_Factory480_Base::prefix */ public function getPrefix() { return $this->prefix; } /** * Позволяет получить имя плагина. * * @return string Возвращает имя плагина. См. Wbcr_Factory480_Base::plugin_name */ public function getPluginName() { return $this->plugin_name; } /** * Позволяет получить версию плагина. * * @return string Возвращает версию плагина. См. Wbcr_Factory480_Base::plugin_version */ public function getPluginVersion() { return $this->plugin_version; } /** * Позволяет получить список подключаемых к плагином компонентов * * @return array * @since 4.2.0 * @author Alexander Kovalev */ public function get_load_plugin_components() { return $this->load_plugin_components; } /** * Предоставляет доступ к сырым данным плагина. Может быть полезен, если вы хотите получить * какие-то данные не описанные в интерфейсе этого плагина. * * @param string $attr_name Имя атрибута, который нужно получить. Идентично ключу в массиве * Wbcr_Factory480_Base::plugin_data * * @return null */ public function getPluginInfoAttr($attr_name) { if( isset($this->plugin_data[$attr_name]) ) { return $this->plugin_data[$attr_name]; } return null; } /** * Предоставляет доступ к экземпляру класса \WBCR\Factory_480\Entities\Support. * * @return \WBCR\Factory_480\Entities\Support */ public function get_support() { return $this->support; } /** * Предоставляет доступ к экземпляру класса \WBCR\Factory_480\Entities\Paths. * * @return \WBCR\Factory_480\Entities\Paths */ public function get_paths() { return $this->paths; } /** * Позволяет получить сырые данные плагина в виде объекта StdClass. * * @return object Возвращает объект с сырыми данными плагина. См. Wbcr_Factory480_Base::plugin_data */ public function getPluginInfo() { return (object)$this->plugin_data; } /** * Проверяет права пользователя * * @return bool * @since 4.2.0 Добавлен * @author Alexander Kovalev */ public function current_user_can($capability = 'manage_options') { // Просмотр страниц: read_pages // Просмотр уведомлений: read_notices // Редактирование: edit_forms if( 'manage_options' == $capability && is_multisite() && $this->isNetworkActive() ) { $capability = 'manage_network'; } return current_user_can($capability); } /** * Проверят, находится ли пользователь в панели усправления сетью сайтов * * @return bool * @since 4.0.8 Добавлен * */ public function isNetworkAdmin() { return is_multisite() && is_network_admin(); } /** * Проверяет активирован ли плагин для сети. Если проект работает в режиме мультисайтов.. * * @return bool Если true, плагин активирован для сети или в текущий момент активируется для сети. * @since 4.0.8 Добавлен */ public function isNetworkActive() { // Makes sure the plugin is defined before trying to use it if( !function_exists('is_plugin_active_for_network') ) { require_once(ABSPATH . '/wp-admin/includes/plugin.php'); } $activate = is_plugin_active_for_network($this->get_paths()->basename); if( !$activate && $this->isNetworkAdmin() && isset($_GET['action']) && $_GET['action'] == 'activate' ) { return isset($_GET['networkwide']) && 1 == (int)$_GET['networkwide']; } return $activate; } /** * Позволяет получить все активные сайты сети. Если проект работает в режиме мультисайтов. * * @return array|int * @since 4.0.8 */ public function getActiveSites($args = ['archived' => 0, 'mature' => 0, 'spam' => 0, 'deleted' => 0]) { global $wp_version; if( version_compare($wp_version, '4.6', '>=') ) { return get_sites($args); } else { $converted_array = []; $sites = wp_get_sites($args); if( empty($sites) ) { return $converted_array; } foreach((array)$sites as $key => $site) { $obj = new stdClass(); foreach($site as $attr => $value) { $obj->$attr = $value; } $converted_array[$key] = $obj; } return $converted_array; } } }