diff --git a/CHANGELOG.md b/CHANGELOG.md index b99460cb1559a8dd6c0c506a2ba2fc55e3ef1b82..f0cdf93136256ae5555dda08b5ac29656d79ed74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## [3.0.0] - 2019-09-17 +### Changed +- Plugin classes moved to wp-builder +### Added +- Factory can create checker from requirement array +- Support for update suggestion when required plugin not found +- WPDesk_Basic_Requirement_Checker_With_Update_Disable can temporarily say that requirements are not met when required plugin is in the process of being updated +- Translations + ## [2.4.0] - 2019-06-04 ### Added - Plugin name in plugin info diff --git a/composer.json b/composer.json index 0f7b8c9029c31b5f3ec89d7a21373b8e113a2730..b025d7f2fce6f6552a845762208dce3c8275f06d 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ } ], "require": { - "php": ">=5.2" + "php": ">=5.3" }, "require-dev": { "php": ">=5.5", diff --git a/lang/wp-basic-requirements-pl_PL.mo b/lang/wp-basic-requirements-pl_PL.mo new file mode 100644 index 0000000000000000000000000000000000000000..1be5028dc9cb2e5a10787862f5a381c950c230a7 Binary files /dev/null and b/lang/wp-basic-requirements-pl_PL.mo differ diff --git a/lang/wp-basic-requirements-pl_PL.po b/lang/wp-basic-requirements-pl_PL.po new file mode 100644 index 0000000000000000000000000000000000000000..b621343cd841f8083a7cb9c9853759db9d0cfb9e --- /dev/null +++ b/lang/wp-basic-requirements-pl_PL.po @@ -0,0 +1,132 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2019-09-18 15:50+0200\n" +"PO-Revision-Date: 2019-09-18 15:59+0200\n" +"Last-Translator: Krzysztof Dyszczyk <krzysztof.dyszczyk@gmail.com>\n" +"Language-Team: \n" +"Language: pl_PL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.3\n" +"X-Poedit-Basepath: ../src\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" +"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;" +"\"\n" +"X-Poedit-SearchPath-0: .\n" + +#: Basic_Requirement_Checker.php:187 +#, php-format +msgid "" +"The “%s” plugin cannot run on PHP versions older than %s. Please " +"contact your host and ask them to upgrade." +msgstr "" +"Wtyczka “%s” nie może działać w wersjach PHP starszych niż %s. " +"Skontaktuj się z administratorem hostingu i poproś o aktualizację." + +#: Basic_Requirement_Checker.php:191 +#, php-format +msgid "" +"The “%s” plugin cannot run on WordPress versions older than %s. " +"Please update WordPress." +msgstr "" +"Wtyczka “%s” nie może działać w wersjach WordPress starszych niż " +"%s. Prosimy o aktualizację WordPress." + +#: Basic_Requirement_Checker.php:195 +#, php-format +msgid "" +"The “%s” plugin cannot run on WooCommerce versions older than " +"%s. Please update WooCommerce." +msgstr "" +"Wtyczka “%s” nie może działać w wersjach WooCommerce starszych " +"niż %s. Prosimy o aktualizację WooCommerce." + +#: Basic_Requirement_Checker.php:199 +#, php-format +msgid "" +"The “%s” plugin cannot run without OpenSSL module version at " +"least %s. Please update OpenSSL module." +msgstr "" +"Wtyczka “%s” nie może działać bez aktywacji OpenSSL co najmniej " +"w wersji %s. Zaktualizuj wersję OpenSSL." + +#: Basic_Requirement_Checker.php:290 +#, php-format +msgid "" +"The “%s” plugin cannot run without %s active. Please install and " +"activate %s plugin." +msgstr "" +"Wtyczka “%s” nie może działać bez aktywacji %s. Zainstaluj i " +"aktywuj wtyczkę %s." + +#: Basic_Requirement_Checker.php:349 +#, php-format +msgid "" +"The “%s” plugin requires free %s plugin. <a href=\"%s\">Install " +"%s →</a>" +msgstr "" +"Wtyczka “%s” wymaga bezpłatnej wtyczki %s. <a href=\"%s" +"\">Zainstaluj %s →</a>" + +#: Basic_Requirement_Checker.php:357 +#, php-format +msgid "" +"The “%s” plugin requires activating %s plugin. <a href=\"%s" +"\">Activate %s →</a>" +msgstr "" +"Wtyczka “%s” wymaga aktywnej wtyczki %s. <a href=“%s”>Aktywuj %s " +"→</a>" + +#: Basic_Requirement_Checker.php:403 +#, php-format +msgid "" +"The “%s” plugin cannot run without %s php module installed. " +"Please contact your host and ask them to install %s." +msgstr "" +"Wtyczka “%s” nie może działać bez modułu php: %s. Skontaktuj się " +"z administratorem hostingu i poproś o instalację %s." + +#: Basic_Requirement_Checker.php:431 +#, php-format +msgid "" +"The “%s” plugin cannot run without %s php setting set to %s. " +"Please contact your host and ask them to set %s." +msgstr "" +"Wtyczka “%s” nie może działać bez ustawienia php %s ustawionego " +"na %s. Skontaktuj się z administratorem hostingu i poproś o ustawienie %s." + +#: Basic_Requirement_Checker_With_Update_Disable.php:27 +#, php-format +msgid "" +"The “%s” plugin disables temporarily as required %s plugin is " +"being upgraded." +msgstr "" +"Wtyczka “%s” jest chwilowo nieaktywna, ponieważ wymagana wtyczka " +"%s jest właśnie aktualizowana." + +#~ msgid "" +#~ "The “%s” plugin cannot start as there is a dependency " +#~ "conflict with other existing plugin “%s”. Please upgrade all " +#~ "plugins to the most recent version or disable the “%s” plugin." +#~ msgstr "" +#~ "Wtyczka “%s” nie może zostać uruchomiona, ponieważ powstał " +#~ "konflikt zależności z już uruchomioną wtyczką “%s”. Proszę " +#~ "zaktualizuj wtyczki do najnowszych wersji lub dezaktywuj wtyczkę “" +#~ "%s”." + +#~ msgid "" +#~ "The “%s” plugin cannot start as there is a dependency " +#~ "conflict with other existing plugin “%s”. The required " +#~ "version of dependency %s is %s and the version used by plugin “" +#~ "%s” is %s. Please upgrade all plugins to the most recent version or " +#~ "disable the “%s” plugin." +#~ msgstr "" +#~ "Plugin “%s” nie może zostać uruchomiony, ponieważ powstał " +#~ "konflikt zależności z już uruchomionem pluginem “%s”. " +#~ "Wymagana wersja zależności %s to %s, a wersja używana przez plugin “" +#~ "%s” to %s. Proszę zaktualizuj pluginy do najnowszej wersji lub " +#~ "deaktywuj plugin “%s”." diff --git a/src/Basic_Requirement_Checker.php b/src/Basic_Requirement_Checker.php index fe8638a80b69b785ab9fbe19cb26e270767a40c2..f68f7dae761b919f0abde94dffc1a8ba129118fc 100644 --- a/src/Basic_Requirement_Checker.php +++ b/src/Basic_Requirement_Checker.php @@ -1,403 +1,503 @@ <?php -if ( ! interface_exists( 'WPDesk_Translatable' ) ) { - require_once 'Translatable.php'; -} - if ( ! interface_exists( 'WPDesk_Requirement_Checker' ) ) { require_once 'Requirement_Checker.php'; } -if (! class_exists('WPDesk_Basic_Requirement_Checker') ) { - /** - * Checks requirements for plugin - * have to be compatible with PHP 5.2.x - */ - class WPDesk_Basic_Requirement_Checker implements WPDesk_Translatable, WPDesk_Requirement_Checker - { - const EXTENSION_NAME_OPENSSL = 'openssl'; - const HOOK_ADMIN_NOTICES_ACTION = 'admin_notices'; - - /** @var string */ - private $plugin_name; - /** @var string */ - private $plugin_file; - /** @var string */ - private $min_php_version; - /** @var string */ - private $min_wp_version; - /** @var string|null */ - private $min_wc_version = null; - /** @var int|null */ - private $min_openssl_version = null; - /** @var array */ - private $plugin_require; - /** @var array */ - private $module_require; - /** @var array */ - private $setting_require; - /** @var array */ - private $notices; - /** @var @string */ - private $text_domain; - - /** - * @param string $plugin_file - * @param string $plugin_name - * @param string $text_domain - * @param string $php_version - * @param string $wp_version - */ - public function __construct( $plugin_file, $plugin_name, $text_domain, $php_version, $wp_version ) { - $this->plugin_file = $plugin_file; - $this->plugin_name = $plugin_name; - $this->text_domain = $text_domain; - - $this->set_min_php_require( $php_version ); - $this->set_min_wp_require( $wp_version ); - - $this->plugin_require = array(); - $this->module_require = array(); - $this->setting_require = array(); - $this->notices = array(); - } - - /** - * @param string $version - * - * @return $this - */ - public function set_min_php_require( $version ) { - $this->min_php_version = $version; - - return $this; - } - - /** - * @param string $version - * - * @return $this - */ - public function set_min_wp_require( $version ) { - $this->min_wp_version = $version; - - return $this; - } - - /** - * @param string $version - * - * @return $this - */ - public function set_min_wc_require( $version ) { - $this->min_wc_version = $version; - - return $this; - } - - /** - * @param $version - * - * @return $this - */ - public function set_min_openssl_require( $version ) { - $this->min_openssl_version = $version; - - return $this; - } - - /** - * @param string $plugin_name - * @param string $nice_plugin_name Nice plugin name for better looks in notice - * - * @return $this - */ - public function add_plugin_require( $plugin_name, $nice_plugin_name = null ) { - if ( $nice_plugin_name === null ) { - $this->plugin_require[ $plugin_name ] = $plugin_name; - } else { - $this->plugin_require[ $plugin_name ] = $nice_plugin_name; - } - - return $this; - } - - /** - * @param string $module_name - * @param string $nice_name Nice module name for better looks in notice - * - * @return $this - */ - public function add_php_module_require( $module_name, $nice_name = null ) { - if ( $nice_name === null ) { - $this->module_require[ $module_name ] = $module_name; - } else { - $this->module_require[ $module_name ] = $nice_name; - } - - return $this; - } - - /** - * @param string $setting - * @param mixed $value - * - * @return $this - */ - public function add_php_setting_require( $setting, $value ) { - $this->setting_require[ $setting ] = $value; - - return $this; - } - - /** - * @return bool - */ - public function are_requirements_met() { - $this->notices = $this->prepare_requirement_notices(); - - return count( $this->notices ) === 0; - } - - /** - * @return array - */ - private function prepare_requirement_notices() { - $notices = array(); - if ( ! self::is_php_at_least( $this->min_php_version ) ) { - $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run on PHP versions older than %s. Please contact your host and ask them to upgrade.', - $this->get_text_domain() ), esc_html( $this->plugin_name ), $this->min_php_version ) ); - } - if ( ! self::is_wp_at_least( $this->min_wp_version ) ) { - $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run on WordPress versions older than %s. Please update WordPress.', - $this->get_text_domain() ), esc_html( $this->plugin_name ), $this->min_wp_version ) ); - } - if ( $this->min_wc_version !== null && $this->can_check_plugin_version() && ! self::is_wc_at_least( $this->min_wc_version ) ) { - $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run on WooCommerce versions older than %s. Please update WooCommerce.', - $this->get_text_domain() ), esc_html( $this->plugin_name ), $this->min_wc_version ) ); - } - if ( $this->min_openssl_version !== null && ! self::is_open_ssl_at_least( $this->min_openssl_version ) ) { - $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run without OpenSSL module version at least %s. Please update OpenSSL module.', - $this->get_text_domain() ), esc_html( $this->plugin_name ), - '0x' . dechex( $this->min_openssl_version ) ) ); - } - - $notices = $this->append_plugin_require_notices( $notices ); - $notices = $this->append_module_require_notices( $notices ); - $notices = $this->append_settings_require_notices( $notices ); - - return $notices; - } - - /** - * @param $min_version - * - * @return mixed - */ - public static function is_php_at_least( $min_version ) { - return version_compare( PHP_VERSION, $min_version, '>=' ); - } - - /** - * Prepares message in html format - * - * @param string $message - * - * @return string - */ - private function prepare_notice_message( $message ) { - return '<div class="error"><p>' . $message . '</p></div>'; - } - - public function get_text_domain() { - return $this->text_domain; - } - - /** - * @param string $min_version - * - * @return bool - */ - public static function is_wp_at_least( $min_version ) { - return version_compare( get_bloginfo( 'version' ), $min_version, '>=' ); - } - - /** - * Are plugins loaded so we can check the version - * - * @return bool - */ - private function can_check_plugin_version() { - return did_action( 'plugins_loaded' ) > 0; - } - - /** - * Checks if plugin is active and have designated version. Needs to be enabled in deferred way. - * - * @param string $min_version - * - * @return bool - */ - public static function is_wc_at_least( $min_version ) { - return defined( 'WC_VERSION' ) && - version_compare( WC_VERSION, $min_version, '>=' ); - } - - /** - * Checks if ssl version is valid - * - * @param int $required_version Version in hex. Version 9.6 is 0x000906000 - * - * @see https://www.openssl.org/docs/man1.1.0/crypto/OPENSSL_VERSION_NUMBER.html - * - * @return bool - */ - public static function is_open_ssl_at_least( $required_version ) { - return defined( 'OPENSSL_VERSION_NUMBER' ) && OPENSSL_VERSION_NUMBER > (int) $required_version; - } - - /** - * @param array $notices - * - * @return array - */ - private function append_plugin_require_notices( $notices ) { - if ( count( $this->plugin_require ) > 0 ) { - foreach ( $this->plugin_require as $plugin_name => $nice_plugin_name ) { - if ( ! self::is_wp_plugin_active( $plugin_name ) ) { - $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run without %s active. Please install and activate %s plugin.', - $this->get_text_domain() ), esc_html( $this->plugin_name ), - esc_html( basename( $nice_plugin_name ) ), esc_html( basename( $nice_plugin_name ) ) ) ); - } - } - } - - return $notices; - } - - /** - * Checks if plugin is active. Needs to be enabled in deferred way. - * - * @param string $plugin_file - * - * @return bool - */ - public static function is_wp_plugin_active( $plugin_file ) { - $active_plugins = (array) get_option( 'active_plugins', array() ); - - if ( is_multisite() ) { - $active_plugins = array_merge( $active_plugins, get_site_option( 'active_sitewide_plugins', array() ) ); - } - - return in_array( $plugin_file, $active_plugins ) || array_key_exists( $plugin_file, $active_plugins ); - } - - /** - * @param array $notices - * - * @return array - */ - private function append_module_require_notices( $notices ) { - if ( count( $this->module_require ) > 0 ) { - foreach ( $this->module_require as $module_name => $nice_module_name ) { - if ( ! self::is_module_active( $module_name ) ) { - $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run without %s php module installed. Please contact your host and ask them to install %s.', - $this->get_text_domain() ), esc_html( $this->plugin_name ), - esc_html( basename( $nice_module_name ) ), esc_html( basename( $nice_module_name ) ) ) ); - } - } - } - - return $notices; - } - - /** - * @param string $name - * - * @return bool - */ - public static function is_module_active( $name ) { - return extension_loaded( $name ); - } - - /** - * @param array $notices - * - * @return array - */ - private function append_settings_require_notices( $notices ) { - if ( count( $this->setting_require ) > 0 ) { - foreach ( $this->setting_require as $setting => $value ) { - if ( ! self::is_setting_set( $setting, $value ) ) { - $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run without %s php setting set to %s. Please contact your host and ask them to set %s.', - $this->get_text_domain() ), esc_html( $this->plugin_name ), esc_html( basename( $setting ) ), - esc_html( basename( $value ) ), esc_html( basename( $setting ) ) ) ); - } - } - } - - return $notices; - } - - /** - * @param string $name - * @param mixed $value - * - * @return bool - */ - public static function is_setting_set( $name, $value ) { - return ini_get( $name ) === (string) $value; - } - - /** - * @return void - * - * @deprecated use render_notices or disable_plugin - */ - public function disable_plugin_render_notice() { - add_action( self::HOOK_ADMIN_NOTICES_ACTION, array( $this, 'handle_render_notices_action') ); - } - - /** - * Renders requirement notices in admin panel - * - * @return void - */ - public function render_notices() { - add_action( self::HOOK_ADMIN_NOTICES_ACTION, array( $this, 'handle_render_notices_action') ); - } - - /** - * Renders requirement notices in admin panel - * - * @return void - */ - public function disable_plugin() { - add_action( self::HOOK_ADMIN_NOTICES_ACTION, array( $this, 'handle_deactivate_action') ); - } - - /** - * @internal Do not use as public. Public only for wp action. - * - * @return void - */ - public function handle_deactivate_action() { - if ( isset( $this->plugin_file ) ) { - deactivate_plugins( plugin_basename( $this->plugin_file ) ); - } - } - - /** - * Should be called as WordPress action - * - * @internal Do not use as public. Public only for wp action. - * - * @return void - */ - public function handle_render_notices_action() { - foreach ( $this->notices as $notice ) { - echo $notice; - } - } - } +if ( ! class_exists( 'WPDesk_Basic_Requirement_Checker' ) ) { + /** + * Checks requirements for plugin + * have to be compatible with PHP 5.3.x + */ + class WPDesk_Basic_Requirement_Checker implements WPDesk_Requirement_Checker { + const EXTENSION_NAME_OPENSSL = 'openssl'; + const HOOK_ADMIN_NOTICES_ACTION = 'admin_notices'; + + const PLUGIN_INFO_KEY_NICE_NAME = 'nice_name'; + const PLUGIN_INFO_KEY_NAME = 'name'; + + /** @var string */ + protected $plugin_name; + /** @var string */ + private $plugin_file; + /** @var string */ + private $min_php_version; + /** @var string */ + private $min_wp_version; + /** @var string|null */ + private $min_wc_version = null; + /** @var int|null */ + private $min_openssl_version = null; + /** @var array */ + protected $plugin_require; + /** @var array */ + private $module_require; + /** @var array */ + private $setting_require; + /** @var array */ + protected $notices; + /** @var @string */ + private $text_domain; + + /** + * @param string $plugin_file + * @param string $plugin_name + * @param string $text_domain + * @param string $php_version + * @param string $wp_version + */ + public function __construct( $plugin_file, $plugin_name, $text_domain, $php_version, $wp_version ) { + $this->plugin_file = $plugin_file; + $this->plugin_name = $plugin_name; + $this->text_domain = $text_domain; + + $this->set_min_php_require( $php_version ); + $this->set_min_wp_require( $wp_version ); + + $this->plugin_require = array(); + $this->module_require = array(); + $this->setting_require = array(); + $this->notices = array(); + } + + /** + * @param string $version + * + * @return $this + */ + public function set_min_php_require( $version ) { + $this->min_php_version = $version; + + return $this; + } + + /** + * @param string $version + * + * @return $this + */ + public function set_min_wp_require( $version ) { + $this->min_wp_version = $version; + + return $this; + } + + /** + * @param string $version + * + * @return $this + */ + public function set_min_wc_require( $version ) { + $this->min_wc_version = $version; + + return $this; + } + + /** + * @param $version + * + * @return $this + */ + public function set_min_openssl_require( $version ) { + $this->min_openssl_version = $version; + + return $this; + } + + /** + * @param string $plugin_name Name in wp format dir/file.php + * @param string $nice_plugin_name Nice plugin name for better looks in notice + * + * @return $this + */ + public function add_plugin_require( $plugin_name, $nice_plugin_name = null ) { + $this->plugin_require[ $plugin_name ] = array( + self::PLUGIN_INFO_KEY_NAME => $plugin_name, + self::PLUGIN_INFO_KEY_NICE_NAME => $nice_plugin_name === null ? $plugin_name : $nice_plugin_name + ); + + return $this; + } + + /** + * Add plugin to require list. Plugin is from repository so we can ask for installation. + * + * @param string $plugin_name Name in wp format dir/file.php + * @param string $version Required version of the plugin. + * @param string $nice_plugin_name Nice plugin name for better looks in notice + * + * @return $this + */ + public function add_plugin_repository_require( $plugin_name, $version, $nice_plugin_name = null ) { + $this->plugin_require[ $plugin_name ] = array( + self::PLUGIN_INFO_KEY_NAME => $plugin_name, + 'version' => $version, + 'repository_url' => 'http://downloads.wordpress.org/plugin/' . dirname( $plugin_name ) . '.latest-stable.zip', + self::PLUGIN_INFO_KEY_NICE_NAME => $nice_plugin_name === null ? $plugin_name : $nice_plugin_name + ); + + return $this; + } + + /** + * @param string $module_name + * @param string $nice_name Nice module name for better looks in notice + * + * @return $this + */ + public function add_php_module_require( $module_name, $nice_name = null ) { + if ( $nice_name === null ) { + $this->module_require[ $module_name ] = $module_name; + } else { + $this->module_require[ $module_name ] = $nice_name; + } + + return $this; + } + + /** + * @param string $setting + * @param mixed $value + * + * @return $this + */ + public function add_php_setting_require( $setting, $value ) { + $this->setting_require[ $setting ] = $value; + + return $this; + } + + /** + * Returns true if are requirements are met. + * + * @return bool + */ + public function are_requirements_met() { + $this->notices = $this->prepare_requirement_notices(); + + return count( $this->notices ) === 0; + } + + /** + * @return array + */ + private function prepare_requirement_notices() { + $notices = array(); + if ( ! self::is_php_at_least( $this->min_php_version ) ) { + $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run on PHP versions older than %s. Please contact your host and ask them to upgrade.', + $this->get_text_domain() ), esc_html( $this->plugin_name ), $this->min_php_version ) ); + } + if ( ! self::is_wp_at_least( $this->min_wp_version ) ) { + $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run on WordPress versions older than %s. Please update WordPress.', + $this->get_text_domain() ), esc_html( $this->plugin_name ), $this->min_wp_version ) ); + } + if ( $this->min_wc_version !== null && $this->can_check_plugin_version() && ! self::is_wc_at_least( $this->min_wc_version ) ) { + $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run on WooCommerce versions older than %s. Please update WooCommerce.', + $this->get_text_domain() ), esc_html( $this->plugin_name ), $this->min_wc_version ) ); + } + if ( $this->min_openssl_version !== null && ! self::is_open_ssl_at_least( $this->min_openssl_version ) ) { + $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run without OpenSSL module version at least %s. Please update OpenSSL module.', + $this->get_text_domain() ), esc_html( $this->plugin_name ), + '0x' . dechex( $this->min_openssl_version ) ) ); + } + + $notices = $this->append_plugin_require_notices( $notices ); + $notices = $this->append_module_require_notices( $notices ); + $notices = $this->append_settings_require_notices( $notices ); + + return $notices; + } + + /** + * @param $min_version + * + * @return mixed + */ + public static function is_php_at_least( $min_version ) { + return version_compare( PHP_VERSION, $min_version, '>=' ); + } + + /** + * Prepares message in html format + * + * @param string $message + * + * @return string + */ + private function prepare_notice_message( $message ) { + return '<div class="error"><p>' . $message . '</p></div>'; + } + + public function get_text_domain() { + return $this->text_domain; + } + + /** + * @param string $min_version + * + * @return bool + */ + public static function is_wp_at_least( $min_version ) { + return version_compare( get_bloginfo( 'version' ), $min_version, '>=' ); + } + + /** + * Are plugins loaded so we can check the version + * + * @return bool + */ + private function can_check_plugin_version() { + return did_action( 'plugins_loaded' ) > 0; + } + + /** + * Checks if plugin is active and have designated version. Needs to be enabled in deferred way. + * + * @param string $min_version + * + * @return bool + */ + public static function is_wc_at_least( $min_version ) { + return defined( 'WC_VERSION' ) && + version_compare( WC_VERSION, $min_version, '>=' ); + } + + /** + * Checks if ssl version is valid + * + * @param int $required_version Version in hex. Version 9.6 is 0x000906000 + * + * @return bool + * @see https://www.openssl.org/docs/man1.1.0/crypto/OPENSSL_VERSION_NUMBER.html + * + */ + public static function is_open_ssl_at_least( $required_version ) { + return defined( 'OPENSSL_VERSION_NUMBER' ) && OPENSSL_VERSION_NUMBER > (int) $required_version; + } + + /** + * @param array $notices + * + * @return array + */ + private function append_plugin_require_notices( $notices ) { + if ( count( $this->plugin_require ) > 0 ) { + foreach ( $this->plugin_require as $plugin_name => $plugin_info ) { + $notice = null; + if ( isset( $plugin_info['repository_url'] ) ) { + $notice = $this->prepare_plugin_repository_require_notice( $plugin_info ); + } elseif ( ! self::is_wp_plugin_active( $plugin_name ) ) { + $notice = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run without %s active. Please install and activate %s plugin.', + $this->get_text_domain() ), esc_html( $this->plugin_name ), + esc_html( basename( $plugin_info[ self::PLUGIN_INFO_KEY_NICE_NAME ] ) ), + esc_html( basename( $plugin_info[ self::PLUGIN_INFO_KEY_NICE_NAME ] ) ) ) ); + } + + if ( $notice !== null ) { + $notices[] = $notice; + } + } + } + + return $notices; + } + + /** + * Prepares WP install url and injects info about plugin to the WP update engine. + * + * @param array $plugin_info + * + * @return string + */ + private function prepare_plugin_repository_install_url( $plugin_info ) { + $slug = basename( $plugin_info[ self::PLUGIN_INFO_KEY_NAME ] ); + $install_url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $slug ), + 'install-plugin_' . $slug ); + + add_filter( 'plugins_api', function ( $api, $action, $args ) use ( $plugin_info ) { + if ( 'plugin_information' !== $action || + false !== $api || + ! isset( $args->slug ) || + 'wpdesk-helper' !== $args->slug + ) { + return $api; + } + + $api = new stdClass(); + $api->name = $plugin_info['nice_name']; // self in closures requires 5.4 + $api->version = $plugin_info['version']; // self in closures requires 5.4 + $api->download_link = esc_url( $plugin_info['repository_url'] ); // self in closures requires 5.4 + + return $api; + }, 10, 3 ); + + return $install_url; + } + + /** + * @param array $plugin_info Internal required plugin info data. + * + * @return string|null Return null if no notice is needed. + */ + private function prepare_plugin_repository_require_notice( $plugin_info ) { + $name = $plugin_info[ self::PLUGIN_INFO_KEY_NAME ]; + $nice_name = $plugin_info[ self::PLUGIN_INFO_KEY_NICE_NAME ]; + + if ( ! self::is_wp_plugin_installed( $name ) ) { + $install_url = $this->prepare_plugin_repository_install_url( $plugin_info ); + + return sprintf( wp_kses( __( 'The “%s” plugin requires free %s plugin. <a href="%s">Install %s →</a>', + $this->get_text_domain() ), array( 'a' => array( 'href' => array() ) ) ), + $this->plugin_name, $nice_name, esc_url( $install_url ), $nice_name ); + } + + if ( ! self::is_wp_plugin_active( $name ) ) { + $activate_url = 'plugins.php?action=activate&plugin=' . urlencode( $plugin_info[ self::PLUGIN_INFO_KEY_NAME ] ) . '&plugin_status=all&paged=1&s&_wpnonce=' . urlencode( wp_create_nonce( 'activate-plugin_' . $name ) ); + + return sprintf( wp_kses( __( 'The “%s” plugin requires activating %s plugin. <a href="%s">Activate %s →</a>', + $this->get_text_domain() ), array( 'a' => array( 'href' => array() ) ) ), + $this->plugin_name, $nice_name, esc_url( admin_url( $activate_url ) ), $nice_name ); + + } + + return null; + } + + /** + * Checks if plugin is active. Needs to be used in deferred way. + * + * @param string $plugin_file + * + * @return bool + */ + public static function is_wp_plugin_active( $plugin_file ) { + $active_plugins = (array) get_option( 'active_plugins', array() ); + + if ( is_multisite() ) { + $active_plugins = array_merge( $active_plugins, get_site_option( 'active_sitewide_plugins', array() ) ); + } + + return in_array( $plugin_file, $active_plugins ) || array_key_exists( $plugin_file, $active_plugins ); + } + + /** + * Checks if plugin is installed. Needs to be enabled in deferred way. + * + * @param string $plugin_file + * + * @return bool + */ + public static function is_wp_plugin_installed( $plugin_file ) { + return array_key_exists( $plugin_file, get_plugins() ); + } + + /** + * @param array $notices + * + * @return array + */ + private function append_module_require_notices( $notices ) { + if ( count( $this->module_require ) > 0 ) { + foreach ( $this->module_require as $module_name => $nice_module_name ) { + if ( ! self::is_module_active( $module_name ) ) { + $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run without %s php module installed. Please contact your host and ask them to install %s.', + $this->get_text_domain() ), esc_html( $this->plugin_name ), + esc_html( basename( $nice_module_name ) ), esc_html( basename( $nice_module_name ) ) ) ); + } + } + } + + return $notices; + } + + /** + * @param string $name + * + * @return bool + */ + public static function is_module_active( $name ) { + return extension_loaded( $name ); + } + + /** + * @param array $notices + * + * @return array + */ + private function append_settings_require_notices( $notices ) { + if ( count( $this->setting_require ) > 0 ) { + foreach ( $this->setting_require as $setting => $value ) { + if ( ! self::is_setting_set( $setting, $value ) ) { + $notices[] = $this->prepare_notice_message( sprintf( __( 'The “%s” plugin cannot run without %s php setting set to %s. Please contact your host and ask them to set %s.', + $this->get_text_domain() ), esc_html( $this->plugin_name ), + esc_html( basename( $setting ) ), + esc_html( basename( $value ) ), esc_html( basename( $setting ) ) ) ); + } + } + } + + return $notices; + } + + /** + * @param string $name + * @param mixed $value + * + * @return bool + */ + public static function is_setting_set( $name, $value ) { + return ini_get( $name ) === (string) $value; + } + + /** + * @return void + * + * @deprecated use render_notices or disable_plugin + */ + public function disable_plugin_render_notice() { + add_action( self::HOOK_ADMIN_NOTICES_ACTION, array( $this, 'handle_render_notices_action' ) ); + } + + /** + * Renders requirement notices in admin panel + * + * @return void + */ + public function render_notices() { + add_action( self::HOOK_ADMIN_NOTICES_ACTION, array( $this, 'handle_render_notices_action' ) ); + } + + /** + * Renders requirement notices in admin panel + * + * @return void + */ + public function disable_plugin() { + add_action( self::HOOK_ADMIN_NOTICES_ACTION, array( $this, 'handle_deactivate_action' ) ); + } + + /** + * @return void + * @internal Do not use as public. Public only for wp action. + * + */ + public function handle_deactivate_action() { + if ( isset( $this->plugin_file ) ) { + deactivate_plugins( plugin_basename( $this->plugin_file ) ); + } + } + + /** + * Should be called as WordPress action + * + * @return void + * @internal Do not use as public. Public only for wp action. + * + */ + public function handle_render_notices_action() { + foreach ( $this->notices as $notice ) { + echo $notice; + } + } + } } \ No newline at end of file diff --git a/src/Basic_Requirement_Checker_Factory.php b/src/Basic_Requirement_Checker_Factory.php index a4bbb9cedf9dd6e93b43659438955140177043b0..5c691b679b8f52844f78e3af1d63a5ec64074689 100644 --- a/src/Basic_Requirement_Checker_Factory.php +++ b/src/Basic_Requirement_Checker_Factory.php @@ -1,22 +1,98 @@ <?php -if ( ! class_exists('Basic_Requirement_Checker')) { - require_once 'Basic_Requirement_Checker.php'; +if ( ! class_exists( 'Basic_Requirement_Checker' ) ) { + require_once 'Basic_Requirement_Checker.php'; } -class WPDesk_Basic_Requirement_Checker_Factory -{ - /** - * @param $plugin_file - * @param $plugin_name - * @param $text_domain - * @param $php_version - * @param $wp_version - * - * @return WPDesk_Requirement_Checker - */ - public function create_requirement_checker($plugin_file, $plugin_name, $text_domain) - { - return new WPDesk_Basic_Requirement_Checker($plugin_file, $plugin_name, $text_domain, null, null); - } +if ( ! class_exists( 'WPDesk_Basic_Requirement_Checker_With_Update_Disable' ) ) { + require_once 'Basic_Requirement_Checker_With_Update_Disable.php'; +} + +/** + * Falicitates createion of requirement checker + */ +class WPDesk_Basic_Requirement_Checker_Factory { + const LIBRARY_TEXT_DOMAIN = 'wp-basic-requirements'; + + /** + * Creates a simplest possible version of requirement checker. + * + * @param string $plugin_file + * @param string $plugin_name + * @param string|null $text_domain Text domain to use. If null try to use library text domain. + * + * @return WPDesk_Requirement_Checker + */ + public function create_requirement_checker( $plugin_file, $plugin_name, $text_domain = null ) { + return new WPDesk_Basic_Requirement_Checker( $plugin_file, $plugin_name, + $this->initialize_translations( $text_domain ), null, null ); + } + + /** + * Creates a requirement checker according to given requirements array info. + * + * @param string $plugin_file + * @param string $plugin_name + * @param string $text_domain Text domain to use. If null try to use library text domain. + * @param array $requirements Requirements array as given by plugin. + * + * @return WPDesk_Requirement_Checker + */ + public function create_from_requirement_array( $plugin_file, $plugin_name, $requirements, $text_domain = null ) { + $requirements_checker = new WPDesk_Basic_Requirement_Checker_With_Update_Disable( + $plugin_file, + $plugin_name, + $this->initialize_translations( $text_domain ), + $requirements['php'], + $requirements['wp'] + ); + + if ( isset( $requirements['plugins'] ) ) { + foreach ( $requirements['plugins'] as $requirement ) { + $requirements_checker->add_plugin_require( $requirement['name'], $requirement['nice_name'] ); + } + } + + if ( isset( $requirements['repo_plugins'] ) ) { + foreach ( $requirements['repo_plugins'] as $requirement ) { + $requirements_checker->add_plugin_repository_require( $requirement['name'], $requirement['version'], + $requirement['nice_name'] ); + } + } + + if ( isset( $requirements['modules'] ) ) { + foreach ( $requirements['modules'] as $requirement ) { + $requirements_checker->add_php_module_require( $requirement['name'], $requirement['nice_name'] ); + } + } + + return $requirements_checker; + } + + /** + * Tries to initialize translations for requirement checker. If not given then default library translation is used. + * + * @param string|null $text_domain + * + * @return string + */ + private function initialize_translations( $text_domain = null ) { + if ( $text_domain === null ) { + $text_domain = self::LIBRARY_TEXT_DOMAIN; + + if ( function_exists( 'determine_locale' ) ) { + $locale = determine_locale(); + } else { // before WP 5.0 compatibility + $locale = get_locale(); + } + $locale = apply_filters( 'plugin_locale', $locale, self::LIBRARY_TEXT_DOMAIN ); + + $lang_mo_file = __DIR__ . '/../lang/' . self::LIBRARY_TEXT_DOMAIN . '-' . $locale . '.mo'; + if ( file_exists( $lang_mo_file ) ) { + load_textdomain( self::LIBRARY_TEXT_DOMAIN, $lang_mo_file ); + } + } + + return $text_domain; + } } diff --git a/src/Basic_Requirement_Checker_With_Update_Disable.php b/src/Basic_Requirement_Checker_With_Update_Disable.php new file mode 100644 index 0000000000000000000000000000000000000000..aeaf871381680523dd8218e7d291bc669bf518c4 --- /dev/null +++ b/src/Basic_Requirement_Checker_With_Update_Disable.php @@ -0,0 +1,47 @@ +<?php + +if ( ! class_exists( 'WPDesk_Basic_Requirement_Checker' ) ) { + require_once 'Basic_Requirement_Checker.php'; +} + +if ( ! class_exists( 'WPDesk_Basic_Requirement_Checker_With_Update_Disable' ) ) { + /** + * Checks requirements for plugin. When required plugin is updated right now, then say that requirements are not met temporary. + * have to be compatible with PHP 5.2.x + */ + class WPDesk_Basic_Requirement_Checker_With_Update_Disable extends WPDesk_Basic_Requirement_Checker { + + /** + * Returns true if are requirements are met. + * + * @return bool + */ + public function are_requirements_met() { + $has_been_met = parent::are_requirements_met(); + if ( ! $has_been_met ) { + return $has_been_met; + } + foreach ( $this->plugin_require as $name => $plugin_info ) { + if ( $this->is_currently_updated( $name ) ) { + $nice_name = $plugin_info[self::PLUGIN_INFO_KEY_NICE_NAME]; + $this->notices[] = sprintf( __( 'The “%s” plugin disables temporarily as required %s plugin is being upgraded.', + $this->get_text_domain() ), + $this->plugin_name, $nice_name, $nice_name ); + } + } + + return count( $this->notices ) === 0; + } + + /** + * Is plugin upgrading right now? + * + * @param string $name + * + * @return bool + */ + private function is_currently_updated( $name ) { + return isset( $_GET['action'] ) && $_GET['action'] === 'upgrade-plugin' && $_GET['plugin'] === $name; + } + } +} \ No newline at end of file diff --git a/src/Buildable.php b/src/Buildable.php deleted file mode 100644 index 78c73224961af9592e346b83fd58f360d06971fa..0000000000000000000000000000000000000000 --- a/src/Buildable.php +++ /dev/null @@ -1,11 +0,0 @@ -<?php - -/** - * Have info about what class should be built by WPDesk_Builder - * - * have to be compatible with PHP 5.2.x - */ -interface WPDesk_Buildable { - /** @return string */ - public function get_class_name(); -} \ No newline at end of file diff --git a/src/Plugin/Has_Plugin_Info.php b/src/Plugin/Has_Plugin_Info.php deleted file mode 100644 index 5ecf98d525474f04c37ff04a64ec6926e653e5c4..0000000000000000000000000000000000000000 --- a/src/Plugin/Has_Plugin_Info.php +++ /dev/null @@ -1,29 +0,0 @@ -<?php - -if ( ! interface_exists( 'WPDesk_Translatable' ) ) { - require_once __DIR__ . '/../Translatable.php'; -} - - -/** - * Have MUST HAVE info for plugin instantion - * - * have to be compatible with PHP 5.2.x - */ -interface WPDesk_Has_Plugin_Info extends WPDesk_Translatable { - /** - * @return string - */ - public function get_plugin_file_name(); - - /** - * @return string - */ - public function get_plugin_dir(); - - /** - * @return string - */ - public function get_version(); - -} \ No newline at end of file diff --git a/src/Plugin/Plugin_Info.php b/src/Plugin/Plugin_Info.php deleted file mode 100644 index 693b408066013e55319f7b6ca32159849081ffea..0000000000000000000000000000000000000000 --- a/src/Plugin/Plugin_Info.php +++ /dev/null @@ -1,171 +0,0 @@ -<?php - -if ( ! interface_exists( 'WPDesk_Translatable' ) ) { - require_once __DIR__ . '/../Translatable.php'; -} -if ( ! class_exists( 'WPDesk_Buildable' ) ) { - require_once __DIR__ . '/../Buildable.php'; -} -if ( ! class_exists( 'WPDesk_Has_Plugin_Info' ) ) { - require_once 'Has_Plugin_Info.php'; -} - -/** - * Structure with core info about plugin - * - * have to be compatible with PHP 5.2.x - */ -class WPDesk_Plugin_Info implements WPDesk_Translatable, WPDesk_Buildable, WPDesk_Has_Plugin_Info { - /** @var string */ - private $plugin_file_name; - - /** @var string */ - private $plugin_dir; - - /** @var string */ - private $plugin_url; - - /** @var string */ - private $class_name; - - /** @var string */ - private $version; - - /** @var string */ - private $product_id; - - /** @var string */ - private $plugin_name; - - /** @var \DateTimeInterface */ - private $release_date; - - /** string */ - private $text_domain; - - /** - * @return string - */ - public function get_plugin_file_name() { - return $this->plugin_file_name; - } - - /** - * @param string $plugin_name - */ - public function set_plugin_file_name( $plugin_name ) { - $this->plugin_file_name = $plugin_name; - } - - /** - * @return string - */ - public function get_plugin_dir() { - return $this->plugin_dir; - } - - /** - * @param string $plugin_dir - */ - public function set_plugin_dir( $plugin_dir ) { - $this->plugin_dir = $plugin_dir; - } - - /** - * @return string - */ - public function get_plugin_url() { - return $this->plugin_url; - } - - /** - * @param string $plugin_url - */ - public function set_plugin_url( $plugin_url ) { - $this->plugin_url = $plugin_url; - } - - /** - * @return string - */ - public function get_version() { - return $this->version; - } - - /** - * @param string $version - */ - public function set_version( $version ) { - $this->version = $version; - } - - /** - * @return string - */ - public function get_product_id() { - return $this->product_id; - } - - /** - * @param string $product_id - */ - public function set_product_id( $product_id ) { - $this->product_id = $product_id; - } - - /** - * @return string - */ - public function get_plugin_name() { - return $this->plugin_name; - } - - /** - * @param string $plugin_name - */ - public function set_plugin_name( $plugin_name ) { - $this->plugin_name = $plugin_name; - } - - /** - * @return DateTimeInterface - */ - public function get_release_date() { - return $this->release_date; - } - - /** - * @param \DateTimeInterface $release_date - */ - public function set_release_date( $release_date ) { - $this->release_date = $release_date; - } - - /** - * @return string - */ - public function get_class_name() { - return $this->class_name; - } - - /** - * @param string $class_name - */ - public function set_class_name( $class_name ) { - $this->class_name = $class_name; - } - - /** - * @return string - */ - public function get_text_domain() { - return $this->text_domain; - } - - /** - * @param $value - */ - public function set_text_domain( $value ) { - $this->text_domain = $value; - } -} \ No newline at end of file diff --git a/src/Translable.php b/src/Translable.php deleted file mode 100644 index c13e2a7e778efd5765940d3517969136766540fc..0000000000000000000000000000000000000000 --- a/src/Translable.php +++ /dev/null @@ -1,9 +0,0 @@ -<?php - -/** - * @deprecated Have typo so better use WPDesk_Translatable - */ -interface WPDesk_Translable { - /** @return string */ - public function get_text_domain(); -} \ No newline at end of file diff --git a/src/Translatable.php b/src/Translatable.php deleted file mode 100644 index a1d9eea460dfe4fd8a113ee8c670b813f5e76786..0000000000000000000000000000000000000000 --- a/src/Translatable.php +++ /dev/null @@ -1,15 +0,0 @@ -<?php - -if ( ! interface_exists( 'WPDesk_Translable' ) ) { - require_once 'Translable.php'; -} - -/** - * Have info about textdomain - how to translate texts - * - * have to be compatible with PHP 5.2.x - */ -interface WPDesk_Translatable extends WPDesk_Translable { - /** @return string */ - public function get_text_domain(); -} \ No newline at end of file diff --git a/tests/unit/Test_Basic_Requirement_Checker.php b/tests/unit/Test_Basic_Requirement_Checker.php index 260369cb7ae4e8233e25b552878685d7a4ac2250..552b31fbbff8e58fc1d9ee8a26eb7f8fe3912e69 100644 --- a/tests/unit/Test_Basic_Requirement_Checker.php +++ b/tests/unit/Test_Basic_Requirement_Checker.php @@ -27,7 +27,7 @@ class Test_Basic_Requirement_Checker extends PHPUnit\Framework\TestCase { } public function test_php_version_check() { - $known_PHP_versions = [ '7.3', '7.2', '7.1', '7.0', '5.6', '5.5', '5.4', '5.3', '5.2' ]; + $known_PHP_versions = array( '7.3', '7.2', '7.1', '7.0', '5.6', '5.5', '5.4', '5.3', '5.2' ); $requirements = $this->create_requirements_for_php_wp( self::ALWAYS_VALID_PHP_VERSION, @@ -55,7 +55,7 @@ class Test_Basic_Requirement_Checker extends PHPUnit\Framework\TestCase { * * @return WPDesk_Basic_Requirement_Checker */ - public function create_requirements_for_php_wp( $php, $wp ) { + private function create_requirements_for_php_wp( $php, $wp ) { return new WPDesk_Basic_Requirement_Checker( self::RANDOM_PLUGIN_FILE, self::RANDOM_PLUGIN_NAME, self::RANDOM_PLUGIN_TEXTDOMAIN, $php, $wp ); } @@ -98,15 +98,15 @@ class Test_Basic_Requirement_Checker extends PHPUnit\Framework\TestCase { $not_existing_plugin_name = 'Not exist'; WP_Mock::wpFunction( 'get_option' ) - ->withArgs( [ 'active_plugins', [] ] ) - ->andReturn( [ $exising_plugin_name ] ); + ->withArgs( array( 'active_plugins', array() ) ) + ->andReturn( array( $exising_plugin_name ) ); WP_Mock::wpFunction( 'is_multisite' ) ->andReturn( $multisite ); WP_Mock::wpFunction( 'get_site_option' ) - ->withArgs( [ 'active_sitewide_plugins', [] ] ) - ->andReturn( [ $exising_multisite_plugin_name ] ); + ->withArgs( array( 'active_sitewide_plugins', array() ) ) + ->andReturn( array( $exising_multisite_plugin_name ) ); $requirements = $this->create_requirements_for_php_wp( self::ALWAYS_VALID_PHP_VERSION, @@ -155,13 +155,53 @@ class Test_Basic_Requirement_Checker extends PHPUnit\Framework\TestCase { self::ALWAYS_VALID_WP_VERSION ); WP_Mock::expectActionAdded( WPDesk_Basic_Requirement_Checker::HOOK_ADMIN_NOTICES_ACTION, - [ $requirements, 'handle_render_notices_action'] ); + array( $requirements, 'handle_render_notices_action' ) ); $this->assertFalse( $requirements->are_requirements_met() ); $requirements->disable_plugin(); - $requirements->render_notices(); + $requirements->render_notices(); $this->expectOutputRegex( '/cannot run on PHP/' ); $requirements->handle_render_notices_action(); } + + public function test_add_plugin_repository_require_checks_for_activation_and_installs() { + $random_version = "1.0"; + $activated_plugin_name = 'WooCommerce'; + $not_activated_plugin_name = "some_other"; + $not_installed_plugin_name = "not_installed"; + $installed_plugin_names = array( $activated_plugin_name, $not_activated_plugin_name ); + + + WP_Mock::wpFunction( 'get_plugins' ) + ->andReturn( array_flip( $installed_plugin_names ) ); + + WP_Mock::wpFunction( 'get_option' ) + ->withArgs( array( 'active_plugins', array() ) ) + ->andReturn( array( $activated_plugin_name ) ); + + WP_Mock::passthruFunction( 'self_admin_url' ); + WP_Mock::passthruFunction( 'wp_kses' ); + WP_Mock::passthruFunction( 'wp_nonce_url' ); + WP_Mock::passthruFunction( 'wp_create_nonce' ); + WP_Mock::passthruFunction( 'admin_url' ); + + $requirements = $this->create_requirements_for_php_wp( self::ALWAYS_VALID_PHP_VERSION, + self::ALWAYS_VALID_WP_VERSION ); + + $requirements->add_plugin_repository_require( $activated_plugin_name, $random_version ); + $this->assertTrue( $requirements->are_requirements_met(), "Should be met for activated plugin" ); + + $requirements->add_plugin_repository_require( $not_activated_plugin_name, $random_version ); + $this->assertFalse( $requirements->are_requirements_met(), "Should NOT be met for only installed plugin" ); + + $this->expectOutputRegex( "/Activate $not_activated_plugin_name/" ); + $requirements->handle_render_notices_action(); + + $requirements->add_plugin_repository_require( $not_installed_plugin_name, $random_version ); + $this->expectOutputRegex( "/Install $not_installed_plugin_name/" ); + $this->assertFalse( $requirements->are_requirements_met(), + "Should NOT be met - uninstalled and unactive plugins are required" ); + $requirements->handle_render_notices_action(); + } } diff --git a/tests/unit/Test_Basic_Requirement_Checker_Factory.php b/tests/unit/Test_Basic_Requirement_Checker_Factory.php new file mode 100644 index 0000000000000000000000000000000000000000..adbf8d9578ddb9e8c825983c1e9a90a661e3389e --- /dev/null +++ b/tests/unit/Test_Basic_Requirement_Checker_Factory.php @@ -0,0 +1,52 @@ +<?php + + +class Test_Basic_Requirement_Checker_Factory extends PHPUnit\Framework\TestCase { + public function test_can_create_checker_withn_valid_requirements() { + $existing_locale = 'pl_PL'; + $requirements = array( + 'php' => '5.6', + 'wp' => '4.5', + 'plugins' => array( + array( + 'name' => 'woocommerce/woocommerce.php', + 'nice_name' => 'WooCommerce', + ), + ), + 'repo_plugins' => array( + array( + 'name' => 'flexible-checkout-fields/flexible-checkout-fields.php', + 'version' => '1.0', + 'nice_name' => 'Flexible Checkout Fields', + ), + ), + ); + + WP_Mock::wpFunction( 'get_locale' ) + ->andReturn( $existing_locale ); + WP_Mock::wpFunction( 'load_textdomain' ) + ->once(); // locale pl_PL exists so it should try to load it + + $factory = new WPDesk_Basic_Requirement_Checker_Factory(); + $checker = $factory->create_from_requirement_array( 'whatever', 'whatever', $requirements ); + + WP_Mock::wpFunction( 'get_plugins' ) + ->andReturn( array() ); + + WP_Mock::wpFunction( 'get_option' ) + ->withArgs( array( 'active_plugins', array() ) ) + ->andReturn( array() ); + + WP_Mock::passthruFunction( 'self_admin_url' ); + WP_Mock::passthruFunction( 'wp_kses' ); + WP_Mock::passthruFunction( 'wp_nonce_url' ); + WP_Mock::passthruFunction( 'wp_create_nonce' ); + WP_Mock::passthruFunction( 'admin_url' ); + + $this->assertFalse( $checker->are_requirements_met(), '2 plugins required and there should be none activated' ); + + $this->expectOutputRegex( '/Flexible Checkout Fields/' ); + $this->expectOutputRegex( '/WooCommerce/' ); + $checker->handle_render_notices_action(); + } +} diff --git a/tests/unit/Test_Basic_Requirement_Checker_With_Update_Disable.php b/tests/unit/Test_Basic_Requirement_Checker_With_Update_Disable.php new file mode 100644 index 0000000000000000000000000000000000000000..ce3d688f1ea514b93196ae8b8800729fa511847a --- /dev/null +++ b/tests/unit/Test_Basic_Requirement_Checker_With_Update_Disable.php @@ -0,0 +1,42 @@ +<?php + +class Test_Basic_Requirement_Checker_With_Update_Disable extends PHPUnit\Framework\TestCase { + const RANDOM_PLUGIN_FILE = 'file'; + const RANDOM_PLUGIN_NAME = 'name'; + const ALWAYS_VALID_PHP_VERSION = '5.2'; + const ALWAYS_VALID_WP_VERSION = '4.0'; + const RANDOM_PLUGIN_TEXTDOMAIN = 'text'; + + public function setUp() { + WP_Mock::setUp(); + + WP_Mock::wpFunction( 'get_bloginfo' ) + ->andReturn( self::ALWAYS_VALID_WP_VERSION ); + } + + public function tearDown() { + WP_Mock::tearDown(); + } + + public function test_requirements_are_not_met_when_plugin_update() { + $checker = new WPDesk_Basic_Requirement_Checker_With_Update_Disable( self::RANDOM_PLUGIN_FILE, + self::RANDOM_PLUGIN_NAME, + self::RANDOM_PLUGIN_TEXTDOMAIN, self::ALWAYS_VALID_PHP_VERSION, self::ALWAYS_VALID_WP_VERSION ); + + $this->assertTrue( $checker->are_requirements_met(), 'Initial php and wp version should be met' ); + + $valid_plugin_name = 'woocommerce/woocommerce.php'; + + WP_Mock::wpFunction( 'get_option' ) + ->withArgs( array( 'active_plugins', array() ) ) + ->andReturn( array( $valid_plugin_name ) ); + + $checker->add_plugin_require( $valid_plugin_name ); + $this->assertTrue( $checker->are_requirements_met(), 'Plugin is activated so initial requirements should be met' ); + + $real_woocommerce_upgrade_url = '/wp-admin/update.php?action=upgrade-plugin&plugin=woocommerce%2Fwoocommerce.php&_wpnonce=263d805825'; + $url = parse_url( $real_woocommerce_upgrade_url ); + parse_str( $url['query'], $_GET ); + $this->assertFalse( $checker->are_requirements_met(), 'Info about upgrade should switch result' ); + } +}