plugin updates

This commit is contained in:
Tony Volpe
2024-06-17 15:33:26 -04:00
parent 3751a5a1a6
commit e4e274a9a7
2674 changed files with 0 additions and 507851 deletions

View File

@@ -1,102 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [2.0.0] - 2023-12-28
### Added
* Tested against PHP 8.3. [#138], [#150]
### Changed
* All the source classes are now namespaced under `Yoast\WHIPv2`. The version number in the namespaced will be bumped up with every major version. [#157]
The classes have also been renamed to remove the `Whip_` prefix, and the folders' names have been capitalized to follow the PSR-4 standard.
* The `Requirement` interface now explicitly declares the following two additional methods: `version() ` and `operator()` and classes implementing the interface should ensure these methods are available. [#146]
* General housekeeping.
### Removed
* The deprecated `Whip_WPMessagePresenter:register_hooks()` method has been removed. [#158]
### Fixed
* Compatibility with PHP >= 8.2: prevent a deprecation notice about dynamic properties usage from being thrown in the `RequirementsChecker` class. [#117]
* Security hardening: added sanitization to the notification dismiss action. [#131]
[#158]: https://github.com/Yoast/whip/pull/158
[#157]: https://github.com/Yoast/whip/pull/157
[#150]: https://github.com/Yoast/whip/pull/150
[#146]: https://github.com/Yoast/whip/pull/146
[#138]: https://github.com/Yoast/whip/pull/138
[#131]: https://github.com/Yoast/whip/pull/131
[#117]: https://github.com/Yoast/whip/pull/117
## [1.2.0] - 2021-07-20
:warning: This version drops support for PHP 5.2!
### Changed
* PHP 5.2 is no longer supported. The minimum supported PHP version for the WHIP library is now PHP 5.3. [#96]
* The previous solution to prevent duplicate messages as included in v1.0.2 has been improved upon and made more stable. Props [Drew Jaynes]. [#44]
* The `Whip_InvalidOperatorType::__construct()` method now has a second, optional `$validOperators` parameter. [#62]
If this parameter is not passed, the default set of valid operators, as was used before, will be used.
* Improved protection against XSS in localizable texts. [#50]
* Improved support for translating localizable texts (I18n). [#59]
* The distributed package will no longer contain development-related files. [#45]
* General housekeeping.
### Deprecated
* The `public` `Whip_WPMessagePresenter:register_hooks()` method has been deprecated in favour of the new `Whip_WPMessagePresenter:registerHooks()`. [#52], [#107]
### Fixed
* The text of the exception message thrown via the `Whip_InvalidType` exception was sometimes garbled. [#61]
* Compatibility with PHP >= 7.4: prevent a deprecation notice from being thrown (fatal error on PHP 8.0). [#88]
[#44]: https://github.com/Yoast/whip/pull/44
[#45]: https://github.com/Yoast/whip/pull/45
[#50]: https://github.com/Yoast/whip/pull/50
[#52]: https://github.com/Yoast/whip/pull/52
[#59]: https://github.com/Yoast/whip/pull/59
[#61]: https://github.com/Yoast/whip/pull/61
[#62]: https://github.com/Yoast/whip/pull/62
[#88]: https://github.com/Yoast/whip/pull/88
[#96]: https://github.com/Yoast/whip/pull/96
[#107]: https://github.com/Yoast/whip/pull/107
[Drew Jaynes]: https://github.com/DrewAPicture
## [1.1.0] - 2017-08-08
### Added
* Allow WordPress messages to be dismissed for a period of 4 weeks.
## [1.0.2] - 2017-06-27
### Fixed
* When multiple plugins containing whip are activated, the message is no longer shown multiple times, props [Andrea](https://github.com/sciamannikoo).
## [1.0.1] - 2017-03-21
### Fixed
* Fix a missing link when the PHP message is switched to the WordPress.org hosting page.
## [1.0.0] - 2017-03-21
### Changed
* Updated screenshot in README
## [1.0.0-beta.2] - 2017-03-11
### Added
* Complete PHP version message
### Changed
* Refactor code architecture.
* Use PHP version constant instead of function.
### Fixed
* Fix broken version reconciliation.
## 1.0.0-beta.1 - 2017-02-21
* Initial pre-release of whip. A package to nudge users to upgrade their software versions.
[Unreleased]: https://github.com/yoast/whip/compare/1.2.0...HEAD
[1.2.0]: https://github.com/yoast/whip/compare/1.1.0...1.2.0
[1.1.0]: https://github.com/yoast/whip/compare/1.0.2...1.1.0
[1.0.2]: https://github.com/yoast/whip/compare/1.0.1...1.0.2
[1.0.1]: https://github.com/yoast/whip/compare/1.0.0...1.0.1
[1.0.0]: https://github.com/yoast/whip/compare/1.0.0-beta.2...1.0.0
[1.0.0-beta.2]: https://github.com/yoast/whip/compare/1.0.0-beta.1...1.0.0-beta.2

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 Yoast
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,10 +0,0 @@
<?php
/**
* WHIP libary file.
*
* @package Yoast\WHIP
*/
return array(
'php' => PHP_VERSION,
);

View File

@@ -1,8 +0,0 @@
<?php
/**
* WHIP libary file.
*
* @package Yoast\WHIP
*/
return '1.0.1';

View File

@@ -1,61 +0,0 @@
<?php
namespace Yoast\WHIPv2;
use Yoast\WHIPv2\Exceptions\InvalidType;
use Yoast\WHIPv2\Interfaces\Requirement;
/**
* Class Configuration.
*/
class Configuration {
/**
* The configuration to use.
*
* @var array<string>
*/
private $configuration;
/**
* Configuration constructor.
*
* @param array<string, string> $configuration The configuration to use.
*
* @throws InvalidType When the $configuration parameter is not of the expected type.
*/
public function __construct( $configuration = array() ) {
if ( ! \is_array( $configuration ) ) {
throw new InvalidType( 'Configuration', $configuration, 'array' );
}
$this->configuration = $configuration;
}
/**
* Retrieves the configured version of a particular requirement.
*
* @param Requirement $requirement The requirement to check.
*
* @return string|int The version of the passed requirement that was detected as a string.
* If the requirement does not exist, this returns int -1.
*/
public function configuredVersion( Requirement $requirement ) {
if ( ! $this->hasRequirementConfigured( $requirement ) ) {
return -1;
}
return $this->configuration[ $requirement->component() ];
}
/**
* Determines whether the passed requirement is present in the configuration.
*
* @param Requirement $requirement The requirement to check.
*
* @return bool Whether or not the requirement is present in the configuration.
*/
public function hasRequirementConfigured( Requirement $requirement ) {
return \array_key_exists( $requirement->component(), $this->configuration );
}
}

View File

@@ -1,20 +0,0 @@
<?php
namespace Yoast\WHIPv2\Exceptions;
use Exception;
/**
* Class EmptyProperty.
*/
class EmptyProperty extends Exception {
/**
* EmptyProperty constructor.
*
* @param string $property Property name.
*/
public function __construct( $property ) {
parent::__construct( \sprintf( '%s cannot be empty.', (string) $property ) );
}
}

View File

@@ -1,27 +0,0 @@
<?php
namespace Yoast\WHIPv2\Exceptions;
use Exception;
/**
* Class InvalidOperatorType.
*/
class InvalidOperatorType extends Exception {
/**
* InvalidOperatorType constructor.
*
* @param string $value Invalid operator.
* @param string[] $validOperators Valid operators.
*/
public function __construct( $value, $validOperators = array( '=', '==', '===', '<', '>', '<=', '>=' ) ) {
parent::__construct(
\sprintf(
'Invalid operator of %s used. Please use one of the following operators: %s',
$value,
\implode( ', ', $validOperators )
)
);
}
}

View File

@@ -1,22 +0,0 @@
<?php
namespace Yoast\WHIPv2\Exceptions;
use Exception;
/**
* Class InvalidType.
*/
class InvalidType extends Exception {
/**
* InvalidType constructor.
*
* @param string $property Property name.
* @param string $value Property value.
* @param string $expectedType Expected property type.
*/
public function __construct( $property, $value, $expectedType ) {
parent::__construct( \sprintf( '%s should be of type %s. Found %s.', $property, $expectedType, \gettype( $value ) ) );
}
}

View File

@@ -1,27 +0,0 @@
<?php
namespace Yoast\WHIPv2\Exceptions;
use Exception;
/**
* Exception for an invalid version comparison string.
*
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded -- Name should be descriptive and was historically (before namespacing) already set to this.
*/
class InvalidVersionComparisonString extends Exception {
/**
* InvalidVersionComparisonString constructor.
*
* @param string $value The passed version comparison string.
*/
public function __construct( $value ) {
parent::__construct(
\sprintf(
'Invalid version comparison string. Example of a valid version comparison string: >=5.3. Passed version comparison string: %s',
$value
)
);
}
}

View File

@@ -1,60 +0,0 @@
<?php
/**
* WHIP libary file.
*
* @package Yoast\WHIP
*/
use Yoast\WHIPv2\MessageDismisser;
use Yoast\WHIPv2\Presenters\WPMessagePresenter;
use Yoast\WHIPv2\RequirementsChecker;
use Yoast\WHIPv2\VersionRequirement;
use Yoast\WHIPv2\WPDismissOption;
if ( ! function_exists( 'whip_wp_check_versions' ) ) {
/**
* Facade to quickly check if version requirements are met.
*
* @param array<string> $requirements The requirements to check.
*
* @return void
*/
function whip_wp_check_versions( $requirements ) {
// Only show for admin users.
if ( ! is_array( $requirements ) ) {
return;
}
$config = include __DIR__ . '/../Configs/default.php';
$checker = new RequirementsChecker( $config );
foreach ( $requirements as $component => $versionComparison ) {
$checker->addRequirement( VersionRequirement::fromCompareString( $component, $versionComparison ) );
}
$checker->check();
if ( ! $checker->hasMessages() ) {
return;
}
$dismissThreshold = ( WEEK_IN_SECONDS * 4 );
$dismissMessage = __( 'Remind me again in 4 weeks.', 'default' );
$dismisser = new MessageDismisser( time(), $dismissThreshold, new WPDismissOption() );
$presenter = new WPMessagePresenter( $checker->getMostRecentMessage(), $dismisser, $dismissMessage );
// Prevent duplicate notices across multiple implementing plugins.
if ( ! has_action( 'whip_register_hooks' ) ) {
add_action( 'whip_register_hooks', array( $presenter, 'registerHooks' ) );
}
/**
* Fires during hooks registration for the message presenter.
*
* @param WPMessagePresenter $presenter Message presenter instance.
*/
do_action( 'whip_register_hooks', $presenter );
}
}

View File

@@ -1,107 +0,0 @@
<?php
namespace Yoast\WHIPv2;
/**
* Represents a host.
*/
class Host {
/**
* Key to an environment variable which should be set to the name of the host.
*
* @var string
*/
const HOST_NAME_KEY = 'WHIP_NAME_OF_HOST';
/**
* Filter name for the filter which allows for pointing to the WP hosting page instead of the Yoast version.
*
* @var string
*/
const HOSTING_PAGE_FILTER_KEY = 'whip_hosting_page_url_wordpress';
/**
* Retrieves the name of the host if set.
*
* @return string The name of the host.
*/
public static function name() {
$name = (string) \getenv( self::HOST_NAME_KEY );
return self::filterName( $name );
}
/**
* Filters the name if we are in a WordPress context.
* In a non-WordPress content this function just returns the passed name.
*
* @param string $name The current name of the host.
*
* @return string The filtered name of the host.
*/
private static function filterName( $name ) {
if ( \function_exists( 'apply_filters' ) ) {
return (string) \apply_filters( \strtolower( self::HOST_NAME_KEY ), $name );
}
return $name;
}
/**
* Retrieves the message from the host if set.
*
* @param string $messageKey The key to use as the environment variable.
*
* @return string The message as set by the host.
*/
public static function message( $messageKey ) {
$message = (string) \getenv( $messageKey );
return self::filterMessage( $messageKey, $message );
}
/**
* Filters the message if we are in a WordPress context.
* In a non-WordPress content this function just returns the passed message.
*
* @param string $messageKey The key used for the environment variable.
* @param string $message The current message from the host.
*
* @return string
*/
private static function filterMessage( $messageKey, $message ) {
if ( \function_exists( 'apply_filters' ) ) {
return (string) \apply_filters( \strtolower( $messageKey ), $message );
}
return $message;
}
/**
* Returns the URL for the hosting page.
*
* @return string The URL to the hosting overview page.
*/
public static function hostingPageUrl() {
$url = 'https://yoa.st/w3';
return self::filterHostingPageUrl( $url );
}
/**
* Filters the hosting page url if we are in a WordPress context.
* In a non-WordPress context this function just returns a link to the Yoast hosting page.
*
* @param string $url The previous URL.
*
* @return string The new URL to the hosting overview page.
*/
private static function filterHostingPageUrl( $url ) {
if ( \function_exists( 'apply_filters' ) && \apply_filters( self::HOSTING_PAGE_FILTER_KEY, false ) ) {
return 'https://wordpress.org/hosting/';
}
return $url;
}
}

View File

@@ -1,25 +0,0 @@
<?php
namespace Yoast\WHIPv2\Interfaces;
/**
* Interface DismissStorage.
*/
interface DismissStorage {
/**
* Saves the value.
*
* @param int $dismissedValue The value to save.
*
* @return bool True when successful.
*/
public function set( $dismissedValue );
/**
* Returns the value.
*
* @return int The stored value.
*/
public function get();
}

View File

@@ -1,16 +0,0 @@
<?php
namespace Yoast\WHIPv2\Interfaces;
/**
* Interface Listener.
*/
interface Listener {
/**
* Method that should implement the listen functionality.
*
* @return void
*/
public function listen();
}

View File

@@ -1,16 +0,0 @@
<?php
namespace Yoast\WHIPv2\Interfaces;
/**
* Interface Message.
*/
interface Message {
/**
* Retrieves the message body.
*
* @return string Message.
*/
public function body();
}

View File

@@ -1,16 +0,0 @@
<?php
namespace Yoast\WHIPv2\Interfaces;
/**
* Interface MessagePresenter.
*/
interface MessagePresenter {
/**
* Renders the message.
*
* @return void
*/
public function renderMessage();
}

View File

@@ -1,30 +0,0 @@
<?php
namespace Yoast\WHIPv2\Interfaces;
/**
* Interface Requirement.
*/
interface Requirement {
/**
* Retrieves the component name defined for the requirement.
*
* @return string The component name.
*/
public function component();
/**
* Gets the components version defined for the requirement.
*
* @return string
*/
public function version();
/**
* Gets the operator to use when comparing version numbers.
*
* @return string The comparison operator.
*/
public function operator();
}

View File

@@ -1,23 +0,0 @@
<?php
namespace Yoast\WHIPv2\Interfaces;
/**
* An interface that represents a version detector and message.
*/
interface VersionDetector {
/**
* Detects the version of the installed software.
*
* @return string
*/
public function detect();
/**
* Returns the message that should be shown if a version is not deemed appropriate by the implementation.
*
* @return string
*/
public function getMessage();
}

View File

@@ -1,75 +0,0 @@
<?php
namespace Yoast\WHIPv2;
use Yoast\WHIPv2\Interfaces\DismissStorage;
/**
* A class to dismiss messages.
*/
class MessageDismisser {
/**
* Storage object to manage the dismissal state.
*
* @var DismissStorage
*/
protected $storage;
/**
* The current time.
*
* @var int
*/
protected $currentTime;
/**
* The number of seconds the message will be dismissed.
*
* @var int
*/
protected $threshold;
/**
* MessageDismisser constructor.
*
* @param int $currentTime The current time.
* @param int $threshold The number of seconds the message will be dismissed.
* @param DismissStorage $storage Storage object to manage the dismissal state.
*/
public function __construct( $currentTime, $threshold, DismissStorage $storage ) {
$this->currentTime = $currentTime;
$this->threshold = $threshold;
$this->storage = $storage;
}
/**
* Saves the version number to the storage to indicate the message as being dismissed.
*
* @return void
*/
public function dismiss() {
$this->storage->set( $this->currentTime );
}
/**
* Checks if the current time is lower than the stored time extended by the threshold.
*
* @return bool True when current time is lower than stored value + threshold.
*/
public function isDismissed() {
return ( $this->currentTime <= ( $this->storage->get() + $this->threshold ) );
}
/**
* Checks the nonce.
*
* @param string $nonce The nonce to check.
* @param string $action The action to check.
*
* @return bool True when the nonce is valid.
*/
public function verifyNonce( $nonce, $action ) {
return (bool) \wp_verify_nonce( $nonce, $action );
}
}

View File

@@ -1,42 +0,0 @@
<?php
namespace Yoast\WHIPv2;
/**
* A helper class to format messages.
*/
final class MessageFormatter {
/**
* Wraps a piece of text in HTML strong tags.
*
* @param string $toWrap The text to wrap.
*
* @return string The wrapped text.
*/
public static function strong( $toWrap ) {
return '<strong>' . $toWrap . '</strong>';
}
/**
* Wraps a piece of text in HTML p tags.
*
* @param string $toWrap The text to wrap.
*
* @return string The wrapped text.
*/
public static function paragraph( $toWrap ) {
return '<p>' . $toWrap . '</p>';
}
/**
* Wraps a piece of text in HTML p and strong tags.
*
* @param string $toWrap The text to wrap.
*
* @return string The wrapped text.
*/
public static function strongParagraph( $toWrap ) {
return self::paragraph( self::strong( $toWrap ) );
}
}

View File

@@ -1,60 +0,0 @@
<?php
namespace Yoast\WHIPv2\Messages;
use Yoast\WHIPv2\Exceptions\EmptyProperty;
use Yoast\WHIPv2\Exceptions\InvalidType;
use Yoast\WHIPv2\Interfaces\Message;
/**
* Class BasicMessage.
*/
class BasicMessage implements Message {
/**
* Message body.
*
* @var string
*/
private $body;
/**
* Message constructor.
*
* @param string $body Message body.
*/
public function __construct( $body ) {
$this->validateParameters( $body );
$this->body = $body;
}
/**
* Retrieves the message body.
*
* @return string Message.
*/
public function body() {
return $this->body;
}
/**
* Validates the parameters passed to the constructor of this class.
*
* @param string $body Message body.
*
* @return void
*
* @throws EmptyProperty When the $body parameter is empty.
* @throws InvalidType When the $body parameter is not of the expected type.
*/
private function validateParameters( $body ) {
if ( empty( $body ) ) {
throw new EmptyProperty( 'Message body' );
}
if ( ! \is_string( $body ) ) {
throw new InvalidType( 'Message body', $body, 'string' );
}
}
}

View File

@@ -1,62 +0,0 @@
<?php
namespace Yoast\WHIPv2\Messages;
use Yoast\WHIPv2\Host;
use Yoast\WHIPv2\Interfaces\Message;
use Yoast\WHIPv2\MessageFormatter;
/**
* Class HostMessage.
*/
class HostMessage implements Message {
/**
* Text domain to use for translations.
*
* @var string
*/
private $textdomain;
/**
* The environment key to use to retrieve the message from.
*
* @var string
*/
private $messageKey;
/**
* Message constructor.
*
* @param string $messageKey The environment key to use to retrieve the message from.
* @param string $textdomain The text domain to use for translations.
*/
public function __construct( $messageKey, $textdomain ) {
$this->textdomain = $textdomain;
$this->messageKey = $messageKey;
}
/**
* Retrieves the message body.
*
* @return string The message body.
*/
public function body() {
$message = array();
$message[] = MessageFormatter::strong( $this->title() ) . '<br />';
$message[] = MessageFormatter::paragraph( Host::message( $this->messageKey ) );
return \implode( "\n", $message );
}
/**
* Renders the message title.
*
* @return string The message title.
*/
public function title() {
/* translators: 1: name. */
return \sprintf( \__( 'A message from %1$s', $this->textdomain ), Host::name() );
}
}

View File

@@ -1,53 +0,0 @@
<?php
namespace Yoast\WHIPv2\Messages;
use Yoast\WHIPv2\Interfaces\Message;
use Yoast\WHIPv2\VersionRequirement;
/**
* Class Whip_InvalidVersionMessage.
*
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded -- Name should be descriptive and was historically (before namespacing) already set to this.
*/
class InvalidVersionRequirementMessage implements Message {
/**
* Object containing the version requirement for a component.
*
* @var VersionRequirement
*/
private $requirement;
/**
* Detected version requirement or -1 if not found.
*
* @var string|int
*/
private $detected;
/**
* InvalidVersionRequirementMessage constructor.
*
* @param VersionRequirement $requirement Object containing the version requirement for a component.
* @param string|int $detected Detected version requirement or -1 if not found.
*/
public function __construct( VersionRequirement $requirement, $detected ) {
$this->requirement = $requirement;
$this->detected = $detected;
}
/**
* Retrieves the message body.
*
* @return string Message.
*/
public function body() {
return \sprintf(
'Invalid version detected for %s. Found %s but expected %s.',
$this->requirement->component(),
$this->detected,
$this->requirement->version()
);
}
}

View File

@@ -1,20 +0,0 @@
<?php
namespace Yoast\WHIPv2\Messages;
use Yoast\WHIPv2\Interfaces\Message;
/**
* Class NullMessage.
*/
class NullMessage implements Message {
/**
* Retrieves the message body.
*
* @return string Message.
*/
public function body() {
return '';
}
}

View File

@@ -1,87 +0,0 @@
<?php
namespace Yoast\WHIPv2\Messages;
use Yoast\WHIPv2\Host;
use Yoast\WHIPv2\Interfaces\Message;
use Yoast\WHIPv2\MessageFormatter;
/**
* Class UpgradePhpMessage
*/
class UpgradePhpMessage implements Message {
/**
* The text domain to use for the translations.
*
* @var string
*/
private $textdomain;
/**
* UpgradePhpMessage constructor.
*
* @param string $textdomain The text domain to use for the translations.
*/
public function __construct( $textdomain ) {
$this->textdomain = $textdomain;
}
/**
* Retrieves the message body to display.
*
* @return string The message to display.
*/
public function body() {
$textdomain = $this->textdomain;
$message = array();
$message[] = MessageFormatter::strongParagraph( \__( 'Your site could be faster and more secure with a newer PHP version.', $textdomain ) ) . '<br />';
$message[] = MessageFormatter::paragraph( \__( 'Hey, we\'ve noticed that you\'re running an outdated version of PHP. PHP is the programming language that WordPress and all its plugins and themes are built on. The version that is currently used for your site is no longer supported. Newer versions of PHP are both faster and more secure. In fact, your version of PHP no longer receives security updates, which is why we\'re sending you to this notice.', $textdomain ) );
$message[] = MessageFormatter::paragraph( \__( 'Hosts have the ability to update your PHP version, but sometimes they don\'t dare to do that because they\'re afraid they\'ll break your site.', $textdomain ) );
$message[] = MessageFormatter::strongParagraph( \__( 'To which version should I update?', $textdomain ) ) . '<br />';
$message[] = MessageFormatter::paragraph(
\sprintf(
/* translators: 1: link open tag; 2: link close tag. */
\__( 'You should update your PHP version to either 5.6 or to 7.0 or 7.1. On a normal WordPress site, switching to PHP 5.6 should never cause issues. We would however actually recommend you switch to PHP7. There are some plugins that are not ready for PHP7 though, so do some testing first. We have an article on how to test whether that\'s an option for you %1$shere%2$s. PHP7 is much faster than PHP 5.6. It\'s also the only PHP version still in active development and therefore the better option for your site in the long run.', $textdomain ),
'<a href="https://yoa.st/wg" target="_blank">',
'</a>'
)
);
if ( Host::name() !== '' ) {
$hostMessage = new HostMessage( 'WHIP_MESSAGE_FROM_HOST_ABOUT_PHP', $textdomain );
$message[] = $hostMessage->body();
}
$hostingPageUrl = Host::hostingPageUrl();
$message[] = MessageFormatter::strongParagraph( \__( 'Can\'t update? Ask your host!', $textdomain ) ) . '<br />';
if ( \function_exists( 'apply_filters' ) && \apply_filters( Host::HOSTING_PAGE_FILTER_KEY, false ) ) {
$message[] = MessageFormatter::paragraph(
\sprintf(
/* translators: 1: link open tag; 2: link close tag; 3: link open tag. */
\__( 'If you cannot upgrade your PHP version yourself, you can send an email to your host. We have %1$sexamples here%2$s. If they don\'t want to upgrade your PHP version, we would suggest you switch hosts. Have a look at one of the recommended %3$sWordPress hosting partners%2$s.', $textdomain ),
'<a href="https://yoa.st/wh" target="_blank">',
'</a>',
\sprintf( '<a href="%1$s" target="_blank">', \esc_url( $hostingPageUrl ) )
)
);
}
else {
$message[] = MessageFormatter::paragraph(
\sprintf(
/* translators: 1: link open tag; 2: link close tag; 3: link open tag. */
\__( 'If you cannot upgrade your PHP version yourself, you can send an email to your host. We have %1$sexamples here%2$s. If they don\'t want to upgrade your PHP version, we would suggest you switch hosts. Have a look at one of our recommended %3$sWordPress hosting partners%2$s, they\'ve all been vetted by the Yoast support team and provide all the features a modern host should provide.', $textdomain ),
'<a href="https://yoa.st/wh" target="_blank">',
'</a>',
\sprintf( '<a href="%1$s" target="_blank">', \esc_url( $hostingPageUrl ) )
)
);
}
return \implode( "\n", $message );
}
}

View File

@@ -1,91 +0,0 @@
<?php
namespace Yoast\WHIPv2;
use Yoast\WHIPv2\Interfaces\Message;
use Yoast\WHIPv2\Messages\NullMessage;
/**
* Manages messages using a global to prevent duplicate messages.
*/
class MessagesManager {
/**
* MessagesManager constructor.
*/
public function __construct() {
if ( ! \array_key_exists( 'whip_messages', $GLOBALS ) ) {
$GLOBALS['whip_messages'] = array();
}
}
/**
* Adds a message to the Messages Manager.
*
* @param Message $message The message to add.
*
* @return void
*/
public function addMessage( Message $message ) {
$whipVersion = require __DIR__ . '/Configs/version.php';
$GLOBALS['whip_messages'][ $whipVersion ] = $message;
}
/**
* Determines whether or not there are messages available.
*
* @return bool Whether or not there are messages available.
*/
public function hasMessages() {
return isset( $GLOBALS['whip_messages'] ) && \count( $GLOBALS['whip_messages'] ) > 0;
}
/**
* Lists the messages that are currently available.
*
* @return array<Message> The messages that are currently set.
*/
public function listMessages() {
return $GLOBALS['whip_messages'];
}
/**
* Deletes all messages.
*
* @return void
*/
public function deleteMessages() {
unset( $GLOBALS['whip_messages'] );
}
/**
* Gets the latest message.
*
* @return Message The message. Returns a NullMessage if none is found.
*/
public function getLatestMessage() {
if ( ! $this->hasMessages() ) {
return new NullMessage();
}
$messages = $this->sortByVersion( $this->listMessages() );
$this->deleteMessages();
return \array_pop( $messages );
}
/**
* Sorts the list of messages based on the version number.
*
* @param array<Message> $messages The list of messages to sort.
*
* @return array<Message> The sorted list of messages.
*/
private function sortByVersion( array $messages ) {
\uksort( $messages, 'version_compare' );
return $messages;
}
}

View File

@@ -1,112 +0,0 @@
<?php
namespace Yoast\WHIPv2\Presenters;
use Yoast\WHIPv2\Interfaces\Message;
use Yoast\WHIPv2\Interfaces\MessagePresenter;
use Yoast\WHIPv2\MessageDismisser;
use Yoast\WHIPv2\WPMessageDismissListener;
/**
* A message presenter to show a WordPress notice.
*
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded -- Sniff does not count acronyms correctly.
*/
class WPMessagePresenter implements MessagePresenter {
/**
* The string to show to dismiss the message.
*
* @var string
*/
private $dismissMessage;
/**
* The message to be displayed.
*
* @var Message
*/
private $message;
/**
* Dismisser object.
*
* @var MessageDismisser
*/
private $dismisser;
/**
* WPMessagePresenter constructor.
*
* @param Message $message The message to use in the presenter.
* @param MessageDismisser $dismisser Dismisser object.
* @param string $dismissMessage The copy to show to dismiss the message.
*/
public function __construct( Message $message, MessageDismisser $dismisser, $dismissMessage ) {
$this->message = $message;
$this->dismisser = $dismisser;
$this->dismissMessage = $dismissMessage;
}
/**
* Registers hooks to WordPress.
*
* This is a separate function so you can control when the hooks are registered.
*
* @return void
*/
public function registerHooks() {
\add_action( 'admin_notices', array( $this, 'renderMessage' ) );
}
/**
* Renders the messages present in the global to notices.
*
* @return void
*/
public function renderMessage() {
$dismissListener = new WPMessageDismissListener( $this->dismisser );
$dismissListener->listen();
if ( $this->dismisser->isDismissed() ) {
return;
}
$dismissButton = \sprintf(
'<a href="%2$s">%1$s</a>',
\esc_html( $this->dismissMessage ),
\esc_url( $dismissListener->getDismissURL() )
);
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped -- output correctly escaped directly above and in the `kses()` method.
\printf(
'<div class="error"><p>%1$s</p><p>%2$s</p></div>',
$this->kses( $this->message->body() ),
$dismissButton
);
// phpcs:enable
}
/**
* Removes content from the message that we don't want to show.
*
* @param string $message The message to clean.
*
* @return string The cleaned message.
*/
public function kses( $message ) {
return \wp_kses(
$message,
array(
'a' => array(
'href' => true,
'target' => true,
),
'strong' => true,
'p' => true,
'ul' => true,
'li' => true,
)
);
}
}

View File

@@ -1,181 +0,0 @@
<?php
namespace Yoast\WHIPv2;
use Yoast\WHIPv2\Exceptions\InvalidType;
use Yoast\WHIPv2\Interfaces\Message;
use Yoast\WHIPv2\Interfaces\Requirement;
use Yoast\WHIPv2\Messages\InvalidVersionRequirementMessage;
use Yoast\WHIPv2\Messages\UpgradePhpMessage;
/**
* Main controller class to require a certain version of software.
*/
class RequirementsChecker {
/**
* Requirements the environment should comply with.
*
* @var array<Requirement>
*/
private $requirements;
/**
* The configuration to check.
*
* @var Configuration
*/
private $configuration;
/**
* Message Manager.
*
* @var MessagesManager
*/
private $messageManager;
/**
* The text domain to use for translations.
*
* @var string
*/
private $textdomain;
/**
* RequirementsChecker constructor.
*
* @param array<string, string> $configuration The configuration to check.
* @param string $textdomain The text domain to use for translations.
*
* @throws InvalidType When the $configuration parameter is not of the expected type.
*/
public function __construct( $configuration = array(), $textdomain = 'default' ) {
$this->requirements = array();
$this->configuration = new Configuration( $configuration );
$this->messageManager = new MessagesManager();
$this->textdomain = $textdomain;
}
/**
* Adds a requirement to the list of requirements if it doesn't already exist.
*
* @param Requirement $requirement The requirement to add.
*
* @return void
*/
public function addRequirement( Requirement $requirement ) {
// Only allow unique entries to ensure we're not checking specific combinations multiple times.
if ( $this->requirementExistsForComponent( $requirement->component() ) ) {
return;
}
$this->requirements[] = $requirement;
}
/**
* Determines whether or not there are requirements available.
*
* @return bool Whether or not there are requirements.
*/
public function hasRequirements() {
return $this->totalRequirements() > 0;
}
/**
* Gets the total amount of requirements.
*
* @return int The total amount of requirements.
*/
public function totalRequirements() {
return \count( $this->requirements );
}
/**
* Determines whether or not a requirement exists for a particular component.
*
* @param string $component The component to check for.
*
* @return bool Whether or not the component has a requirement defined.
*/
public function requirementExistsForComponent( $component ) {
foreach ( $this->requirements as $requirement ) {
if ( $requirement->component() === $component ) {
return true;
}
}
return false;
}
/**
* Determines whether a requirement has been fulfilled.
*
* @param Requirement $requirement The requirement to check.
*
* @return bool Whether or not the requirement is fulfilled.
*/
private function requirementIsFulfilled( Requirement $requirement ) {
$availableVersion = $this->configuration->configuredVersion( $requirement );
$requiredVersion = $requirement->version();
if ( \in_array( $requirement->operator(), array( '=', '==', '===' ), true ) ) {
return \version_compare( $availableVersion, $requiredVersion, '>=' );
}
return \version_compare( $availableVersion, $requiredVersion, $requirement->operator() );
}
/**
* Checks if all requirements are fulfilled and adds a message to the message manager if necessary.
*
* @return void
*/
public function check() {
foreach ( $this->requirements as $requirement ) {
// Match against config.
$requirementFulfilled = $this->requirementIsFulfilled( $requirement );
if ( $requirementFulfilled ) {
continue;
}
$this->addMissingRequirementMessage( $requirement );
}
}
/**
* Adds a message to the message manager for requirements that cannot be fulfilled.
*
* @param Requirement $requirement The requirement that cannot be fulfilled.
*
* @return void
*/
private function addMissingRequirementMessage( Requirement $requirement ) {
switch ( $requirement->component() ) {
case 'php':
$this->messageManager->addMessage( new UpgradePhpMessage( $this->textdomain ) );
break;
default:
$this->messageManager->addMessage( new InvalidVersionRequirementMessage( $requirement, $this->configuration->configuredVersion( $requirement ) ) );
break;
}
}
/**
* Determines whether or not there are messages available.
*
* @return bool Whether or not there are messages to display.
*/
public function hasMessages() {
return $this->messageManager->hasMessages();
}
/**
* Gets the most recent message from the message manager.
*
* @return Message The latest message.
*/
public function getMostRecentMessage() {
return $this->messageManager->getLatestMessage();
}
}

View File

@@ -1,153 +0,0 @@
<?php
namespace Yoast\WHIPv2;
use Yoast\WHIPv2\Exceptions\EmptyProperty;
use Yoast\WHIPv2\Exceptions\InvalidOperatorType;
use Yoast\WHIPv2\Exceptions\InvalidType;
use Yoast\WHIPv2\Exceptions\InvalidVersionComparisonString;
use Yoast\WHIPv2\Interfaces\Requirement;
/**
* A value object containing a version requirement for a component version.
*/
class VersionRequirement implements Requirement {
/**
* The component name.
*
* @var string
*/
private $component;
/**
* The component version.
*
* @var string
*/
private $version;
/**
* The operator to use when comparing version.
*
* @var string
*/
private $operator;
/**
* Requirement constructor.
*
* @param string $component The component name.
* @param string $version The component version.
* @param string $operator The operator to use when comparing version.
*/
public function __construct( $component, $version, $operator = '=' ) {
$this->validateParameters( $component, $version, $operator );
$this->component = $component;
$this->version = $version;
$this->operator = $operator;
}
/**
* Retrieves the component name defined for the requirement.
*
* @return string The component name.
*/
public function component() {
return $this->component;
}
/**
* Gets the components version defined for the requirement.
*
* @return string
*/
public function version() {
return $this->version;
}
/**
* Gets the operator to use when comparing version numbers.
*
* @return string The comparison operator.
*/
public function operator() {
return $this->operator;
}
/**
* Creates a new version requirement from a comparison string.
*
* @param string $component The component for this version requirement.
* @param string $comparisonString The comparison string for this version requirement.
*
* @return VersionRequirement The parsed version requirement.
*
* @throws InvalidVersionComparisonString When an invalid version comparison string is passed.
*/
public static function fromCompareString( $component, $comparisonString ) {
$matcher = '`
(
>=? # Matches >= and >.
|
<=? # Matches <= and <.
)
([^>=<\s]+) # Matches anything except >, <, =, and whitespace.
`x';
if ( ! \preg_match( $matcher, $comparisonString, $match ) ) {
throw new InvalidVersionComparisonString( $comparisonString );
}
$version = $match[2];
$operator = $match[1];
return new VersionRequirement( $component, $version, $operator );
}
/**
* Validates the parameters passed to the requirement.
*
* @param string $component The component name.
* @param string $version The component version.
* @param string $operator The operator to use when comparing version.
*
* @return void
*
* @throws EmptyProperty When any of the parameters is empty.
* @throws InvalidOperatorType When the $operator parameter is invalid.
* @throws InvalidType When any of the parameters is not of the expected type.
*/
private function validateParameters( $component, $version, $operator ) {
if ( empty( $component ) ) {
throw new EmptyProperty( 'Component' );
}
if ( ! \is_string( $component ) ) {
throw new InvalidType( 'Component', $component, 'string' );
}
if ( empty( $version ) ) {
throw new EmptyProperty( 'Version' );
}
if ( ! \is_string( $version ) ) {
throw new InvalidType( 'Version', $version, 'string' );
}
if ( empty( $operator ) ) {
throw new EmptyProperty( 'Operator' );
}
if ( ! \is_string( $operator ) ) {
throw new InvalidType( 'Operator', $operator, 'string' );
}
$validOperators = array( '=', '==', '===', '<', '>', '<=', '>=' );
if ( ! \in_array( $operator, $validOperators, true ) ) {
throw new InvalidOperatorType( $operator, $validOperators );
}
}
}

View File

@@ -1,45 +0,0 @@
<?php
namespace Yoast\WHIPv2;
use Yoast\WHIPv2\Interfaces\DismissStorage;
/**
* Represents the WordPress option for saving the dismissed messages.
*
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded -- Sniff does not count acronyms correctly.
*/
class WPDismissOption implements DismissStorage {
/**
* WordPress option name.
*
* @var string
*/
protected $optionName = 'whip_dismiss_timestamp';
/**
* Saves the value to the options.
*
* @param int $dismissedValue The value to save.
*
* @return bool True when successful.
*/
public function set( $dismissedValue ) {
return \update_option( $this->optionName, $dismissedValue );
}
/**
* Returns the value of the whip_dismissed option.
*
* @return int Returns the value of the option or an empty string when not set.
*/
public function get() {
$dismissedOption = \get_option( $this->optionName );
if ( ! $dismissedOption ) {
return 0;
}
return (int) $dismissedOption;
}
}

View File

@@ -1,66 +0,0 @@
<?php
namespace Yoast\WHIPv2;
use Yoast\WHIPv2\Interfaces\Listener;
/**
* Listener for dismissing a message.
*
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded -- Sniff does not count acronyms correctly.
*/
class WPMessageDismissListener implements Listener {
/**
* The name of the dismiss action expected to be passed via $_GET.
*
* @var string
*/
const ACTION_NAME = 'whip_dismiss';
/**
* The object for dismissing a message.
*
* @var MessageDismisser
*/
protected $dismisser;
/**
* Sets the dismisser attribute.
*
* @param MessageDismisser $dismisser The object for dismissing a message.
*/
public function __construct( MessageDismisser $dismisser ) {
$this->dismisser = $dismisser;
}
/**
* Listens to a GET request to fetch the required attributes.
*
* @return void
*/
public function listen() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce is verified in the dismisser.
$action = ( isset( $_GET['action'] ) && \is_string( $_GET['action'] ) ) ? \sanitize_text_field( \wp_unslash( $_GET['action'] ) ) : null;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce is verified in the dismisser.
$nonce = ( isset( $_GET['nonce'] ) && \is_string( $_GET['nonce'] ) ) ? \sanitize_text_field( \wp_unslash( $_GET['nonce'] ) ) : '';
if ( $action === self::ACTION_NAME && $this->dismisser->verifyNonce( $nonce, self::ACTION_NAME ) ) {
$this->dismisser->dismiss();
}
}
/**
* Creates an url for dismissing the notice.
*
* @return string The url for dismissing the message.
*/
public function getDismissURL() {
return \sprintf(
\admin_url( 'index.php?action=%1$s&nonce=%2$s' ),
self::ACTION_NAME,
\wp_create_nonce( self::ACTION_NAME )
);
}
}