Σ(゚Д゚;≡;゚д゚)Σ(゚Д゚;≡;゚д゚)Σ(゚Д゚;≡;゚д゚)始,故人唐宰相鲁公,🆚开府南服,余以布衣从戎。明年,别公漳水湄。后明年,公以事过张睢阳庙及颜杲卿所尝往来处,悲歌慷慨,卒不负其言而从之游。今其诗具在,可考也。😭
health-check/postname-permalink-runner.php 0000644 00000001613 15233532001 0014705 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Runs the Postname_Permalink health check.
*/
class Postname_Permalink_Runner implements Runner_Interface {
/**
* Is set to true when permalinks are set to contain the post name
*
* @var bool
*/
private $permalinks_contain_postname;
/**
* Constructor.
*/
public function __construct() {
$this->permalinks_contain_postname = false;
}
/**
* Runs the health check. Checks if permalinks are set to contain the post name.
*
* @return void
*/
public function run() {
$this->permalinks_contain_postname = ( strpos( get_option( 'permalink_structure' ), '%postname%' ) !== false );
}
/**
* Returns true if permalinks are set to contain the post name.
*
* @return bool True if permalinks are set to contain the post name.
*/
public function is_successful() {
return $this->permalinks_contain_postname;
}
}
health-check/default-tagline-reports.php 0000644 00000004242 15233532001 0014332 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Presents a set of different messages for the Default_Tagline health check.
*/
class Default_Tagline_Reports {
use Reports_Trait;
/**
* Constructor
*
* @param Report_Builder_Factory $report_builder_factory The factory for result builder objects. This class uses the report builder to generate WordPress-friendly health check results.
* @return void
*/
public function __construct( Report_Builder_Factory $report_builder_factory ) {
$this->report_builder_factory = $report_builder_factory;
}
/**
* Returns the message for a successful health check.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_success_result() {
return $this->get_report_builder()
->set_label( \__( 'You changed the default WordPress tagline', 'wordpress-seo' ) )
->set_status_good()
->set_description( \__( 'You are using a custom tagline or an empty one.', 'wordpress-seo' ) )
->build();
}
/**
* Returns the message for a failed health check. In this case, when the user still has the default WordPress tagline set.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_has_default_tagline_result() {
return $this->get_report_builder()
->set_label( \__( 'You should change the default WordPress tagline', 'wordpress-seo' ) )
->set_status_recommended()
->set_description( \__( 'You still have the default WordPress tagline. Even an empty one is probably better.', 'wordpress-seo' ) )
->set_actions( $this->get_actions() )
->build();
}
/**
* Returns the actions that the user should take when his tagline is still set to the WordPress default.
*
* @return string The actions as an HTML string.
*/
private function get_actions() {
$query_args = [
'autofocus[control]' => 'blogdescription',
];
$customize_url = \add_query_arg( $query_args, \wp_customize_url() );
return \sprintf(
/* translators: 1: link open tag; 2: link close tag. */
\esc_html__( '%1$sYou can change the tagline in the customizer%2$s.', 'wordpress-seo' ),
'<a href="' . \esc_url( $customize_url ) . '">',
'</a>'
);
}
}
health-check/page-comments-check.php 0000644 00000002633 15233532001 0013405 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Paasses when comments are set to be on a single page.
*/
class Page_Comments_Check extends Health_Check {
/**
* Runs the health check.
*
* @var Page_Comments_Runner
*/
private $runner;
/**
* Generates WordPress-friendly health check results.
*
* @var Page_Comments_Reports
*/
private $reports;
/**
* Constructor.
*
* @param Page_Comments_Runner $runner The object that implements the actual health check.
* @param Page_Comments_Reports $reports The object that generates WordPress-friendly results.
* @return void
*/
public function __construct(
Page_Comments_Runner $runner,
Page_Comments_Reports $reports
) {
$this->runner = $runner;
$this->reports = $reports;
$this->reports->set_test_identifier( $this->get_test_identifier() );
$this->set_runner( $this->runner );
}
/**
* Returns a human-readable label for this health check.
*
* @return string The human-readable label.
*/
public function get_test_label() {
return __( 'Page comments', 'wordpress-seo' );
}
/**
* Returns the WordPress-friendly health check result.
*
* @return string[] The WordPress-friendly health check result.
*/
protected function get_result() {
if ( $this->runner->is_successful() ) {
return $this->reports->get_success_result();
}
return $this->reports->get_has_comments_on_multiple_pages_result();
}
}
health-check/default-tagline-runner.php 0000644 00000002156 15233532001 0014147 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Runs the Default_Tagline health check.
*/
class Default_Tagline_Runner implements Runner_Interface {
/**
* The default WordPress tagline.
*/
const DEFAULT_BLOG_DESCRIPTION = 'Just another WordPress site';
/**
* Is set to true when the default tagline is set.
*
* @var bool
*/
private $has_default_tagline = true;
/**
* Runs the health check. Checks if the tagline is set to WordPress' default tagline, or to its set translation.
*
* @return void
*/
public function run() {
$blog_description = \get_option( 'blogdescription' );
// We are using the WordPress internal translation.
$translated_blog_description = \__( 'Just another WordPress site', 'default' );
$this->has_default_tagline = $translated_blog_description === $blog_description || $blog_description === self::DEFAULT_BLOG_DESCRIPTION;
}
/**
* Returns true if the tagline is set to a non-default tagline.
*
* @return bool The boolean indicating if the health check was succesful.
*/
public function is_successful() {
return ! $this->has_default_tagline;
}
}
health-check/curl-check.php 0000644 00000003225 15233532001 0011611 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Passes if the health check can reach the MyYoast API using a recent enough cURL version.
*/
class Curl_Check extends Health_Check {
/**
* Runs the health check.
*
* @var Curl_Runner
*/
private $runner;
/**
* Generates WordPress-friendly health check results.
*
* @var Curl_Reports
*/
private $reports;
/**
* Constructor.
*
* @param Curl_Runner $runner The object that implements the actual health check.
* @param Curl_Reports $reports The object that generates WordPress-friendly results.
* @return void
*/
public function __construct(
Curl_Runner $runner,
Curl_Reports $reports
) {
$this->runner = $runner;
$this->reports = $reports;
$this->reports->set_test_identifier( $this->get_test_identifier() );
$this->set_runner( $this->runner );
}
/**
* Returns a human-readable label for this health check.
*
* @return string The human-readable label.
*/
public function get_test_label() {
return __( 'cURL', 'wordpress-seo' );
}
/**
* Returns the WordPress-friendly health check result.
*
* @return string[] The WordPress-friendly health check result.
*/
protected function get_result() {
if ( ! $this->runner->has_premium_plugins_installed() ) {
return [];
}
if ( $this->runner->is_successful() ) {
return $this->reports->get_success_result();
}
if ( ! $this->runner->has_recent_curl_version_installed() ) {
return $this->reports->get_no_recent_curl_version_installed_result();
}
if ( ! $this->runner->can_reach_my_yoast_api() ) {
return $this->reports->get_my_yoast_api_not_reachable_result();
}
return [];
}
}
health-check/report-builder.php 0000644 00000011642 15233532001 0012532 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Provides an interface to build WordPress-friendly health check results.
*/
class Report_Builder {
/**
* Passed health check.
*/
const STATUS_GOOD = 'good';
/**
* Changes are recommended but not necessary.
*/
const STATUS_RECOMMENDED = 'recommended';
/**
* Significant issues that the user should consider fixing.
*/
const STATUS_CRITICAL = 'critical';
/**
* The user-facing label.
*
* @var string
*/
private $label = '';
/**
* The identifier that WordPress uses for the health check.
*
* @var string
*/
private $test_identifier = '';
/**
* The test status (good, recommended, critical).
*
* @var string
*/
private $status = '';
/**
* The short description for the result.
*
* @var string
*/
private $description = '';
/**
* Actions that the user can take to solve the health check result.
*
* @var string
*/
private $actions = '';
/**
* Sets the label for the health check that the user can see.
*
* @param string $label The label that the user can see.
* @return Report_Builder This builder.
*/
public function set_label( $label ) {
$this->label = $label;
return $this;
}
/**
* Sets the name for the test that the plugin uses to identify the test.
*
* @param string $test_identifier The identifier for the health check.
* @return Report_Builder This builder.
*/
public function set_test_identifier( $test_identifier ) {
$this->test_identifier = $test_identifier;
return $this;
}
/**
* Sets the status of the test result to GOOD (green label).
*
* @return Report_Builder This builder.
*/
public function set_status_good() {
$this->status = self::STATUS_GOOD;
return $this;
}
/**
* Sets the status of the test result to RECOMMENDED (orange label).
*
* @return Report_Builder This builder.
*/
public function set_status_recommended() {
$this->status = self::STATUS_RECOMMENDED;
return $this;
}
/**
* Sets the status of the test result to CRITICAL (red label).
*
* @return Report_Builder This builder.
*/
public function set_status_critical() {
$this->status = self::STATUS_CRITICAL;
return $this;
}
/**
* Sets a description for the test result. This will be the heading for the result in the user interface.
*
* @param string $description The description for the test result.
* @return Report_Builder This builder.
*/
public function set_description( $description ) {
$this->description = $description;
return $this;
}
/**
* Sets a text that describes how the user can solve the failed health check.
*
* @param string $actions The descriptive text.
* @return Report_Builder This builder.
*/
public function set_actions( $actions ) {
$this->actions = $actions;
return $this;
}
/**
* Builds an array of strings in the format that WordPress uses to display health checks (https://developer.wordpress.org/reference/hooks/site_status_test_result/).
*
* @return array The report in WordPress' site status report format.
*/
public function build() {
return [
'label' => $this->label,
'status' => $this->status,
'badge' => $this->get_badge(),
'description' => $this->description,
'actions' => $this->get_actions_with_signature(),
'test' => $this->test_identifier,
];
}
/**
* Generates a badge that the user can see.
*
* @return string[] The badge.
*/
private function get_badge() {
return [
'label' => $this->get_badge_label(),
'color' => $this->get_badge_color(),
];
}
/**
* Generates the label for a badge.
*
* @return string The badge label.
*/
private function get_badge_label() {
return \__( 'SEO', 'wordpress-seo' );
}
/**
* Generates the color for the badge using the current status.
*
* @return string The color for the badge's outline.
*/
private function get_badge_color() {
if ( $this->status === self::STATUS_CRITICAL || $this->status === self::STATUS_RECOMMENDED ) {
return 'red';
}
return 'blue';
}
/**
* Concatenates the set actions with Yoast's signature.
*
* @return string A string containing the set actions and Yoast's signature.
*/
private function get_actions_with_signature() {
return $this->actions . $this->get_signature();
}
/**
* Generates Yoast's signature that's displayed at the bottom of the health check result.
*
* @return string Yoast's signature as an HTML string.
*/
private function get_signature() {
return \sprintf(
/* translators: 1: Start of a paragraph beginning with the Yoast icon, 2: Expands to 'Yoast SEO', 3: Paragraph closing tag. */
\esc_html__( '%1$sThis was reported by the %2$s plugin%3$s', 'wordpress-seo' ),
'<p class="yoast-site-health__signature"><img src="' . \esc_url( \plugin_dir_url( \WPSEO_FILE ) . 'packages/js/images/Yoast_SEO_Icon.svg' ) . '" alt="" height="20" width="20" class="yoast-site-health__signature-icon">',
'Yoast SEO',
'</p>'
);
}
}
health-check/curl-runner.php 0000644 00000011201 15233532001 0012036 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
use WPSEO_Addon_Manager;
use Yoast\WP\SEO\Helpers\Curl_Helper;
/**
* Runs the Curl health check.
*/
class Curl_Runner implements Runner_Interface {
/**
* Sets the minimum cURL version for this health check to pass.
*/
const MINIMUM_CURL_VERSION = '7.34.0';
/**
* Sets the target URL for testing whether the MyYoast API is reachable.
*/
const MYYOAST_API_REQUEST_URL = 'sites/current';
/**
* True when cURL is installed.
*
* @var bool
*/
private $curl_installed = false;
/**
* True when cURL is equal to or more recent than MINIMUM_CURL_VERSION.
*
* @var bool
*/
private $curl_is_recent = false;
/**
* True when the health check got a response from the MyYoast API.
*
* @var bool
*/
private $got_my_yoast_api_response = false;
/**
* True when there are Yoast add-ons installed.
*
* @var bool
*/
private $has_installed_addons = false;
/**
* The add-on manger that the health check uses to determine if there are any add-ons installed.
*
* @var WPSEO_Addon_Manager
*/
private $addon_manager;
/**
* Factory for the MyYoast API request object that the health check uses to check if cURL works correctly.
*
* @var MyYoast_Api_Request_Factory
*/
private $my_yoast_api_request_factory;
/**
* The cURL helper from which the health check gets information about the installed cURL version.
*
* @var Curl_Helper
*/
private $curl_helper;
/**
* Constructor.
*
* @psalm-suppress InvalidClass MyYoast is a product name, so it's an exception to the class naming conventions.
* @param WPSEO_Addon_Manager $addon_manager The add-on manager.
* @param MyYoast_Api_Request_Factory $my_yoast_api_request_factory A MyYoast API request object.
* @param Curl_Helper $curl_helper A cURL helper object for obtaining cURL installation information.
*/
public function __construct(
WPSEO_Addon_Manager $addon_manager,
MyYoast_Api_Request_Factory $my_yoast_api_request_factory,
Curl_Helper $curl_helper
) {
$this->addon_manager = $addon_manager;
$this->my_yoast_api_request_factory = $my_yoast_api_request_factory;
$this->curl_helper = $curl_helper;
}
/**
* Runs the health check. Checks if cURL is installed and up to date, and if it's able to reach the MyYoast API
*
* @return void
*/
public function run() {
$this->check_has_installed_addons();
$this->check_curl_installed();
if ( ! $this->curl_installed ) {
return;
}
$this->check_curl_is_recent();
$this->check_can_reach_my_yoast_api();
}
/**
* Checks if there are installed Yoast add-ons.
*
* @return void
*/
private function check_has_installed_addons() {
$this->has_installed_addons = $this->addon_manager->has_installed_addons();
}
/**
* Checks if cURL is installed.
*
* @return void
*/
private function check_curl_installed() {
$this->curl_installed = $this->curl_helper->is_installed();
}
/**
* Checks if the installed cURL version is equal to or more recent than MINIMUM_CURL_VERSION.
*
* @return void
*/
private function check_curl_is_recent() {
$version = $this->curl_helper->get_version();
if ( $version === null ) {
$this->curl_is_recent = false;
return;
}
$this->curl_is_recent = version_compare( $version, self::MINIMUM_CURL_VERSION, '>=' );
}
/**
* Checks if cURL is able to reach the MyYoast API.
*
* @return void
*/
private function check_can_reach_my_yoast_api() {
$api_request = $this->my_yoast_api_request_factory->create( self::MYYOAST_API_REQUEST_URL );
$got_response = $api_request->fire();
$this->got_my_yoast_api_response = $got_response;
}
/**
* Returns whether the health check was successful.
*
* @return bool True if all the routines for this health check were successful.
*/
public function is_successful() {
return $this->has_installed_addons && $this->curl_is_recent && $this->got_my_yoast_api_response;
}
/**
* Returns whether there are premium plugins installed.
*
* @return bool True if there are premium plugins installed.
*/
public function has_premium_plugins_installed() {
return $this->has_installed_addons;
}
/**
* Returns whether cURL was able to reach the MyYoast API.
*
* @return bool True if cURL was able to reach the MyYoast API.
*/
public function can_reach_my_yoast_api() {
return $this->got_my_yoast_api_response;
}
/**
* Returns whether the installed cURL version is recent enough.
*
* @return bool True if the installed cURL version is more recent than MINIMUM_CURL_VERSION.
*/
public function has_recent_curl_version_installed() {
return $this->curl_is_recent;
}
}
health-check/ryte-runner.php 0000644 00000010701 15233532001 0012060 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
use WPSEO_Ryte_Option;
use WPSEO_Utils;
use Yoast\WP\SEO\Integrations\Admin\Ryte_Integration;
/**
* Runs the Ryte health check.
*/
class Ryte_Runner implements Runner_Interface {
/**
* The Ryte_Integration object that the health check uses to check the site's indexability.
*
* @var Ryte_Integration
*/
private $ryte;
/**
* Set to true when the health check gets a valid response from Ryte.
*
* @var bool
*/
private $got_valid_response;
/**
* The error that is set when the health check gets a response error from Ryte.
*
* @var array|null
*/
private $response_error;
/**
* The Ryte option that represents the site's indexability.
*
* @var WPSEO_Ryte_Option
*/
private $ryte_option;
/**
* The WPSEO_Utils class used to determine whether the site is in development mode.
*
* @var WPSEO_Utils
*/
private $utils;
/**
* Constructor.
*
* @param Ryte_Integration $ryte The Ryte_Integration object that the health check uses to check indexability.
* @param WPSEO_Utils $utils The WPSEO_Utils object used to determine whether the site is in development mode.
*/
public function __construct(
Ryte_Integration $ryte,
WPSEO_Utils $utils
) {
$this->ryte = $ryte;
$this->utils = $utils;
$this->got_valid_response = false;
$this->ryte_option = $ryte->get_option();
}
/**
* Runs the health check. Checks if Ryte is accessible and whether the site is indexable.
*
* @return void
*/
public function run() {
if ( ! $this->should_run() ) {
return;
}
$this->fetch_from_ryte();
if ( ! $this->got_valid_response ) {
return;
}
$this->set_ryte_option();
}
/**
* Attempts to get a new indexability status from Ryte.
*
* @return void
*/
private function fetch_from_ryte() {
$this->ryte->fetch_from_ryte();
$response = $this->ryte->get_response();
if ( is_array( $response ) && isset( $response['is_error'] ) ) {
$this->got_valid_response = false;
$this->response_error = $response;
return;
}
$this->got_valid_response = true;
}
/**
* Sets the Ryte option based on the response from Ryte.
*
* @return void
*/
private function set_ryte_option() {
$this->ryte_option = $this->ryte->get_option();
}
/**
* Checks if the site is a live production site that has Ryte enabled.
*
* @return bool
*/
public function should_run() {
if ( wp_get_environment_type() !== 'production' ) {
return false;
}
if ( wp_debug_mode() || $this->utils->is_development_mode() ) {
return false;
}
if ( get_option( 'blog_public' ) === '0' ) {
return false;
}
$ryte_option = $this->ryte->get_option();
if ( ! $ryte_option->is_enabled() ) {
return false;
}
return true;
}
/**
* Checks if the site is indexable.
*
* @return bool
*/
public function is_successful() {
if ( ! $this->could_fetch() ) {
return false;
}
$ryte_status = $this->ryte_option->get_status();
if ( $ryte_status === WPSEO_Ryte_Option::IS_INDEXABLE ) {
return true;
}
return false;
}
/**
* Checks if the site's indexability is unknown.
*
* @return bool Returns true if the site indexability is unknown even though getting a response from Ryte was successful.
*/
public function has_unknown_indexability() {
if ( ! $this->could_fetch() ) {
return true;
}
$ryte_status = $this->ryte_option->get_status();
if ( $ryte_status === WPSEO_Ryte_Option::IS_INDEXABLE ) {
return false;
}
if ( $ryte_status === WPSEO_Ryte_Option::IS_NOT_INDEXABLE ) {
return false;
}
// This return statement should never be reached.
return true;
}
/**
* Checks if the health check was able to get a valid response from Ryte.
*
* @return bool
*/
private function could_fetch() {
if ( ! $this->got_valid_response ) {
return false;
}
$ryte_status = $this->ryte_option->get_status();
if ( $ryte_status === WPSEO_Ryte_Option::CANNOT_FETCH ) {
return false;
}
return true;
}
/**
* Checks whether there was a response error when attempting a request to Ryte.
*
* @return bool True if the health check got a valid error response.
*/
public function got_response_error() {
return isset( $this->response_error );
}
/**
* Returns the error response is there was one.
*
* @return array|null
*/
public function get_error_response() {
if ( ! $this->got_response_error() ) {
return null;
}
return $this->response_error;
}
}
health-check/page-comments-reports.php 0000644 00000004412 15233532001 0014023 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Presents a set of different messages for the Page_Comments health check.
*/
class Page_Comments_Reports {
use Reports_Trait;
/**
* Constructor.
*
* @param Report_Builder_Factory $report_builder_factory The factory for result builder objects. This class uses the report builder to generate WordPress-friendly health check results.
*/
public function __construct( Report_Builder_Factory $report_builder_factory ) {
$this->report_builder_factory = $report_builder_factory;
}
/**
* Returns the report for when comments are set to be all on one page.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_success_result() {
return $this->get_report_builder()
->set_label( esc_html__( 'Comments are displayed on a single page', 'wordpress-seo' ) )
->set_status_good()
->set_description( __( 'Comments on your posts are displayed on a single page. This is just like we\'d suggest it. You\'re doing well!', 'wordpress-seo' ) )
->build();
}
/**
* Returns the report for when comments are set to be broken up across multiple pages.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_has_comments_on_multiple_pages_result() {
return $this->get_report_builder()
->set_label( __( 'Comments break into multiple pages', 'wordpress-seo' ) )
->set_status_recommended()
->set_description( __( 'Comments on your posts break into multiple pages. As this is not needed in 999 out of 1000 cases, we recommend you disable it. To fix this, uncheck "Break comments into pages..." on the Discussion Settings page.', 'wordpress-seo' ) )
->set_actions( $this->get_has_comments_on_multiple_pages_actions() )
->build();
}
/**
* Returns the actions for when the comments are set to be broken up across multiple pages.
*
* @return string The actions as a string.
*/
private function get_has_comments_on_multiple_pages_actions() {
return sprintf(
/* translators: 1: Opening tag of the link to the discussion settings page, 2: Link closing tag. */
esc_html__( '%1$sGo to the Discussion Settings page%2$s', 'wordpress-seo' ),
'<a href="' . esc_url( admin_url( 'options-discussion.php' ) ) . '">',
'</a>'
);
}
}
health-check/postname-permalink-check.php 0000644 00000002705 15233532001 0014454 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Paasses when permalinks are set to contain the post name.
*/
class Postname_Permalink_Check extends Health_Check {
/**
* Runs the health check.
*
* @var Postname_Permalink_Runner
*/
private $runner;
/**
* Generates WordPress-friendly health check results.
*
* @var Postname_Permalink_Reports
*/
private $reports;
/**
* Constructor.
*
* @param Postname_Permalink_Runner $runner The object that implements the actual health check.
* @param Postname_Permalink_Reports $reports The object that generates WordPress-friendly results.
* @return void
*/
public function __construct(
Postname_Permalink_Runner $runner,
Postname_Permalink_Reports $reports
) {
$this->runner = $runner;
$this->reports = $reports;
$this->reports->set_test_identifier( $this->get_test_identifier() );
$this->set_runner( $this->runner );
}
/**
* Returns a human-readable label for this health check.
*
* @return string The human-readable label.
*/
public function get_test_label() {
return __( 'Postname permalink', 'wordpress-seo' );
}
/**
* Returns the WordPress-friendly health check result.
*
* @return string[] The WordPress-friendly health check result.
*/
protected function get_result() {
if ( $this->runner->is_successful() ) {
return $this->reports->get_success_result();
}
return $this->reports->get_has_no_postname_in_permalink_result();
}
}
health-check/runner-interface.php 0000644 00000000425 15233532001 0013037 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Interface for the health check runner. The abstract Health_Check uses this to run a health check.
*/
interface Runner_Interface {
/**
* Runs the health check.
*
* @return void
*/
public function run();
}
health-check/reports-trait.php 0000644 00000001637 15233532001 0012415 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Used by classes that use a health check Report_Builder.
*/
trait Reports_Trait {
/**
* The factory for the builder object that generates WordPress-friendly test results.
*
* @var Report_Builder_Factory
*/
private $report_builder_factory;
/**
* The test identifier that's set on the Report_Builder.
*
* @var string
*/
private $test_identifier = '';
/**
* Sets the name that WordPress uses to identify this health check.
*
* @param string $test_identifier The identifier.
* @return void
*/
public function set_test_identifier( $test_identifier ) {
$this->test_identifier = $test_identifier;
}
/**
* Returns a new Report_Builder instance using the set test identifier.
*
* @return Report_Builder
*/
private function get_report_builder() {
return $this->report_builder_factory->create( $this->test_identifier );
}
}
health-check/ryte-check.php 0000644 00000003454 15233532001 0011633 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Passes if the health check determines that the site is indexable using Ryte.
*/
class Ryte_Check extends Health_Check {
/**
* Runs the health check.
*
* @var Ryte_Runner
*/
private $runner;
/**
* Generates WordPress-friendly health check results.
*
* @var Ryte_Reports
*/
private $reports;
/**
* Constructor.
*
* @param Ryte_Runner $runner The object that implements the actual health check.
* @param Ryte_Reports $reports The object that generates WordPress-friendly results.
* @return void
*/
public function __construct(
Ryte_Runner $runner,
Ryte_Reports $reports
) {
$this->runner = $runner;
$this->reports = $reports;
$this->reports->set_test_identifier( $this->get_test_identifier() );
$this->set_runner( $this->runner );
}
/**
* Returns a human-readable label for this health check.
*
* @return string The human-readable label.
*/
public function get_test_label() {
return __( 'Ryte', 'wordpress-seo' );
}
/**
* Returns the WordPress-friendly health check result.
*
* @return string[] The WordPress-friendly health check result.
*/
protected function get_result() {
if ( ! $this->runner->should_run() ) {
return [];
}
if ( $this->runner->got_response_error() ) {
$error_response = $this->runner->get_error_response();
if ( $error_response === null ) {
return $this->reports->get_unknown_indexability_result();
}
return $this->reports->get_response_error_result( $error_response );
}
if ( $this->runner->has_unknown_indexability() ) {
return $this->reports->get_unknown_indexability_result();
}
if ( ! $this->runner->is_successful() ) {
return $this->reports->get_not_indexable_result();
}
return $this->reports->get_success_result();
}
}
health-check/ryte-reports.php 0000644 00000021362 15233532001 0012252 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
use WPSEO_Admin_Utils;
use WPSEO_Shortlinker;
use Yoast\WP\SEO\Presenters\Admin\Alert_Presenter;
/**
* Presents a set of different messages for the Ryte health check.
*/
class Ryte_Reports {
use Reports_Trait;
/**
* The WPSEO_Shortlinker object used to generate short links.
*
* @var WPSEO_Shortlinker
*/
private $shortlinker;
/**
* Constructor
*
* @param Report_Builder_Factory $report_builder_factory The factory for result builder objects. This class uses the report builder to generate WordPress-friendly health check results.
* @param WPSEO_Shortlinker $shortlinker The WPSEO_Shortlinker object used to generate short links.
* @return void
*/
public function __construct(
Report_Builder_Factory $report_builder_factory,
WPSEO_Shortlinker $shortlinker
) {
$this->report_builder_factory = $report_builder_factory;
$this->shortlinker = $shortlinker;
}
/**
* Returns the message for a successful health check.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_success_result() {
return $this->get_report_builder()
/* translators: %1$s expands to 'Yoast'. */
->set_label( __( 'Your site can be found by search engines', 'wordpress-seo' ) )
->set_status_good()
->set_description( $this->get_success_result_description() )
->set_actions( $this->get_ryte_actions() )
->build();
}
/**
* Returns the report for a health check result in which the site was not indexable.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_not_indexable_result() {
return $this->get_report_builder()
->set_label( __( 'Your site cannot be found by search engines', 'wordpress-seo' ) )
->set_status_critical()
->set_description( $this->get_not_indexable_result_description() )
->set_actions( $this->get_not_indexable_result_actions() . $this->get_ryte_actions() )
->build();
}
/**
* Returns the report for when the health check was unable to determine indexability.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_unknown_indexability_result() {
return $this->get_report_builder()
/* translators: %1$s: Expands to 'Ryte'. */
->set_label( sprintf( __( '%1$s cannot determine whether your site can be found by search engines', 'wordpress-seo' ), 'Ryte' ) )
->set_status_recommended()
->set_description( $this->get_unknown_indexability_result_description() )
->set_actions( $this->get_ryte_actions() )
->build();
}
/**
* Returns the result for when the health check got an error response from Ryte.
*
* @param array $response_error The error response from Ryte.
* @return string[] The message as a WordPress site status report.
*/
public function get_response_error_result( $response_error ) {
return $this->get_report_builder()
->set_label( __( 'An error occurred while checking whether your site can be found by search engines', 'wordpress-seo' ) )
->set_status_recommended()
->set_description( $this->get_response_error_result_description( $response_error ) )
->set_actions( $this->get_response_error_result_actions() . $this->get_ryte_actions() )
->build();
}
/**
* Returns the description for a successful result.
*
* @return string The description for a successful result.
*/
private function get_success_result_description() {
return sprintf(
/* translators: %1$s: Expands to 'Ryte', %2$s: Expands to 'Yoast SEO'. */
__( '%1$s offers a free indexability check for %2$s users, and it shows that your site can be found by search engines.', 'wordpress-seo' ),
'Ryte',
'Yoast SEO'
);
}
/**
* Returns the description for when the site is not indexable.
*
* @return string The description for when the site is not indexable.
*/
private function get_not_indexable_result_description() {
return sprintf(
/* translators: %1$s: Expands to 'Ryte', %2$s: Expands to 'Yoast SEO'. */
__( '%1$s offers a free indexability check for %2$s users and it has determined that your site cannot be found by search engines. If this site is live or about to become live, this should be fixed.', 'wordpress-seo' ),
'Ryte',
'Yoast SEO'
);
}
/**
* Returns the actions for when the site is not indexable.
*
* @return string The actions for when the site is not indexable.
*/
private function get_not_indexable_result_actions() {
return sprintf(
/* translators: %1$s: Opening tag of the link to the Yoast help center, %2$s: Link closing tag. */
esc_html__( '%1$sRead more about troubleshooting search engine visibility.%2$s', 'wordpress-seo' ),
'<a href="' . esc_url( $this->shortlinker->get( 'https://yoa.st/onpageindexerror' ) ) . '" target="_blank">',
WPSEO_Admin_Utils::get_new_tab_message() . '</a>'
) . '<br /><br />';
}
/**
* Returns the description for when the site's indexability couldn't be determined.
*
* @return string The description for when the site's indexability couldn't be determined.
*/
private function get_unknown_indexability_result_description() {
return sprintf(
/* translators: %1$s: Expands to 'Ryte', %2$s: Expands to 'Yoast SEO'. */
__(
'%1$s offers a free indexability check for %2$s users and right now it has trouble determining whether search engines can find your site. This could have several (legitimate) reasons and is not a problem in itself. If this is a live site, it is recommended that you figure out why the %1$s check failed.',
'wordpress-seo'
),
'Ryte',
'Yoast SEO'
) . '<br />' . $this->get_unknown_indexability_description_alert();
}
/**
* Returns an alert for when the health check was unable to determine indexability.
*
* @return string An alert for when the health check was unable to determine indexability.
*/
private function get_unknown_indexability_description_alert() {
/* translators: %1$s: Expands to 'Ryte', %2$s: Link start tag to the Yoast help center, %3$s: Link closing tag. */
$alert_text = esc_html__(
'As the indexability status of your website can only be fetched from %1$s every 15 seconds,
a first step could be to wait at least 15 seconds and refresh the Site Health page. If that did not help,
%2$sread more about troubleshooting search engine visibility%3$s.',
'wordpress-seo'
);
$alert_content = sprintf(
$alert_text,
'Ryte',
'<a href="' . esc_url( $this->shortlinker->get( 'https://yoa.st/onpagerequestfailed' ) ) . '" target="_blank">',
WPSEO_Admin_Utils::get_new_tab_message() . '</a>'
);
$alert = new Alert_Presenter( $alert_content, 'info' );
return $alert->present();
}
/**
* Returns the description for when the health check got an error response from Ryte.
*
* @param array $error_response The error response from Ryte.
* @return string The description.
*/
private function get_response_error_result_description( $error_response ) {
return sprintf(
'%s<br><br>%s',
sprintf(
/* translators: %1$s: Expands to 'Ryte', %2$s: Expands to 'Yoast SEO'. */
esc_html__( '%1$s offers a free indexability check for %2$s users. The request to %1$s to check whether your site can be found by search engines failed due to an error.', 'wordpress-seo' ),
'Ryte',
'Yoast SEO'
),
sprintf(
/* translators: 1: The Ryte response raw error code, if any. 2: The error message. 3: The WordPress error code, if any. */
__( 'Error details: %1$s %2$s %3$s', 'wordpress-seo' ),
$error_response['raw_error_code'],
$error_response['message'],
$error_response['wp_error_code']
)
);
}
/**
* Returns the actions for when the health check got an error response from Ryte.
*
* @return string The actions for when the health check got an error response from Ryte.
*/
private function get_response_error_result_actions() {
return sprintf(
/* translators: %1$s: Opening tag of the link to the Yoast help center, %2$s: Link closing tag. */
esc_html__( 'If this is a live site, %1$sit is recommended that you figure out why the check failed.%2$s', 'wordpress-seo' ),
'<a href="' . esc_url( $this->shortlinker->get( 'https://yoa.st/onpagerequestfailed' ) ) . '" target="_blank">',
WPSEO_Admin_Utils::get_new_tab_message() . '</a>'
) . '<br /><br />';
}
/**
* Returns the link to Ryte that's appended to every report.
*
* @return string The link to Ryte as an action.
*/
private function get_ryte_actions() {
return sprintf(
/* translators: %1$s: Opening tag of the link to the Yoast Ryte website, %2$s: Expands to 'Ryte', %3$s: Link closing tag. */
esc_html__( '%1$sGo to %2$s to analyze your entire site%3$s', 'wordpress-seo' ),
'<a href="' . esc_url( $this->shortlinker->get( 'https://yoa.st/rytelp' ) ) . '" target="_blank">',
'Ryte',
WPSEO_Admin_Utils::get_new_tab_message() . '</a>'
);
}
}
health-check/curl-reports.php 0000644 00000011157 15233532001 0012235 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
use WPSEO_Admin_Utils;
use WPSEO_Shortlinker;
/**
* Presents a set of different messages for the cURL health check.
*/
class Curl_Reports {
use Reports_Trait;
/**
* The WPSEO_Shortlinker object used to generate short links.
*
* @var WPSEO_Shortlinker
*/
private $shortlinker;
/**
* Constructor
*
* @param Report_Builder_Factory $report_builder_factory The factory for result builder objects. This class uses the report builder to generate WordPress-friendly health check results.
* @param WPSEO_Shortlinker $shortlinker The WPSEO_Shortlinker object used to generate short links.
* @return void
*/
public function __construct(
Report_Builder_Factory $report_builder_factory,
WPSEO_Shortlinker $shortlinker
) {
$this->report_builder_factory = $report_builder_factory;
$this->shortlinker = $shortlinker;
}
/**
* Returns the message for a successful health check.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_success_result() {
return $this->get_report_builder()
/* translators: %1$s expands to 'Yoast'. */
->set_label( sprintf( __( '%1$s premium plugin updates work fine', 'wordpress-seo' ), 'Yoast' ) )
->set_status_good()
->set_description( __( 'Great! You can activate your premium plugin(s) and receive updates.', 'wordpress-seo' ) )
->build();
}
/**
* Returns the message for when the health check was unable to reach the MyYoast API.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_my_yoast_api_not_reachable_result() {
return $this->get_report_builder()
/* translators: %1$s expands to 'Yoast'. */
->set_label( sprintf( __( '%1$s premium plugins cannot update', 'wordpress-seo' ), 'Yoast' ) )
->set_status_critical()
->set_description( $this->get_my_yoast_api_not_reachable_description() )
->build();
}
/**
* Returns the description for when the health check was unable to reach the MyYoast API.
*
* @return string The description containing a link to a Yoast help page about keeping cURL up to date.
*/
private function get_my_yoast_api_not_reachable_description() {
return sprintf(
/* translators: %1$s Emphasis open tag, %2$s: Emphasis close tag, %3$s Link start tag to the Yoast help center, %4$s Link closing tag, %5$s to Yoast SEO, %6$s to my.yoast.com. */
esc_html__( 'You can %1$snot%2$s activate your premium plugin(s) and receive updates because %5$s cannot connect to %6$s. A common cause for not being able to connect is an out-of-date version of cURL, software used to connect to other servers. However, your cURL version seems fine. Please talk to your host and, if needed, the Yoast support team to figure out what is broken. %3$sRead more about cURL in our help center%4$s.', 'wordpress-seo' ),
'<em>',
'</em>',
'<a href="' . esc_url( $this->shortlinker->get( 'https://yoa.st/3u8' ) ) . '" target="_blank">',
WPSEO_Admin_Utils::get_new_tab_message() . '</a>',
'Yoast SEO',
'my.yoast.com'
);
}
/**
* Returns the message for a successful health check.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_no_recent_curl_version_installed_result() {
return $this->get_report_builder()
/* translators: %1$s expands to 'Yoast'. */
->set_label( sprintf( __( '%1$s premium plugins cannot update', 'wordpress-seo' ), 'Yoast' ) )
->set_status_critical()
->set_description( $this->get_no_recent_curl_version_installed_description() )
->build();
}
/**
* Returns the description for when the health check couldn't find a recent enough version of cURL installed on the server.
*
* @return string The description containing a link to a Yoast help page about keeping cURL up to date.
*/
private function get_no_recent_curl_version_installed_description() {
return sprintf(
/* translators: %1$s Emphasis open tag, %2$s: Emphasis close tag, %3$s Link start tag to the Yoast help center, %4$s Link closing tag, %5$s to Yoast SEO, %6$s to my.yoast.com. */
esc_html__( 'You can %1$snot%2$s activate your premium plugin(s) and receive updates because %5$s cannot connect to %6$s. The cause for this error is probably that the cURL software on your server is too old. Please contact your host and ask them to update it to at least version 7.34. %3$sRead more about cURL in our help center%4$s.', 'wordpress-seo' ),
'<em>',
'</em>',
'<a href="' . esc_url( $this->shortlinker->get( 'https://yoa.st/3u8' ) ) . '" target="_blank">',
WPSEO_Admin_Utils::get_new_tab_message() . '</a>',
'Yoast SEO',
'my.yoast.com'
);
}
}
health-check/links-table-check.php 0000644 00000002667 15233532001 0013062 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Passes when the links table is accessible.
*/
class Links_Table_Check extends Health_Check {
/**
* Runs the health check.
*
* @var Links_Table_Runner
*/
private $runner;
/**
* Generates WordPress-friendly health check results.
*
* @var Links_Table_Reports
*/
private $reports;
/**
* Constructor.
*
* @param Links_Table_Runner $runner The object that implements the actual health check.
* @param Links_Table_Reports $reports The object that generates WordPress-friendly results.
* @return void
*/
public function __construct(
Links_Table_Runner $runner,
Links_Table_Reports $reports
) {
$this->runner = $runner;
$this->reports = $reports;
$this->reports->set_test_identifier( $this->get_test_identifier() );
$this->set_runner( $this->runner );
}
/**
* Returns a human-readable label for this health check.
*
* @return string The human-readable label.
*/
public function get_test_label() {
return \__( 'Links table', 'wordpress-seo' );
}
/**
* Returns the WordPress-friendly health check result.
*
* @return string[] The WordPress-friendly health check result.
*/
protected function get_result() {
if ( ! $this->runner->should_run() ) {
return [];
}
if ( $this->runner->is_successful() ) {
return $this->reports->get_success_result();
}
return $this->reports->get_links_table_not_accessible_result();
}
}
health-check/links-table-reports.php 0000644 00000006463 15233532001 0013501 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
use WPSEO_Admin_Utils;
use WPSEO_Shortlinker;
/**
* Presents a set of different messages for the Links_Table health check.
*/
class Links_Table_Reports {
use Reports_Trait;
/**
* Shortlinker object used to create short links for reports.
*
* @var WPSEO_Shortlinker
*/
private $shortlinker;
/**
* Constructor
*
* @param Report_Builder_Factory $report_builder_factory The factory for result builder objects. This class uses the report builder to generate WordPress-friendly health check results.
* @param WPSEO_Shortlinker $shortlinker Object used to add short links to the report description.
* @return void
*/
public function __construct(
Report_Builder_Factory $report_builder_factory,
WPSEO_Shortlinker $shortlinker
) {
$this->report_builder_factory = $report_builder_factory;
$this->shortlinker = $shortlinker;
}
/**
* Returns the message for a successful health check.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_success_result() {
return $this->get_report_builder()
->set_label( \__( 'The text link counter is working as expected', 'wordpress-seo' ) )
->set_status_good()
->set_description( $this->get_success_description() )
->build();
}
/**
* Returns the message for a failed health check.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_links_table_not_accessible_result() {
return $this->get_report_builder()
->set_label( \__( 'The text link counter feature is not working as expected', 'wordpress-seo' ) )
->set_status_recommended()
->set_description( $this->get_links_table_not_accessible_description() )
->set_actions( $this->get_actions() )
->build();
}
/**
* Returns the description for when the health check was successful.
*
* @return string The description as a string.
*/
private function get_success_description() {
return sprintf(
/* translators: 1: Link to the Yoast SEO blog, 2: Link closing tag. */
\esc_html__( 'The text link counter helps you improve your site structure. %1$sFind out how the text link counter can enhance your SEO%2$s.', 'wordpress-seo' ),
'<a href="' . $this->shortlinker->get( 'https://yoa.st/3zw' ) . '" target="_blank">',
WPSEO_Admin_Utils::get_new_tab_message() . '</a>'
);
}
/**
* Returns the description for when the health couldn't access the links table.
*
* @return string The description as a string.
*/
private function get_links_table_not_accessible_description() {
return sprintf(
/* translators: 1: Yoast SEO. */
\__( 'For this feature to work, %1$s needs to create a table in your database. We were unable to create this table automatically.', 'wordpress-seo' ),
'Yoast SEO'
);
}
/**
* Returns the actions that the user should take when the links table is not accessible.
*
* @return string The actions as a string.
*/
private function get_actions() {
return sprintf(
/* translators: 1: Link to the Yoast help center, 2: Link closing tag. */
esc_html__( '%1$sFind out how to solve this problem on our help center%2$s.', 'wordpress-seo' ),
'<a href="' . $this->shortlinker->get( 'https://yoa.st/3zv' ) . '" target="_blank">',
WPSEO_Admin_Utils::get_new_tab_message() . '</a>'
);
}
}
health-check/report-builder-factory.php 0000644 00000000720 15233532001 0014172 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Creates Report_Builder instances.
*/
class Report_Builder_Factory {
/**
* Creates a new Report_Builder instance.
*
* @param string $test_identifier The test identifier as a string.
* @return Report_Builder The new Report_Builder instance.
*/
public function create( $test_identifier ) {
$instance = new Report_Builder();
return $instance->set_test_identifier( $test_identifier );
}
}
health-check/default-tagline-check.php 0000644 00000002700 15233532001 0013706 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Passes when the tagline is set to something other than the WordPress default tagline.
*/
class Default_Tagline_Check extends Health_Check {
/**
* Runs the health check.
*
* @var Default_Tagline_Runner
*/
private $runner;
/**
* Generates WordPress-friendly health check results.
*
* @var Default_Tagline_Reports
*/
private $reports;
/**
* Constructor.
*
* @param Default_Tagline_Runner $runner The object that implements the actual health check.
* @param Default_Tagline_Reports $reports The object that generates WordPress-friendly results.
* @return void
*/
public function __construct(
Default_Tagline_Runner $runner,
Default_Tagline_Reports $reports
) {
$this->runner = $runner;
$this->reports = $reports;
$this->reports->set_test_identifier( $this->get_test_identifier() );
$this->set_runner( $this->runner );
}
/**
* Returns a human-readable label for this health check.
*
* @return string The human-readable label.
*/
public function get_test_label() {
return __( 'Default tagline', 'wordpress-seo' );
}
/**
* Returns the WordPress-friendly health check result.
*
* @return string[] The WordPress-friendly health check result.
*/
protected function get_result() {
if ( $this->runner->is_successful() ) {
return $this->reports->get_success_result();
}
return $this->reports->get_has_default_tagline_result();
}
}
health-check/postname-permalink-reports.php 0000644 00000005050 15233532001 0015071 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Presents a set of different messages for the Postname_Permalink health check.
*/
class Postname_Permalink_Reports {
use Reports_Trait;
/**
* Constructor.
*
* @param Report_Builder_Factory $report_builder_factory The factory for result builder objects. This class uses the report builder to generate WordPress-friendly health check results.
*/
public function __construct( Report_Builder_Factory $report_builder_factory ) {
$this->report_builder_factory = $report_builder_factory;
}
/**
* Returns the report for when permalinks are set to contain the post name.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_success_result() {
return $this->get_report_builder()
->set_label( esc_html__( 'Your permalink structure includes the post name', 'wordpress-seo' ) )
->set_status_good()
->set_description( __( 'You do have your postname in the URL of your posts and pages.', 'wordpress-seo' ) )
->build();
}
/**
* Returns the report for when permalinks are not set to contain the post name.
*
* @return string[] The message as a WordPress site status report.
*/
public function get_has_no_postname_in_permalink_result() {
return $this->get_report_builder()
->set_label( __( 'You do not have your postname in the URL of your posts and pages', 'wordpress-seo' ) )
->set_status_recommended()
->set_description( $this->get_has_no_postname_in_permalink_description() )
->set_actions( $this->get_has_no_postname_in_permalink_actions() )
->build();
}
/**
* Returns the description for when permalinks are not set to contain the post name.
*
* @return string The description as a string.
*/
private function get_has_no_postname_in_permalink_description() {
return sprintf(
/* translators: %s expands to '/%postname%/' */
__( 'It\'s highly recommended to have your postname in the URL of your posts and pages. Consider setting your permalink structure to %s.', 'wordpress-seo' ),
'<strong>/%postname%/</strong>'
);
}
/**
* Returns the actions for when permalinks are not set to contain the post name.
*
* @return string The actions as a string.
*/
private function get_has_no_postname_in_permalink_actions() {
return sprintf(
/* translators: %1$s is a link start tag to the permalink settings page, %2$s is the link closing tag. */
__( 'You can fix this on the %1$sPermalink settings page%2$s.', 'wordpress-seo' ),
'<a href="' . admin_url( 'options-permalink.php' ) . '">',
'</a>'
);
}
}
health-check/myyoast-api-request-factory.php 0000644 00000000750 15233532001 0015200 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
use WPSEO_MyYoast_Api_Request;
/**
* Creates WPSEO_MyYoast_Api_Request objects.
*/
class MyYoast_Api_Request_Factory {
/**
* Creates a new WPSEO_MyYoast_API_Request.
*
* @param string $url The URL for the request.
* @param array $args Optional arguments for the request.
* @return WPSEO_MyYoast_Api_Request
*/
public function create( $url, $args = [] ) {
return new WPSEO_MyYoast_Api_Request( $url, $args );
}
}
health-check/page-comments-runner.php 0000644 00000001503 15233532001 0013634 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Runs the Page_Comments health check.
*/
class Page_Comments_Runner implements Runner_Interface {
/**
* Is set to true when comments are set to display on a single page.
*
* @var bool
*/
private $comments_on_single_page;
/**
* Constructor.
*/
public function __construct() {
$this->comments_on_single_page = false;
}
/**
* Runs the health check. Checks if comments are displayed on a single page.
*
* @return void
*/
public function run() {
$this->comments_on_single_page = get_option( 'page_comments' ) !== '1';
}
/**
* Returns true if comments are displayed on a single page.
*
* @return bool True if comments are displayed on a single page.
*/
public function is_successful() {
return $this->comments_on_single_page;
}
}
health-check/health-check.php 0000644 00000004657 15233532001 0012123 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
/**
* Abstract class for all health checks. Provides a uniform interface for the Health_Check_Integration.
*/
abstract class Health_Check {
/**
* The prefix to add to the test identifier. Used to differentiate between Yoast's health checks, and other health checks.
*/
const TEST_IDENTIFIER_PREFIX = 'yoast-';
/**
* The object that runs the actual health check.
*
* @var Runner_Interface
*/
private $runner;
/**
* The health check implementation sets the runner so this class can start a health check.
*
* @param Runner_Interface $runner The health check runner.
* @return void
*/
protected function set_runner( $runner ) {
$this->runner = $runner;
}
/**
* Returns the identifier of health check implementation. WordPress needs this to manage the health check (https://developer.wordpress.org/reference/hooks/site_status_tests/).
*
* @return string The identifier that WordPress requires.
*/
public function get_test_identifier() {
$full_class_name = \get_class( $this );
$class_name_backslash_index = \strrpos( $full_class_name, '\\' );
$class_name = $full_class_name;
if ( $class_name_backslash_index ) {
$class_name_index = ( $class_name_backslash_index + 1 );
$class_name = \substr( $full_class_name, $class_name_index );
}
$lowercase = \strtolower( $class_name );
$whitespace_as_dashes = \str_replace( '_', '-', $lowercase );
$with_prefix = self::TEST_IDENTIFIER_PREFIX . $whitespace_as_dashes;
return $with_prefix;
}
/**
* Returns the name of health check implementation that the user can see. WordPress needs this to manage the health check (https://developer.wordpress.org/reference/hooks/site_status_tests/).
*
* @return string A human-readable label for the health check.
*/
abstract public function get_test_label();
/**
* Runs the health check, and returns its result in the format that WordPress requires to show the results to the user (https://developer.wordpress.org/reference/hooks/site_status_test_result/).
*
* @return string[] The array containing a WordPress site status report.
*/
public function run_and_get_result() {
$this->runner->run();
return $this->get_result();
}
/**
* Gets the result from the health check implementation.
*
* @return string[] The array containing a WordPress site status report.
*/
abstract protected function get_result();
}
health-check/links-table-runner.php 0000644 00000003774 15233532001 0013316 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Health_Check;
use Yoast\WP\SEO\Config\Migration_Status;
use Yoast\WP\SEO\Helpers\Options_Helper;
/**
* Runs the Links_Table health check.
*/
class Links_Table_Runner implements Runner_Interface {
/**
* Is set to true when the links table is accessible.
*
* @var bool
*/
private $links_table_accessible = false;
/**
* The Migration_Status object used to determine whether the links table is accessible.
*
* @var Migration_Status
*/
private $migration_status;
/**
* The Options_Helper object used to determine whether the health check should run or not.
*
* @var Options_Helper
*/
private $options_helper;
/**
* Constructor.
*
* @param Migration_Status $migration_status Object used to determine whether the links table is accessible.
* @param Options_Helper $options_helper Object used to determine whether the health check should run.
*/
public function __construct(
Migration_Status $migration_status,
Options_Helper $options_helper
) {
$this->migration_status = $migration_status;
$this->options_helper = $options_helper;
}
/**
* Runs the health check. Checks if the tagline is set to WordPress' default tagline, or to its set translation.
*
* @return void
*/
public function run() {
if ( ! $this->should_run() ) {
return;
}
$this->links_table_accessible = $this->migration_status->is_version( 'free', WPSEO_VERSION );
}
/**
* Determines whether the health check should run or not.
*
* @return bool True if the text link counter feature is enabled.
*/
public function should_run() {
$text_link_counter_enabled = $this->options_helper->get( 'enable_text_link_counter' );
if ( ! is_bool( $text_link_counter_enabled ) ) {
return false;
}
return $text_link_counter_enabled;
}
/**
* Returns true if the links table is accessible
*
* @return bool The boolean indicating if the health check was succesful.
*/
public function is_successful() {
return $this->links_table_accessible;
}
}
importing/conflicting-plugins-service.php 0000644 00000005711 15233532001 0014677 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Importing;
use Yoast\WP\SEO\Config\Conflicting_Plugins;
/**
* Detects plugin conflicts.
*/
class Conflicting_Plugins_Service {
/**
* Detects the conflicting plugins.
*
* @return array A list of all active conflicting plugins.
*/
public function detect_conflicting_plugins() {
$all_active_plugins = $this->get_active_plugins();
// Search for active plugins.
return $this->get_active_conflicting_plugins( $all_active_plugins );
}
/**
* Deactivates the specified plugin(s) if any, or the entire list of known conflicting plugins.
*
* @param string|array|false $plugins Optional. The plugin filename, or array of plugin filenames, to deactivate.
*/
public function deactivate_conflicting_plugins( $plugins = false ) {
// If no plugins are specified, deactivate any known conflicting plugins that are active.
if ( ! $plugins ) {
$plugins = $this->detect_conflicting_plugins();
}
// In case of a single plugin, wrap it in an array.
if ( \is_string( $plugins ) ) {
$plugins = [ $plugins ];
}
if ( ! \is_array( $plugins ) ) {
return;
}
// Deactivate all specified plugins across the network, while retaining their deactivation hook.
\deactivate_plugins( $plugins );
}
/**
* Loop through the list of known conflicting plugins to check if one of the plugins is active.
*
* @param array $all_active_plugins All plugins loaded by WordPress.
*
* @return array The array of activated conflicting plugins.
*/
protected function get_active_conflicting_plugins( $all_active_plugins ) {
$active_conflicting_plugins = [];
foreach ( Conflicting_Plugins::all_plugins() as $plugin ) {
if ( \in_array( $plugin, $all_active_plugins, true ) ) {
$active_conflicting_plugins[] = $plugin;
}
}
return $active_conflicting_plugins;
}
/**
* Get a list of all plugins active in the current WordPress instance.
*
* @return false|array The names of all active plugins.
*/
protected function get_active_plugins() {
// Request a list of active plugins from WordPress.
$all_active_plugins = \get_option( 'active_plugins' );
return $this->ignore_deactivating_plugin( $all_active_plugins );
}
/**
* While deactivating a plugin, we should ignore the plugin currently being deactivated.
*
* @param array $all_active_plugins All plugins currently loaded by WordPress.
*
* @return array The remaining active plugins.
*/
protected function ignore_deactivating_plugin( $all_active_plugins ) {
if ( isset( $_GET['action'] ) && isset( $_GET['plugin'] ) && \filter_var( \wp_unslash( $_GET['action'] ) ) === 'deactivate' ) {
$deactivated_plugin = \filter_var( \wp_unslash( $_GET['plugin'] ) );
\check_admin_referer( 'deactivate-plugin_' . $deactivated_plugin );
$key_to_remove = \array_search( $deactivated_plugin, $all_active_plugins, true );
if ( $key_to_remove !== false ) {
unset( $all_active_plugins[ $key_to_remove ] );
}
}
return $all_active_plugins;
}
}
importing/importable-detector-service.php 0000644 00000005030 15233532001 0014660 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Importing;
use Yoast\WP\SEO\Actions\Importing\Importing_Action_Interface;
/**
* Detects if any data from other SEO plugins is available for importing.
*/
class Importable_Detector_Service {
/**
* All known import actions
*
* @var array|Importing_Action_Interface[]
*/
protected $importers;
/**
* Importable_Detector_Service constructor.
*
* @param Importing_Action_Interface ...$importers All of the known importers.
*/
public function __construct( Importing_Action_Interface ...$importers ) {
$this->importers = $importers;
}
/**
* Returns the detected importers that have data to work with.
*
* @param string|null $plugin The plugin name of the importer.
* @param string|null $type The type of the importer.
*
* @return array The detected importers that have data to work with.
*/
public function detect_importers( $plugin = null, $type = null ) {
$detectors = $this->filter_actions( $this->importers, $plugin, $type );
$detected = [];
foreach ( $detectors as $detector ) {
if ( $detector->is_enabled() && $detector->get_type() !== 'cleanup' && ! $detector->get_completed() && $detector->get_limited_unindexed_count( 1 ) > 0 ) {
$detected[ $detector->get_plugin() ][] = $detector->get_type();
}
}
return $detected;
}
/**
* Returns the detected cleanups that have data to work with.
*
* @param string|null $plugin The plugin name of the cleanup.
*
* @return array The detected importers that have data to work with.
*/
public function detect_cleanups( $plugin = null ) {
$detectors = $this->filter_actions( $this->importers, $plugin, 'cleanup' );
$detected = [];
foreach ( $detectors as $detector ) {
if ( $detector->is_enabled() && ! $detector->get_completed() && $detector->get_limited_unindexed_count( 1 ) > 0 ) {
$detected[ $detector->get_plugin() ][] = $detector->get_type();
}
}
return $detected;
}
/**
* Filters all import actions from a list that do not match the given Plugin or Type.
*
* @param Importing_Action_Interface[] $all_actions The complete list of actions.
* @param string|null $plugin The Plugin name whose actions to keep.
* @param string|null $type The type of actions to keep.
*
* @return array
*/
public function filter_actions( $all_actions, $plugin = null, $type = null ) {
return \array_filter(
$all_actions,
static function( $action ) use ( $plugin, $type ) {
return $action->is_compatible_with( $plugin, $type );
}
);
}
}
importing/aioseo/aioseo-replacevar-service.php 0000644 00000006637 15233532001 0015611 0 ustar 00 <?php
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Given it's a very specific case.
namespace Yoast\WP\SEO\Services\Importing\Aioseo;
/**
* Replaces AISOEO replacevars with Yoast ones.
*/
class Aioseo_Replacevar_Service {
/**
* Mapping between the AiOSEO replace vars and the Yoast replace vars.
*
* @var array
*
* @see https://yoast.com/help/list-available-snippet-variables-yoast-seo/
*/
protected $replace_vars_map = [
// The key is the AiOSEO replace var, the value is the Yoast replace var (see class-wpseo-replace-vars).
'#archive_title' => '%%archive_title%%',
'#archive_date' => '%%date%%',
'#attachment_caption' => '%%caption%%',
'#author_bio' => '%%user_description%%',
'#author_first_name' => '%%author_first_name%%',
'#author_last_name' => '%%author_last_name%%',
'#author_name' => '%%name%%',
'#blog_title' => '%%sitename%%', // Same with #site_title.
'#categories' => '%%category%%',
'#current_date' => '%%currentdate%%',
'#current_day' => '%%currentday%%',
'#current_month' => '%%currentmonth%%',
'#current_year' => '%%currentyear%%',
'#parent_title' => '%%parent_title%%',
'#page_number' => '%%pagenumber%%',
'#permalink' => '%%permalink%%',
'#post_content' => '%%post_content%%',
'#post_date' => '%%date%%',
'#post_day' => '%%post_day%%',
'#post_month' => '%%post_month%%',
'#post_title' => '%%title%%',
'#post_year' => '%%post_year%%',
'#post_excerpt_only' => '%%excerpt_only%%',
'#post_excerpt' => '%%excerpt%%',
'#search_term' => '%%searchphrase%%',
'#separator_sa' => '%%sep%%',
'#site_title' => '%%sitename%%',
'#tagline' => '%%sitedesc%%',
'#taxonomy_title' => '%%category_title%%',
'#taxonomy_description' => '%%term_description%%',
];
/**
* Edits the replace_vars map of the class.
*
* @param string $aioseo_var The AIOSEO replacevar.
* @param string $yoast_var The Yoast replacevar.
*
* @return void
*/
public function compose_map( $aioseo_var, $yoast_var ) {
$map = $this->replace_vars_map;
$map[ $aioseo_var ] = $yoast_var;
$this->replace_vars_map = $map;
}
/**
* Transforms AIOSEO replacevars into Yoast replacevars.
*
* @param string $aioseo_replacevar The AIOSEO replacevar.
*
* @return string The Yoast replacevar.
*/
public function transform( $aioseo_replacevar ) {
$yoast_replacevar = \str_replace( \array_keys( $this->replace_vars_map ), \array_values( $this->replace_vars_map ), $aioseo_replacevar );
// Transform the '#custom_field-<custom_field>' tags into '%%cf_<custom_field>%%' ones.
$yoast_replacevar = \preg_replace_callback(
'/#custom_field-([a-zA-Z0-9_-]+)/',
static function ( $cf_matches ) {
return '%%cf_' . $cf_matches[1] . '%%';
},
$yoast_replacevar
);
// Transform the '#tax_name-<custom-tax-name>' tags into '%%ct_<custom-tax-name>%%' ones.
$yoast_replacevar = \preg_replace_callback(
'/#tax_name-([a-zA-Z0-9_-]+)/',
static function ( $ct_matches ) {
return '%%ct_' . $ct_matches[1] . '%%';
},
$yoast_replacevar
);
return $yoast_replacevar;
}
}
importing/aioseo/aioseo-social-images-provider-service.php 0000644 00000010653 15233532001 0020023 0 ustar 00 <?php
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Given it's a very specific case.
namespace Yoast\WP\SEO\Services\Importing\Aioseo;
use Yoast\WP\SEO\Helpers\Aioseo_Helper;
use Yoast\WP\SEO\Helpers\Image_Helper;
/**
* Provides AISOEO social images urls.
*/
class Aioseo_Social_Images_Provider_Service {
/**
* The AIOSEO helper.
*
* @var Aioseo_Helper
*/
protected $aioseo_helper;
/**
* The image helper.
*
* @var Image_Helper
*/
protected $image;
/**
* Class constructor.
*
* @param Aioseo_Helper $aioseo_helper The AIOSEO helper.
* @param Image_Helper $image The image helper.
*/
public function __construct(
Aioseo_Helper $aioseo_helper,
Image_Helper $image
) {
$this->aioseo_helper = $aioseo_helper;
$this->image = $image;
}
/**
* Retrieves the default source of social images.
*
* @param string $social_setting The social settings we're working with, eg. open-graph or twitter.
*
* @return string The default source of social images.
*/
public function get_default_social_image_source( $social_setting ) {
return $this->get_social_defaults( 'source', $social_setting );
}
/**
* Retrieves the default custom social image if there is any.
*
* @param string $social_setting The social settings we're working with, eg. open-graph or twitter.
*
* @return string The global default social image.
*/
public function get_default_custom_social_image( $social_setting ) {
return $this->get_social_defaults( 'custom_image', $social_setting );
}
/**
* Retrieves social defaults, be it Default Post Image Source or Default Post Image.
*
* @param string $setting The setting we want, eg. source or custom image.
* @param string $social_setting The social settings we're working with, eg. open-graph or twitter.
*
* @return string The social default.
*/
public function get_social_defaults( $setting, $social_setting ) {
switch ( $setting ) {
case 'source':
$setting_key = 'defaultImageSourcePosts';
break;
case 'custom_image':
$setting_key = 'defaultImagePosts';
break;
default:
return '';
}
$aioseo_settings = $this->aioseo_helper->get_global_option();
if ( $social_setting === 'og' ) {
$social_setting = 'facebook';
}
if ( ! isset( $aioseo_settings['social'][ $social_setting ]['general'][ $setting_key ] ) ) {
return '';
}
return $aioseo_settings['social'][ $social_setting ]['general'][ $setting_key ];
}
/**
* Retrieves the url of the first image in content.
*
* @param int $post_id The post id to extract the image from.
*
* @return string The url of the first image in content.
*/
public function get_first_image_in_content( $post_id ) {
$image = $this->image->get_gallery_image( $post_id );
if ( ! $image ) {
$image = $this->image->get_post_content_image( $post_id );
}
return $image;
}
/**
* Retrieves the url of the first attached image.
*
* @param int $post_id The post id to extract the image from.
*
* @return string The url of the first attached image.
*/
public function get_first_attached_image( $post_id ) {
if ( \get_post_type( $post_id ) === 'attachment' ) {
return $this->image->get_attachment_image_source( $post_id, 'fullsize' );
}
$attachments = \get_children(
[
'post_parent' => $post_id,
'post_status' => 'inherit',
'post_type' => 'attachment',
'post_mime_type' => 'image',
]
);
if ( $attachments && ! empty( $attachments ) ) {
return $this->image->get_attachment_image_source( \array_values( $attachments )[0]->ID, 'fullsize' );
}
return '';
}
/**
* Retrieves the url of the featured image.
*
* @param int $post_id The post id to extract the image from.
*
* @return string The url of the featured image.
*/
public function get_featured_image( $post_id ) {
$feature_image_id = \get_post_thumbnail_id( $post_id );
if ( $feature_image_id ) {
return $this->image->get_attachment_image_source( $feature_image_id, 'fullsize' );
}
return '';
}
/**
* Retrieves the url of the first available image. Tries each image source to get one image.
*
* @param int $post_id The post id to extract the image from.
*
* @return string The url of the featured image.
*/
public function get_auto_image( $post_id ) {
$image = $this->get_first_attached_image( $post_id );
if ( ! $image ) {
$image = $this->get_first_image_in_content( $post_id );
}
return $image;
}
}
importing/aioseo/aioseo-robots-provider-service.php 0000644 00000003254 15233532001 0016615 0 ustar 00 <?php
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Given it's a very specific case.
namespace Yoast\WP\SEO\Services\Importing\Aioseo;
use Yoast\WP\SEO\Helpers\Aioseo_Helper;
/**
* Provides AISOEO search appearance robot settings.
*/
class Aioseo_Robots_Provider_Service {
/**
* The AIOSEO helper.
*
* @var Aioseo_Helper
*/
protected $aioseo_helper;
/**
* Class constructor.
*
* @param Aioseo_Helper $aioseo_helper The AIOSEO helper.
*/
public function __construct(
Aioseo_Helper $aioseo_helper
) {
$this->aioseo_helper = $aioseo_helper;
}
/**
* Retrieves the robot setting set globally in AIOSEO.
*
* @param string $setting_name The name of the robot setting, eg. noindex.
*
* @return bool Whether global robot settings enable or not the specific setting.
*/
public function get_global_robot_settings( $setting_name ) {
$aioseo_settings = $this->aioseo_helper->get_global_option();
if ( empty( $aioseo_settings ) ) {
return false;
}
$global_robot_settings = $aioseo_settings['searchAppearance']['advanced']['globalRobotsMeta'];
if ( $global_robot_settings['default'] === true ) {
return false;
}
return $global_robot_settings[ $setting_name ];
}
/**
* Gets the subtype's robot setting from the db.
*
* @param array $mapping The mapping of the setting we're working with.
*
* @return bool The robot setting.
*/
public function get_subtype_robot_setting( $mapping ) {
$aioseo_settings = \json_decode( \get_option( $mapping['option_name'], '' ), true );
return $aioseo_settings['searchAppearance'][ $mapping['type'] ][ $mapping['subtype'] ]['advanced']['robotsMeta'][ $mapping['robot_type'] ];
}
}
importing/aioseo/aioseo-robots-transformer-service.php 0000644 00000003326 15233532001 0017325 0 ustar 00 <?php
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Given it's a very specific case.
namespace Yoast\WP\SEO\Services\Importing\Aioseo;
/**
* Transforms AISOEO search appearance robot settings.
*/
class Aioseo_Robots_Transformer_Service {
/**
* The robots transfomer service.
*
* @var Aioseo_Robots_Provider_Service
*/
protected $robots_provider;
/**
* Class constructor.
*
* @param Aioseo_Robots_Provider_Service $robots_provider The robots provider service.
*/
public function __construct(
Aioseo_Robots_Provider_Service $robots_provider
) {
$this->robots_provider = $robots_provider;
}
/**
* Transforms the robot setting, taking into consideration whether they defer to global defaults.
*
* @param string $setting_name The name of the robot setting, eg. noindex.
* @param bool $setting_value The value of the robot setting.
* @param array $mapping The mapping of the setting we're working with.
*
* @return bool The transformed robot setting.
*/
public function transform_robot_setting( $setting_name, $setting_value, $mapping ) {
$aioseo_settings = \json_decode( \get_option( $mapping['option_name'], '' ), true );
// Let's check first if it defers to global robot settings.
if ( empty( $aioseo_settings ) || ! isset( $aioseo_settings['searchAppearance'][ $mapping['type'] ][ $mapping['subtype'] ]['advanced']['robotsMeta']['default'] ) ) {
return $setting_value;
}
$defers_to_defaults = $aioseo_settings['searchAppearance'][ $mapping['type'] ][ $mapping['subtype'] ]['advanced']['robotsMeta']['default'];
if ( $defers_to_defaults ) {
return $this->robots_provider->get_global_robot_settings( $setting_name );
}
return $setting_value;
}
}
indexables/indexable-version-manager.php 0000644 00000004440 15233532001 0014415 0 ustar 00 <?php
namespace Yoast\WP\SEO\Services\Indexables;
use Yoast\WP\SEO\Models\Indexable;
use Yoast\WP\SEO\Values\Indexables\Indexable_Builder_Versions;
/**
* Handles version control for Indexables.
*/
class Indexable_Version_Manager {
/**
* Stores the version of each Indexable type.
*
* @var Indexable_Builder_Versions The current versions of all indexable builders.
*/
protected $indexable_builder_versions;
/**
* Indexable_Version_Manager constructor.
*
* @param Indexable_Builder_Versions $indexable_builder_versions The current versions of all indexable builders.
*/
public function __construct( Indexable_Builder_Versions $indexable_builder_versions ) {
$this->indexable_builder_versions = $indexable_builder_versions;
}
/**
* Determines if an Indexable has a lower version than the builder for that Indexable's type.
*
* @param Indexable $indexable The Indexable to check.
*
* @return bool True if the given version is older than the current latest version.
*/
public function indexable_needs_upgrade( $indexable ) {
if ( ( ! $indexable )
|| ( ! \is_a( $indexable, Indexable::class ) )
) {
return false;
}
return $this->needs_upgrade( $indexable->object_type, $indexable->version );
}
/**
* Determines if an Indexable version for the type is lower than the current version for that Indexable type.
*
* @param string $object_type The Indexable's object type.
* @param int $indexable_version The Indexable's version.
*
* @return bool True if the given version is older than the current latest version.
*/
protected function needs_upgrade( $object_type, $indexable_version ) {
$current_indexable_builder_version = $this->indexable_builder_versions->get_latest_version_for_type( $object_type );
// If the Indexable's version is below the current version, that Indexable needs updating.
return $indexable_version < $current_indexable_builder_version;
}
/**
* Sets an Indexable's version to the latest version.
*
* @param Indexable $indexable The Indexable to update.
*
* @return Indexable
*/
public function set_latest( $indexable ) {
if ( ! $indexable ) {
return $indexable;
}
$indexable->version = $this->indexable_builder_versions->get_latest_version_for_type( $indexable->object_type );
return $indexable;
}
}