Merged in feature/MAW-855-import-code-into-aws (pull request #2)

code import from pantheon

* code import from pantheon
This commit is contained in:
Tony Volpe
2023-12-04 23:08:14 +00:00
parent 8c9b1312bc
commit 8f4b5efda6
4766 changed files with 185592 additions and 239967 deletions

View File

@@ -0,0 +1,134 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Addon_Manager;
use WPSEO_Admin_Asset_Manager;
use Yoast\WP\SEO\Conditionals\User_Profile_Conditional;
use Yoast\WP\SEO\Helpers\Options_Helper;
use Yoast\WP\SEO\Helpers\User_Helper;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Introductions\Infrastructure\Wistia_Embed_Permission_Repository;
/**
* Ai_Consent_Integration class.
*/
class Ai_Consent_Integration implements Integration_Interface {
/**
* Represents the admin asset manager.
*
* @var WPSEO_Admin_Asset_Manager
*/
private $asset_manager;
/**
* Represents the add-on manager.
*
* @var WPSEO_Addon_Manager
*/
private $addon_manager;
/**
* Represents the options manager.
*
* @var Options_Helper
*/
private $options_helper;
/**
* Represents the user helper.
*
* @var User_Helper
*/
private $user_helper;
/**
* Represents the wistia embed permission repository.
*
* @var Wistia_Embed_Permission_Repository
*/
private $wistia_embed_permission_repository;
/**
* Returns the conditionals based in which this loadable should be active.
*
* @return array
*/
public static function get_conditionals() {
return [ User_Profile_Conditional::class ];
}
/**
* Constructs the class.
*
* @param WPSEO_Admin_Asset_Manager $asset_manager The admin asset manager.
* @param WPSEO_Addon_Manager $addon_manager The addon manager.
* @param Options_Helper $options_helper The options helper.
* @param User_Helper $user_helper The user helper.
* @param Wistia_Embed_Permission_Repository $wistia_embed_permission_repository The wistia embed permission
* repository.
*/
public function __construct(
WPSEO_Admin_Asset_Manager $asset_manager,
WPSEO_Addon_Manager $addon_manager,
Options_Helper $options_helper,
User_Helper $user_helper,
Wistia_Embed_Permission_Repository $wistia_embed_permission_repository
) {
$this->asset_manager = $asset_manager;
$this->addon_manager = $addon_manager;
$this->options_helper = $options_helper;
$this->user_helper = $user_helper;
$this->wistia_embed_permission_repository = $wistia_embed_permission_repository;
}
/**
* Initializes the integration.
*
* This is the place to register hooks and filters.
*
* @return void
*/
public function register_hooks() {
// Hide AI feature option in user profile if the user is not allowed to use it.
if ( current_user_can( 'edit_posts' ) ) {
\add_action( 'wpseo_user_profile_additions', [ $this, 'render_user_profile' ], 12 );
}
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ], 11 );
}
/**
* Enqueues the required assets.
*
* @return void
*/
public function enqueue_assets() {
$this->asset_manager->enqueue_style( 'premium-ai-generator' );
\wp_enqueue_script( 'wp-seo-premium-manage-ai-consent-button' );
$user_id = $this->user_helper->get_current_user_id();
\wp_localize_script(
'wp-seo-premium-manage-ai-consent-button',
'wpseoPremiumManageAiConsentButton',
[
'hasConsent' => $this->user_helper->get_meta( $user_id, '_yoast_wpseo_ai_consent', true ),
// Note: this is passing the Free plugin URL! As the image is located in there.
'pluginUrl' => \plugins_url( '', \WPSEO_FILE ),
'wistiaEmbedPermission' => $this->wistia_embed_permission_repository->get_value_for_user( $user_id ),
]
);
}
/**
* Renders the AI consent button for the user profile.
*
* @return void
*/
public function render_user_profile() {
echo '<label for="ai-generator-consent-button">',
esc_html__( 'AI features', 'wordpress-seo-premium' ),
'</label>',
'<div id="ai-generator-consent" style="display:inline-block; margin-top: 28px; padding-left:5px;"></div>';
}
}

View File

@@ -0,0 +1,111 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Addon_Manager;
use WPSEO_Admin_Asset_Manager;
use Yoast\WP\SEO\Helpers\Options_Helper;
use Yoast\WP\SEO\Helpers\User_Helper;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Premium\Conditionals\Ai_Editor_Conditional;
/**
* Ai_Generator_Integration class.
*/
class Ai_Generator_Integration implements Integration_Interface {
/**
* Represents the admin asset manager.
*
* @var WPSEO_Admin_Asset_Manager
*/
private $asset_manager;
/**
* Represents the add-on manager.
*
* @var WPSEO_Addon_Manager
*/
private $addon_manager;
/**
* Represents the options manager.
*
* @var Options_Helper
*/
private $options_helper;
/**
* Represents the user helper.
*
* @var User_Helper
*/
private $user_helper;
/**
* Returns the conditionals based in which this loadable should be active.
*
* @return array
*/
public static function get_conditionals() {
return [ Ai_Editor_Conditional::class ];
}
/**
* Constructs the class.
*
* @param WPSEO_Admin_Asset_Manager $asset_manager The admin asset manager.
* @param WPSEO_Addon_Manager $addon_manager The addon manager.
* @param Options_Helper $options_helper The options helper.
* @param User_Helper $user_helper The user helper.
*/
public function __construct(
WPSEO_Admin_Asset_Manager $asset_manager,
WPSEO_Addon_Manager $addon_manager,
Options_Helper $options_helper,
User_Helper $user_helper
) {
$this->asset_manager = $asset_manager;
$this->addon_manager = $addon_manager;
$this->options_helper = $options_helper;
$this->user_helper = $user_helper;
}
/**
* Initializes the integration.
*
* This is the place to register hooks and filters.
*
* @return void
*/
public function register_hooks() {
if ( ! $this->options_helper->get( 'enable_ai_generator', false ) ) {
return;
}
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
// Enqueue after Elementor_Premium integration, which re-registers the assets.
\add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'enqueue_assets' ], 11 );
}
/**
* Enqueues the required assets.
*
* @return void
*/
public function enqueue_assets() {
\wp_enqueue_script( 'wp-seo-premium-ai-generator' );
\wp_localize_script(
'wp-seo-premium-ai-generator',
'wpseoPremiumAiGenerator',
[
'adminUrl' => \admin_url( 'admin.php' ),
'hasConsent' => $this->user_helper->get_meta( $this->user_helper->get_current_user_id(), '_yoast_wpseo_ai_consent', true ),
'hasValidSubscription' => $this->addon_manager->has_valid_subscription( WPSEO_Addon_Manager::PREMIUM_SLUG ),
'pluginUrl' => \plugins_url( '', \WPSEO_PREMIUM_FILE ),
'postType' => \get_post_type(),
]
);
$this->asset_manager->enqueue_style( 'premium-ai-generator' );
}
}

View File

@@ -0,0 +1,226 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WP_Query;
use wpdb;
use WPSEO_Admin_Asset_Manager;
use Yoast\WP\Lib\Model;
use Yoast\WP\SEO\Conditionals\Admin\Posts_Overview_Or_Ajax_Conditional;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Helpers\Post_Type_Helper;
use Yoast\WP\SEO\Integrations\Admin\Admin_Columns_Cache_Integration;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Premium\Conditionals\Cornerstone_Enabled_Conditional;
use Yoast\WP\SEO\Premium\Presenters\Icons\Checkmark_Icon_Presenter;
use Yoast\WP\SEO\Premium\Presenters\Icons\Cross_Icon_Presenter;
/**
* Cornerstone_Column_Integration class.
*/
class Cornerstone_Column_Integration implements Integration_Interface {
/**
* Name of the column.
*
* @var string
*/
const CORNERSTONE_COLUMN_NAME = 'wpseo-cornerstone';
/**
* The post type helper.
*
* @var Post_Type_Helper
*/
protected $post_type_helper;
/**
* The database object.
*
* @var wpdb
*/
protected $wpdb;
/**
* The admin columns cache.
*
* @var Admin_Columns_Cache_Integration
*/
protected $admin_columns_cache;
/**
* {@inheritDoc}
*/
public static function get_conditionals() {
return [
Admin_Conditional::class,
Posts_Overview_Or_Ajax_Conditional::class,
Cornerstone_Enabled_Conditional::class,
];
}
/**
* Cornerstone_Column_Integration constructor
*
* @codeCoverageIgnore
*
* @param Post_Type_Helper $post_type_helper The post type helper.
* @param wpdb $wpdb The wpdb object.
* @param Admin_Columns_Cache_Integration $admin_columns_cache The admin columns cache.
*/
public function __construct(
Post_Type_Helper $post_type_helper,
wpdb $wpdb,
Admin_Columns_Cache_Integration $admin_columns_cache
) {
$this->post_type_helper = $post_type_helper;
$this->wpdb = $wpdb;
$this->admin_columns_cache = $admin_columns_cache;
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
\add_filter( 'posts_clauses', [ $this, 'order_by_cornerstone' ], 1, 2 );
\add_action( 'admin_init', [ $this, 'register_init_hooks' ] );
// Adds a filter to exclude the attachments from the cornerstone column.
\add_filter( 'wpseo_cornerstone_column_post_types', [ 'WPSEO_Post_Type', 'filter_attachment_post_type' ] );
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
}
/**
* Register hooks that need to be registered after `init` due to all post types not yet being registered.
*/
public function register_init_hooks() {
$public_post_types = \apply_filters( 'wpseo_cornerstone_column_post_types', $this->post_type_helper->get_accessible_post_types() );
if ( ! \is_array( $public_post_types ) || empty( $public_post_types ) ) {
return;
}
foreach ( $public_post_types as $post_type ) {
\add_filter( 'manage_' . $post_type . '_posts_columns', [ $this, 'add_cornerstone_column' ] );
\add_action( 'manage_' . $post_type . '_posts_custom_column', [ $this, 'column_content' ], 10, 2 );
\add_filter( 'manage_edit-' . $post_type . '_sortable_columns', [ $this, 'column_sort' ] );
}
}
/**
* Enqueues the assets needed for the integration to work.
*
* @return void
*/
public function enqueue_assets() {
\wp_enqueue_style( WPSEO_Admin_Asset_Manager::PREFIX . 'premium-post-overview' );
}
/**
* Adds the columns for the post overview.
*
* @param array $columns Array with columns.
*
* @return array The extended array with columns.
*/
public function add_cornerstone_column( $columns ) {
if ( ! \is_array( $columns ) ) {
return $columns;
}
$columns[ self::CORNERSTONE_COLUMN_NAME ] = \sprintf(
'<span class="yoast-column-cornerstone yoast-column-header-has-tooltip" data-tooltip-text="%1$s"><span class="screen-reader-text">%2$s</span></span>',
\esc_attr__( 'Is this cornerstone content?', 'wordpress-seo-premium' ),
/* translators: Hidden accessibility text. */
\esc_html__( 'Cornerstone content', 'wordpress-seo-premium' )
);
return $columns;
}
/**
* Modifies the query pieces to allow ordering column by cornerstone.
*
* @param array $pieces Array of Query pieces.
* @param WP_Query $query The Query on which to apply.
*
* @return array
*/
public function order_by_cornerstone( $pieces, $query ) {
if ( $query->get( 'orderby' ) !== self::CORNERSTONE_COLUMN_NAME ) {
return $pieces;
}
return $this->build_sort_query_pieces( $pieces, $query );
}
/**
* Builds the pieces for a sorting query.
*
* @param array $pieces Array of Query pieces.
* @param WP_Query $query The Query on which to apply.
*
* @return array Modified Query pieces.
*/
protected function build_sort_query_pieces( $pieces, $query ) {
// We only want our code to run in the main WP query.
if ( ! $query->is_main_query() ) {
return $pieces;
}
// Get the order query variable - ASC or DESC.
$order = \strtoupper( $query->get( 'order' ) );
// Make sure the order setting qualifies. If not, set default as ASC.
if ( ! \in_array( $order, [ 'ASC', 'DESC' ], true ) ) {
$order = 'ASC';
}
$table = Model::get_table_name( 'Indexable' );
$pieces['join'] .= " LEFT JOIN $table AS yoast_indexable ON yoast_indexable.object_id = {$this->wpdb->posts}.ID AND yoast_indexable.object_type = 'post' ";
$pieces['orderby'] = "yoast_indexable.is_cornerstone $order, FIELD( {$this->wpdb->posts}.post_status, 'publish' ) $order, {$pieces['orderby']}";
return $pieces;
}
/**
* Displays the column content for the given column.
*
* @param string $column_name Column to display the content for.
* @param int $post_id Post to display the column content for.
*/
public function column_content( $column_name, $post_id ) {
$indexable = $this->admin_columns_cache->get_indexable( $post_id );
// Nothing to output if we don't have the value.
if ( empty( $indexable ) ) {
return;
}
// phpcs:disable WordPress.Security.EscapeOutput -- Reason: The Icons contains safe svg.
if ( $column_name === self::CORNERSTONE_COLUMN_NAME ) {
if ( $indexable->is_cornerstone === true ) {
echo new Checkmark_Icon_Presenter( 20 );
return;
}
echo new Cross_Icon_Presenter( 20 );
}
// phpcs:enable
}
/**
* Sets the sortable columns.
*
* @param array $columns Array with sortable columns.
*
* @return array The extended array with sortable columns.
*/
public function column_sort( $columns ) {
$columns[ self::CORNERSTONE_COLUMN_NAME ] = self::CORNERSTONE_COLUMN_NAME;
return $columns;
}
}

View File

@@ -0,0 +1,139 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Admin_Asset_Manager;
use WPSEO_Taxonomy_Meta;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Premium\Conditionals\Cornerstone_Enabled_Conditional;
use Yoast\WP\SEO\Premium\Presenters\Icons\Checkmark_Icon_Presenter;
use Yoast\WP\SEO\Premium\Presenters\Icons\Cross_Icon_Presenter;
use Yoast\WP\SEO\Premium\Conditionals\Term_Overview_Or_Ajax_Conditional;
use Yoast\WP\SEO\Premium\Helpers\Current_Page_Helper;
/**
* Cornerstone_Taxonomy_Column_Integration class.
*
* phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
*/
class Cornerstone_Taxonomy_Column_Integration implements Integration_Interface {
/**
* Name of the column.
*
* @var string
*/
const CORNERSTONE_COLUMN_NAME = 'wpseo-cornerstone';
/**
* Holds the Current_Page_Helper instance.
*
* @var Current_Page_Helper
*/
private $current_page_helper;
/**
* Returns the posted/get taxonomy value if it is set.
*
* @param Current_Page_Helper $current_page_helper The Current_Page_Helper.
*/
public function __construct( Current_Page_Helper $current_page_helper ) {
$this->current_page_helper = $current_page_helper;
}
/**
* {@inheritDoc}
*/
public static function get_conditionals() {
return [
Admin_Conditional::class,
Term_Overview_Or_Ajax_Conditional::class,
Cornerstone_Enabled_Conditional::class,
];
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
\add_action( 'admin_init', [ $this, 'register_init_hooks' ] );
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
}
/**
* Register hooks that need to be registered after `init` due to all post types not yet being registered.
*/
public function register_init_hooks() {
$taxonomy = $this->current_page_helper->get_current_taxonomy();
$is_product = $this->current_page_helper->get_current_post_type() === 'product';
$is_product_cat = $taxonomy === 'product_cat';
$is_product_tag = $taxonomy === 'product_tag';
if ( ( $is_product && ( $is_product_cat || $is_product_tag ) ) || ( ! $is_product && $taxonomy ) ) {
\add_filter( 'manage_edit-' . $taxonomy . '_columns', [ $this, 'add_cornerstone_column' ] );
\add_filter( 'manage_' . $taxonomy . '_custom_column', [ $this, 'column_content' ], 10, 3 );
}
}
/**
* Enqueues the assets needed for the integration to work.
*
* @return void
*/
public function enqueue_assets() {
\wp_enqueue_style( WPSEO_Admin_Asset_Manager::PREFIX . 'premium-post-overview' );
}
/**
* Adds the cornerstone column for the term overview.
*
* @param array $columns Array with columns.
*
* @return array The extended array with columns.
*/
public function add_cornerstone_column( $columns ) {
if ( ! \is_array( $columns ) ) {
return $columns;
}
$columns[ self::CORNERSTONE_COLUMN_NAME ] = \sprintf(
'<span class="yoast-tooltip yoast-tooltip-n yoast-tooltip-alt" data-label="%1$s">
<span class="yoast-column-cornerstone yoast-column-header-has-tooltip">
<span class="screen-reader-text">%2$s</span>
</span>
</span>',
\esc_attr__( 'Is this cornerstone content?', 'wordpress-seo-premium' ),
/* translators: Hidden accessibility text. */
\esc_html__( 'Cornerstone content', 'wordpress-seo-premium' )
);
return $columns;
}
/**
* Displays the column content for the given column.
*
* @param string $content The current content of the column.
* @param string $column_name The name of the column.
* @param int $term_id ID of requested taxonomy.
*
* @return string
*/
public function column_content( $content, $column_name, $term_id ) {
$is_cornerstone = (int) WPSEO_Taxonomy_Meta::get_term_meta( $term_id, $this->current_page_helper->get_current_taxonomy(), 'is_cornerstone' );
if ( $column_name === self::CORNERSTONE_COLUMN_NAME ) {
if ( $is_cornerstone ) {
// phpcs:disable WordPress.Security.EscapeOutput -- Reason: The Icons contains safe svg.
echo new Checkmark_Icon_Presenter( 20 );
return;
}
echo new Cross_Icon_Presenter( 20 );
}
return $content;
}
}

View File

@@ -0,0 +1,229 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WP_Query;
use wpdb;
use WPSEO_Admin_Asset_Manager;
use Yoast\WP\Lib\Model;
use Yoast\WP\SEO\Conditionals\Admin\Posts_Overview_Or_Ajax_Conditional;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Helpers\Post_Type_Helper;
use Yoast\WP\SEO\Helpers\Score_Icon_Helper;
use Yoast\WP\SEO\Integrations\Admin\Admin_Columns_Cache_Integration;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Premium\Conditionals\Inclusive_Language_Enabled_Conditional;
/**
* Inclusive_Language_Column_Integration class.
*
* phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
*/
class Inclusive_Language_Column_Integration implements Integration_Interface {
/**
* Name of the column.
*
* @var string
*/
const INCLUSIVE_LANGUAGE_COLUMN_NAME = 'wpseo-inclusive-language';
/**
* The post type helper.
*
* @var Post_Type_Helper
*/
protected $post_type_helper;
/**
* The score icon helper.
*
* @var Score_Icon_Helper
*/
protected $score_icon_helper;
/**
* The database object.
*
* @var wpdb
*/
protected $wpdb;
/**
* The admin columns cache.
*
* @var Admin_Columns_Cache_Integration
*/
protected $admin_columns_cache;
/**
* {@inheritDoc}
*/
public static function get_conditionals() {
return [
Admin_Conditional::class,
Posts_Overview_Or_Ajax_Conditional::class,
Inclusive_Language_Enabled_Conditional::class,
];
}
/**
* Inclusive_Language_Column_Integration constructor
*
* @codeCoverageIgnore
*
* @param Post_Type_Helper $post_type_helper The post type helper.
* @param Score_Icon_Helper $score_icon_helper The score icon helper.
* @param wpdb $wpdb The wpdb object.
* @param Admin_Columns_Cache_Integration $admin_columns_cache The admin columns cache.
*/
public function __construct(
Post_Type_Helper $post_type_helper,
Score_Icon_Helper $score_icon_helper,
wpdb $wpdb,
Admin_Columns_Cache_Integration $admin_columns_cache
) {
$this->post_type_helper = $post_type_helper;
$this->score_icon_helper = $score_icon_helper;
$this->wpdb = $wpdb;
$this->admin_columns_cache = $admin_columns_cache;
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
\add_filter( 'posts_clauses', [ $this, 'order_by_inclusive_language_score' ], 1, 2 );
\add_action( 'admin_init', [ $this, 'register_init_hooks' ] );
// Adds a filter to exclude the attachments from the inclusive language column.
\add_filter( 'wpseo_inclusive_language_column_post_types', [ 'WPSEO_Post_Type', 'filter_attachment_post_type' ] );
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
}
/**
* Register hooks that need to be registered after `init` due to all post types not yet being registered.
*/
public function register_init_hooks() {
$public_post_types = \apply_filters( 'wpseo_inclusive_language_column_post_types', $this->post_type_helper->get_accessible_post_types() );
if ( ! \is_array( $public_post_types ) || empty( $public_post_types ) ) {
return;
}
foreach ( $public_post_types as $post_type ) {
\add_filter( 'manage_' . $post_type . '_posts_columns', [ $this, 'add_inclusive_language_column' ] );
\add_action( 'manage_' . $post_type . '_posts_custom_column', [ $this, 'column_content' ], 10, 2 );
\add_filter( 'manage_edit-' . $post_type . '_sortable_columns', [ $this, 'column_sort' ] );
}
}
/**
* Enqueues the assets needed for the integration to work.
*
* @return void
*/
public function enqueue_assets() {
\wp_enqueue_style( WPSEO_Admin_Asset_Manager::PREFIX . 'premium-post-overview' );
}
/**
* Adds the inclusive language column for the post overview.
*
* @param array $columns Array with columns.
*
* @return array The extended array with columns.
*/
public function add_inclusive_language_column( $columns ) {
if ( ! \is_array( $columns ) ) {
return $columns;
}
$columns[ self::INCLUSIVE_LANGUAGE_COLUMN_NAME ] = \sprintf(
'<span class="yoast-column-inclusive-language yoast-column-header-has-tooltip" data-tooltip-text="%1$s"><span class="screen-reader-text">%2$s</span></span>',
\esc_attr__( 'Inclusive language score', 'wordpress-seo-premium' ),
\esc_html__( 'Inclusive language score', 'wordpress-seo-premium' )
);
return $columns;
}
/**
* Modifies the query pieces to allow ordering column by inclusive language score.
*
* @param array $pieces Array of Query pieces.
* @param WP_Query $query The Query on which to apply.
*
* @return array
*/
public function order_by_inclusive_language_score( $pieces, $query ) {
if ( $query->get( 'orderby' ) !== self::INCLUSIVE_LANGUAGE_COLUMN_NAME ) {
return $pieces;
}
return $this->build_sort_query_pieces( $pieces, $query );
}
/**
* Builds the pieces for a sorting query.
*
* @param array $pieces Array of Query pieces.
* @param WP_Query $query The Query on which to apply.
*
* @return array Modified Query pieces.
*/
protected function build_sort_query_pieces( $pieces, $query ) {
// We only want our code to run in the main WP query.
if ( ! $query->is_main_query() ) {
return $pieces;
}
// Get the order query variable - ASC or DESC.
$order = \strtoupper( $query->get( 'order' ) );
// Make sure the order setting qualifies. If not, set default as ASC.
if ( ! \in_array( $order, [ 'ASC', 'DESC' ], true ) ) {
$order = 'ASC';
}
$table = Model::get_table_name( 'Indexable' );
$pieces['join'] .= " LEFT JOIN $table AS yoast_indexable ON yoast_indexable.object_id = {$this->wpdb->posts}.ID AND yoast_indexable.object_type = 'post' ";
$pieces['orderby'] = "yoast_indexable.inclusive_language_score $order, {$pieces['orderby']}";
return $pieces;
}
/**
* Displays the column content for the given column.
*
* @param string $column_name Column to display the content for.
* @param int $post_id Post to display the column content for.
*/
public function column_content( $column_name, $post_id ) {
$indexable = $this->admin_columns_cache->get_indexable( $post_id );
// Nothing to output if we don't have the value.
if ( empty( $indexable ) ) {
return;
}
if ( $column_name === self::INCLUSIVE_LANGUAGE_COLUMN_NAME ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Correctly escaped through the Score_Icon_Helper.
echo $this->score_icon_helper->for_inclusive_language( $indexable->inclusive_language_score );
}
}
/**
* Sets the sortable columns.
*
* @param array $columns Array with sortable columns.
*
* @return array The extended array with sortable columns.
*/
public function column_sort( $columns ) {
$columns[ self::INCLUSIVE_LANGUAGE_COLUMN_NAME ] = self::INCLUSIVE_LANGUAGE_COLUMN_NAME;
return $columns;
}
}

View File

@@ -0,0 +1,165 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Meta;
use WPSEO_Rank;
use Yoast\WP\SEO\Conditionals\Admin\Posts_Overview_Or_Ajax_Conditional;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Premium\Conditionals\Inclusive_Language_Enabled_Conditional;
/**
* Inclusive_Language_Filter_Integration class.
*
* phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
*/
class Inclusive_Language_Filter_Integration implements Integration_Interface {
/**
* {@inheritDoc}
*/
public static function get_conditionals() {
return [
Admin_Conditional::class,
Posts_Overview_Or_Ajax_Conditional::class,
Inclusive_Language_Enabled_Conditional::class,
];
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
// Creates the inclusive language score filter dropdown -- with priority 20 to fire after the SEO/readability filter.
\add_action( 'restrict_manage_posts', [ $this, 'posts_filter_dropdown_inclusive_language' ], 20 );
// Adds the inclusive language score filter to the list of active filters -- if selected for filtering.
\add_filter( 'wpseo_change_applicable_filters', [ $this, 'add_inclusive_language_filter' ] );
// Adds the inclusive language score meta column to the order by part of the query -- if selected for ordering.
\add_filter( 'wpseo_change_order_by', [ $this, 'add_inclusive_language_order_by' ] );
}
/**
* Adds a dropdown that allows filtering on inclusive language score.
*
* @return void
*/
public function posts_filter_dropdown_inclusive_language() {
$ranks = WPSEO_Rank::get_all_inclusive_language_ranks();
echo '<label class="screen-reader-text" for="wpseo-inclusive-language-filter">'
/* translators: Hidden accessibility text. */
. \esc_html__( 'Filter by Inclusive Language Score', 'wordpress-seo-premium' )
. '</label>';
echo '<select name="inclusive_language_filter" id="wpseo-inclusive-language-filter">';
// phpcs:ignore WordPress.Security.EscapeOutput -- Output is correctly escaped in the generate_option() method.
echo $this->generate_option( '', __( 'All Inclusive Language Scores', 'wordpress-seo-premium' ) );
foreach ( $ranks as $rank ) {
$selected = \selected( $this->get_current_inclusive_language_filter(), $rank->get_rank(), false );
// phpcs:ignore WordPress.Security.EscapeOutput -- Output is correctly escaped in the generate_option() method.
echo $this->generate_option( $rank->get_rank(), $rank->get_drop_down_inclusive_language_labels(), $selected );
}
echo '</select>';
}
/**
* Generates an <option> element.
*
* @param string $value The option's value.
* @param string $label The option's label.
* @param string $selected HTML selected attribute for an option.
*
* @return string The generated <option> element.
*/
protected function generate_option( $value, $label, $selected = '' ) {
return '<option ' . $selected . ' value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>';
}
/**
* Retrieves the current inclusive language score filter value from the $_GET variable.
*
* @return string|null The sanitized inclusive language score filter value or null when the variable is not set in $_GET.
*/
public function get_current_inclusive_language_filter() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
if ( isset( $_GET['inclusive_language_filter'] ) && \is_string( $_GET['inclusive_language_filter'] ) ) {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
return \sanitize_text_field( \wp_unslash( $_GET['inclusive_language_filter'] ) );
}
return null;
}
/**
* Determines the inclusive language score filter to the meta query, based on the passed inclusive language filter.
*
* @param string $inclusive_language_filter The inclusive language filter to use to determine what further filter to apply.
*
* @return array The inclusive language score filter.
*/
public function determine_inclusive_language_filters( $inclusive_language_filter ) {
$rank = new WPSEO_Rank( $inclusive_language_filter );
return $this->create_inclusive_language_score_filter( $rank->get_starting_score(), $rank->get_end_score() );
}
/**
* Creates an inclusive language score filter.
*
* @param number $low The lower boundary of the score.
* @param number $high The higher boundary of the score.
*
* @return array The inclusive language score filter.
*/
protected function create_inclusive_language_score_filter( $low, $high ) {
return [
[
'key' => WPSEO_Meta::$meta_prefix . 'inclusive_language_score',
'value' => [ $low, $high ],
'type' => 'numeric',
'compare' => 'BETWEEN',
],
];
}
/**
* Adds the inclusive language filter to the list of active filters -- if it has been used for filtering.
*
* @param array $active_filters The currently active filters.
* @return array The active filters, including the inclusive language filter -- if it has been used for filtering.
*/
public function add_inclusive_language_filter( $active_filters ) {
$inclusive_language_filter = $this->get_current_inclusive_language_filter();
if ( \is_string( $inclusive_language_filter ) && $inclusive_language_filter !== '' ) {
$active_filters = \array_merge(
$active_filters,
$this->determine_inclusive_language_filters( $inclusive_language_filter )
);
}
return $active_filters;
}
/**
* Adds the inclusive language score field to the order by part of the query -- if it has been selected during filtering.
*
* @param array $order_by The current order by statement.
* @param string $order_by_column The column to use for ordering.
* @return array The order by.
*/
public function add_inclusive_language_order_by( $order_by, $order_by_column = '' ) {
if ( $order_by === [] && $order_by_column === Inclusive_Language_Column_Integration::INCLUSIVE_LANGUAGE_COLUMN_NAME ) {
return [
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Reason: Only used when user requests sorting.
'meta_key' => WPSEO_Meta::$meta_prefix . 'inclusive_language_score',
'orderby' => 'meta_value_num',
];
}
return $order_by;
}
}

View File

@@ -0,0 +1,143 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Admin_Asset_Manager;
use WPSEO_Taxonomy_Meta;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Helpers\Score_Icon_Helper;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Premium\Conditionals\Inclusive_Language_Enabled_Conditional;
use Yoast\WP\SEO\Premium\Conditionals\Term_Overview_Or_Ajax_Conditional;
use Yoast\WP\SEO\Premium\Helpers\Current_Page_Helper;
/**
* Inclusive_Language_Column_Integration class.
*
* phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
*/
class Inclusive_Language_Taxonomy_Column_Integration implements Integration_Interface {
/**
* Name of the column.
*
* @var string
*/
const INCLUSIVE_LANGUAGE_COLUMN_NAME = 'wpseo-inclusive-language';
/**
* The score icon helper.
*
* @var Score_Icon_Helper
*/
protected $score_icon_helper;
/**
* Holds the Current_Page_Helper instance.
*
* @var Current_Page_Helper
*/
private $current_page_helper;
/**
* {@inheritDoc}
*/
public static function get_conditionals() {
return [
Admin_Conditional::class,
Term_Overview_Or_Ajax_Conditional::class,
Inclusive_Language_Enabled_Conditional::class,
];
}
/**
* Inclusive_Language_Column_Integration constructor
*
* @param Score_Icon_Helper $score_icon_helper The score icon helper.
* @param Current_Page_Helper $current_page_helper The Current_Page_Helper.
*/
public function __construct(
Score_Icon_Helper $score_icon_helper,
Current_Page_Helper $current_page_helper
) {
$this->score_icon_helper = $score_icon_helper;
$this->current_page_helper = $current_page_helper;
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
\add_action( 'admin_init', [ $this, 'register_init_hooks' ] );
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
}
/**
* Register hooks that need to be registered after `init` due to all post types not yet being registered.
*/
public function register_init_hooks() {
$taxonomy = $this->current_page_helper->get_current_taxonomy();
$is_product = $this->current_page_helper->get_current_post_type() === 'product';
$is_product_cat = $taxonomy === 'product_cat';
$is_product_tag = $taxonomy === 'product_tag';
if ( ( $is_product && ( $is_product_cat || $is_product_tag ) ) || ( ! $is_product && $taxonomy ) ) {
\add_filter( 'manage_edit-' . $taxonomy . '_columns', [ $this, 'add_inclusive_language_column' ] );
\add_filter( 'manage_' . $taxonomy . '_custom_column', [ $this, 'column_content' ], 10, 3 );
}
}
/**
* Enqueues the assets needed for the integration to work.
*
* @return void
*/
public function enqueue_assets() {
\wp_enqueue_style( WPSEO_Admin_Asset_Manager::PREFIX . 'premium-post-overview' );
}
/**
* Adds the inclusive language column for the term overview.
*
* @param array $columns Array with columns.
*
* @return array The extended array with columns.
*/
public function add_inclusive_language_column( $columns ) {
if ( ! \is_array( $columns ) ) {
return $columns;
}
$columns[ self::INCLUSIVE_LANGUAGE_COLUMN_NAME ] = \sprintf(
'<span class="yoast-tooltip yoast-tooltip-n yoast-tooltip-alt" data-label="%1$s">
<span class="yoast-column-inclusive-language yoast-column-header-has-tooltip">
<span class="screen-reader-text">%2$s</span>
</span>
</span>',
\esc_attr__( 'Inclusive language score', 'wordpress-seo-premium' ),
\esc_html__( 'Inclusive language score', 'wordpress-seo-premium' )
);
return $columns;
}
/**
* Displays the column content for the given column.
*
* @param string $content The current content of the column.
* @param string $column_name The name of the column.
* @param int $term_id ID of requested taxonomy.
*
* @return string
*/
public function column_content( $content, $column_name, $term_id ) {
$score = (int) WPSEO_Taxonomy_Meta::get_term_meta( $term_id, $this->current_page_helper->get_current_taxonomy(), 'inclusive_language_score' );
if ( $column_name === self::INCLUSIVE_LANGUAGE_COLUMN_NAME ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Correctly escaped through the Score_Icon_Helper.
return $this->score_icon_helper->for_inclusive_language( $score );
}
return $content;
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WP_Query;
use WPSEO_Meta;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Integrations\Integration_Interface;
/**
* Keyword_Integration class
*/
class Keyword_Integration implements Integration_Interface {
/**
* {@inheritDoc}
*/
public static function get_conditionals() {
return [ Admin_Conditional::class ];
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
\add_filter( 'wpseo_posts_for_focus_keyword', [ $this, 'add_posts_for_focus_keyword' ], 10, 3 );
\add_filter( 'wpseo_posts_for_related_keywords', [ $this, 'add_posts_for_related_keywords' ], 10, 2 );
}
/**
* Enhances the array of posts that share their focus keywords with the post's related keywords by adding posts' ids with the same related keywords.
*
* @param array $usage The array of posts' ids that share their focus keywords with the post.
* @param int $post_id The id of the post we're finding the usage of related keywords for.
*
* @return array The filtered array of posts' ids.
*/
public function add_posts_for_related_keywords( $usage, $post_id ) {
$additional_keywords = \json_decode( WPSEO_Meta::get_value( 'focuskeywords', $post_id ), true );
if ( empty( $additional_keywords ) ) {
return $usage;
}
foreach ( $additional_keywords as $additional_keyword ) {
if ( isset( $additional_keyword['keyword'] ) ) {
$keyword = $additional_keyword['keyword'];
$usage[ $keyword ] = WPSEO_Meta::keyword_usage( $keyword, $post_id );
}
}
return $usage;
}
/**
* Enhances the array of posts that share their focus keywords with the post's focus keywords by adding posts' ids with the same related keywords.
*
* @param array $post_ids The array of posts' ids that share their related keywords with the post.
* @param string $keyword The keyword to search for.
* @param int $post_id The id of the post the keyword is associated to.
*
* @return array The filtered array of posts' ids.
*/
public function add_posts_for_focus_keyword( $post_ids, $keyword, $post_id ) {
$query = [
'meta_query' => [
[
'key' => '_yoast_wpseo_focuskeywords',
'value' => \sprintf( '"keyword":"%s"', $keyword ),
'compare' => 'LIKE',
],
],
'post__not_in' => [ $post_id ],
'fields' => 'ids',
'post_type' => 'any',
/*
* We only need to return zero, one or two results:
* - Zero: keyword hasn't been used before
* - One: Keyword has been used once before
* - Two or more: Keyword has been used twice or more before
*/
'posts_per_page' => 2,
];
$get_posts = new WP_Query( $query );
return \array_merge( $post_ids, $get_posts->posts );
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Options;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Integrations\Integration_Interface;
/**
* Metabox_Formatter_Integration class
*/
class Metabox_Formatter_Integration implements Integration_Interface {
/**
* {@inheritDoc}
*/
public static function get_conditionals() {
return [ Admin_Conditional::class ];
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
\add_filter( 'wpseo_social_template_post_type', [ $this, 'get_template_for_post_type' ], 10, 3 );
\add_filter( 'wpseo_social_template_taxonomy', [ $this, 'get_template_for_taxonomy' ], 10, 3 );
}
/**
* Retrieves a template for a post type.
*
* @param string $template The default template.
* @param string $template_option_name The subname of the option in which the template you want to get is saved.
* @param string $post_type The name of the post type.
*
* @return string
*/
public function get_template_for_post_type( $template, $template_option_name, $post_type ) {
$needed_option = \sprintf( 'social-%s-%s', $template_option_name, $post_type );
if ( WPSEO_Options::get( $needed_option, '' ) !== '' ) {
return WPSEO_Options::get( $needed_option );
}
return $template;
}
/**
* Retrieves a template for a taxonomy.
*
* @param string $template The default template.
* @param string $template_option_name The subname of the option in which the template you want to get is saved.
* @param string $taxonomy The name of the taxonomy.
*
* @return string
*/
public function get_template_for_taxonomy( $template, $template_option_name, $taxonomy ) {
$needed_option = \sprintf( 'social-%s-tax-%s', $template_option_name, $taxonomy );
return WPSEO_Options::get( $needed_option, $template );
}
}

View File

@@ -1,24 +1,24 @@
<?php
namespace Yoast\WP\SEO\Integrations\Admin\Prominent_Words;
namespace Yoast\WP\SEO\Premium\Integrations\Admin\Prominent_Words;
use WPSEO_Language_Utils;
use Yoast\WP\SEO\Actions\Indexing\Indexable_General_Indexation_Action;
use Yoast\WP\SEO\Actions\Indexing\Indexable_Post_Indexation_Action;
use Yoast\WP\SEO\Actions\Indexing\Indexable_Post_Type_Archive_Indexation_Action;
use Yoast\WP\SEO\Actions\Indexing\Indexable_Term_Indexation_Action;
use Yoast\WP\SEO\Actions\Indexing\Indexation_Action_Interface;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Conditionals\Migrations_Conditional;
use Yoast\WP\SEO\Helpers\Language_Helper;
use Yoast\WP\SEO\Helpers\Prominent_Words_Helper;
use Yoast\WP\SEO\Helpers\Url_Helper;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Premium\Actions\Prominent_Words\Content_Action;
use Yoast\WP\SEO\Routes\Prominent_Words_Route;
use Yoast\WP\SEO\Premium\Helpers\Prominent_Words_Helper;
use Yoast\WP\SEO\Premium\Routes\Prominent_Words_Route;
/**
* Class Indexing_Integration.
*
* @package Yoast\WP\SEO\Integrations\Admin\Prominent_Words
*/
class Indexing_Integration implements Integration_Interface {
@@ -39,39 +39,11 @@ class Indexing_Integration implements Integration_Interface {
const PER_INDEXABLE_LIMIT_NO_FUNCTION_WORD_SUPPORT = 30;
/**
* Holds the content action.
* All indexing actions.
*
* @var Content_Action
* @var Indexation_Action_Interface[]
*/
protected $content_indexation_action;
/**
* The post indexing action.
*
* @var Indexable_Post_Indexation_Action
*/
protected $post_indexation_action;
/**
* The term indexing action.
*
* @var Indexable_Term_Indexation_Action
*/
protected $term_indexation_action;
/**
* The post type archive indexing action.
*
* @var Indexable_Post_Type_Archive_Indexation_Action
*/
protected $post_type_archive_indexation_action;
/**
* Represents the general indexing action.
*
* @var Indexable_General_Indexation_Action
*/
protected $general_indexation_action;
protected $indexing_actions;
/**
* Represents the language helper.
@@ -80,6 +52,13 @@ class Indexing_Integration implements Integration_Interface {
*/
protected $language_helper;
/**
* Represents the url helper.
*
* @var Url_Helper
*/
protected $url_helper;
/**
* Represents the prominent words helper.
*
@@ -103,6 +82,7 @@ class Indexing_Integration implements Integration_Interface {
* @param Indexable_General_Indexation_Action $general_indexation_action The general indexing action.
* @param Indexable_Post_Type_Archive_Indexation_Action $post_type_archive_indexation_action The post type archive indexing action.
* @param Language_Helper $language_helper The language helper.
* @param Url_Helper $url_helper The url helper.
* @param Prominent_Words_Helper $prominent_words_helper The prominent words helper.
*/
public function __construct(
@@ -112,15 +92,26 @@ class Indexing_Integration implements Integration_Interface {
Indexable_General_Indexation_Action $general_indexation_action,
Indexable_Post_Type_Archive_Indexation_Action $post_type_archive_indexation_action,
Language_Helper $language_helper,
Url_Helper $url_helper,
Prominent_Words_Helper $prominent_words_helper
) {
$this->content_indexation_action = $content_indexation_action;
$this->post_indexation_action = $post_indexation_action;
$this->term_indexation_action = $term_indexation_action;
$this->general_indexation_action = $general_indexation_action;
$this->post_type_archive_indexation_action = $post_type_archive_indexation_action;
$this->language_helper = $language_helper;
$this->prominent_words_helper = $prominent_words_helper;
$this->language_helper = $language_helper;
$this->url_helper = $url_helper;
$this->prominent_words_helper = $prominent_words_helper;
// Indexation actions are used to calculate the number of unindexed objects.
$this->indexing_actions = [
// Get the number of indexables that haven't had their prominent words indexed yet.
$content_indexation_action,
// Take posts and terms into account that do not have indexables yet.
// These need to be counted again here (in addition to being counted in Free) because them being unindexed
// means that the above prominent words unindexed count couldn't detect these posts/terms for prominent words indexing.
$post_indexation_action,
$term_indexation_action,
$general_indexation_action,
$post_type_archive_indexation_action,
];
}
/**
@@ -135,6 +126,7 @@ class Indexing_Integration implements Integration_Interface {
\add_filter( 'wpseo_indexing_data', [ $this, 'adapt_indexing_data' ] );
\add_filter( 'wpseo_indexing_get_unindexed_count', [ $this, 'get_unindexed_count' ] );
\add_filter( 'wpseo_indexing_get_limited_unindexed_count', [ $this, 'get_limited_unindexed_count' ], 10, 2 );
\add_filter( 'wpseo_indexing_endpoints', [ $this, 'add_endpoints' ] );
}
@@ -202,7 +194,10 @@ class Indexing_Integration implements Integration_Interface {
* @return void
*/
public function enqueue_scripts() {
if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'wpseo_tools' || ( $_GET['page'] === 'wpseo_tools' && isset( $_GET['tool'] ) ) ) {
if ( ! isset( $_GET['page'] )
|| ( $_GET['page'] !== 'wpseo_tools' && $_GET['page'] !== 'wpseo_workouts' && $_GET['page'] !== 'wpseo_dashboard' )
|| ( $_GET['page'] === 'wpseo_tools' && isset( $_GET['tool'] ) )
) {
return;
}
@@ -210,6 +205,7 @@ class Indexing_Integration implements Integration_Interface {
$this->prominent_words_helper->set_indexing_completed( $is_completed );
\wp_enqueue_script( 'yoast-premium-prominent-words-indexation' );
\wp_localize_script( 'yoast-premium-prominent-words-indexation', 'wpseoPremiumIndexationData', [ 'licensedURL' => $this->url_helper->network_safe_home_url() ] );
}
/**
@@ -220,14 +216,27 @@ class Indexing_Integration implements Integration_Interface {
* @return int The total number of indexables to recalculate.
*/
public function get_unindexed_count( $unindexed_count ) {
// Get the number of indexables that haven't had their prominent words indexed yet.
$unindexed_count += $this->content_indexation_action->get_total_unindexed();
foreach ( $this->indexing_actions as $indexing_action ) {
$unindexed_count += $indexing_action->get_total_unindexed();
}
return $unindexed_count;
}
// Take posts and terms into account that do not have indexables yet.
$unindexed_count += $this->post_indexation_action->get_total_unindexed();
$unindexed_count += $this->term_indexation_action->get_total_unindexed();
$unindexed_count += $this->general_indexation_action->get_total_unindexed();
$unindexed_count += $this->post_type_archive_indexation_action->get_total_unindexed();
/**
* Returns a limited number of unindexed objects.
*
* @param int $unindexed_count The unindexed count.
* @param int $limit Limit the number of unindexed objects that are counted.
*
* @return int The total number of unindexed objects.
*/
public function get_limited_unindexed_count( $unindexed_count, $limit ) {
foreach ( $this->indexing_actions as $indexing_action ) {
$unindexed_count += $indexing_action->get_limited_unindexed_count( $limit - $unindexed_count + 1 );
if ( $unindexed_count > $limit ) {
return $unindexed_count;
}
}
return $unindexed_count;
}

View File

@@ -1,6 +1,6 @@
<?php
namespace Yoast\WP\SEO\Integrations\Admin\Prominent_Words;
namespace Yoast\WP\SEO\Premium\Integrations\Admin\Prominent_Words;
use Yoast\WP\SEO\Conditionals\No_Conditionals;
use Yoast\WP\SEO\Integrations\Integration_Interface;
@@ -9,8 +9,6 @@ use Yoast\WP\SEO\Premium\Actions\Prominent_Words\Save_Action;
/**
* Adds a hidden field to the metabox for storing the calculated words and also
* handles the value of it after posting.
*
* @package Yoast\WP\SEO\Integrations\Admin\Prominent_Words
*/
class Metabox_Integration implements Integration_Interface {
@@ -40,7 +38,7 @@ class Metabox_Integration implements Integration_Interface {
\add_filter( 'update_post_metadata', [ $this, 'save_prominent_words_for_post' ], 10, 4 );
\add_filter( 'wpseo_taxonomy_content_fields', [ $this, 'add_words_for_linking_hidden_field' ] );
\add_filter( 'edit_term', [ $this, 'save_prominent_words_for_term' ] );
\add_action( 'edit_term', [ $this, 'save_prominent_words_for_term' ] );
}
/**

View File

@@ -0,0 +1,66 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Meta;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Integrations\Integration_Interface;
/**
* Take related keyphrases into account when filtering posts on keyphrase.
*
* phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
*/
class Related_Keyphrase_Filter_Integration implements Integration_Interface {
/**
* The conditionals that should be met for this integration to be active.
*
* @return string[] A list of fully qualified class names of the `Conditional`s that should be met.
*/
public static function get_conditionals() {
return [ Admin_Conditional::class ];
}
/**
* Register the WordPress hooks needed for this integration to work.
*
* @return void
*/
public function register_hooks() {
\add_filter( 'wpseo_change_keyphrase_filter_in_request', [ $this, 'add_related_keyphrase_filter' ], 10, 2 );
}
/**
* Adapts the keyphrase filter to also take related keyphrases into account.
*
* @param array $keyphrase_filter The current keyphrase filter.
* @param string $keyphrase The keyphrase.
*
* @return array The new keyphrase filter,
*/
public function add_related_keyphrase_filter( $keyphrase_filter, $keyphrase ) {
return [
'relation' => 'OR',
$keyphrase_filter,
$this->get_related_keyphrase_filter( $keyphrase ),
];
}
/**
* Returns the filter to use within the WP Meta Query to filter
* on related keyphrase.
*
* @param string $focus_keyphrase The focus keyphrase to filter on.
*
* @return array The filter.
*/
private function get_related_keyphrase_filter( $focus_keyphrase ) {
return [
'post_type' => \get_query_var( 'post_type', 'post' ),
'key' => WPSEO_Meta::$meta_prefix . 'focuskeywords',
'value' => '"keyword":"' . \sanitize_text_field( $focus_keyphrase ) . '"',
'compare' => 'LIKE',
];
}
}

View File

@@ -0,0 +1,128 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Admin_Asset_Manager;
use WPSEO_Metabox;
use WPSEO_Options;
use WPSEO_Post_Type;
use WPSEO_Taxonomy;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Premium\Helpers\Current_Page_Helper;
/**
* Replacement_Variables_Integration class
*/
class Replacement_Variables_Integration implements Integration_Interface {
/**
* {@inheritDoc}
*/
public static function get_conditionals() {
return [ Admin_Conditional::class ];
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
}
/**
* Enqueue the replacement variables styles and component.
*/
public function enqueue_assets() {
/**
* Filter: 'wpseo_premium_load_emoji_picker' - Allow changing whether the emoji picker is loaded for the meta description and SEO title fields.
*
* Note: This is a Premium plugin-only hook.
*
* @since 19.0
*
* @param bool $load Whether to load the emoji picker.
*/
if ( ! \apply_filters( 'wpseo_premium_load_emoji_picker', true ) ) {
return;
}
$is_elementor_action = false;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
if ( isset( $_GET['action'] ) && \is_string( $_GET['action'] ) ) {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Reason: We are not processing form information, We are only strictly comparing.
$is_elementor_action = ( \wp_unslash( $_GET['action'] ) === 'elementor' );
}
$is_settings_page = false;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
if ( isset( $_GET['page'] ) && \is_string( $_GET['page'] ) ) {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Reason: We are not processing form information, We are only strictly comparing.
$is_settings_page = ( \wp_unslash( $_GET['page'] ) === 'wpseo_page_settings' );
}
if ( ! $is_settings_page && ! $is_elementor_action && ! $this->load_metabox( $this->get_current_page() ) ) {
return;
}
\wp_enqueue_script( 'yoast-seo-premium-draft-js-plugins' );
\wp_enqueue_style( 'yoast-seo-premium-draft-js-plugins' );
$draft_js_external_script_location = 'https://yoast.com/shared-assets/scripts/wp-seo-premium-draft-js-plugins-source-2.0.0.min.js';
if ( \file_exists( \WPSEO_PREMIUM_PATH . 'assets/js/external/draft-js-emoji-picker.min.js' ) ) {
$draft_js_external_script_location = \plugins_url( 'wordpress-seo-premium/assets/js/external/draft-js-emoji-picker.min.js' );
}
\wp_enqueue_script(
'yoast-seo-premium-draft-js-plugins-external',
$draft_js_external_script_location,
[
'yoast-seo-premium-commons',
WPSEO_Admin_Asset_Manager::PREFIX . 'search-metadata-previews',
],
\WPSEO_PREMIUM_VERSION,
false
);
}
/**
* Checks whether or not the metabox related scripts should be loaded.
*
* @codeCoverageIgnore
*
* @param string $current_page The page we are on.
*
* @return bool True when it should be loaded.
*/
protected function load_metabox( $current_page ) {
$page_helper = new Current_Page_Helper();
// When the current page is a term related one.
if ( WPSEO_Taxonomy::is_term_edit( $current_page ) || WPSEO_Taxonomy::is_term_overview( $current_page ) ) {
return WPSEO_Options::get( 'display-metabox-tax-' . $page_helper->get_current_taxonomy() );
}
// When the current page isn't a post related one.
if ( WPSEO_Metabox::is_post_edit( $current_page ) || WPSEO_Metabox::is_post_overview( $current_page ) ) {
return WPSEO_Post_Type::has_metabox_enabled( $page_helper->get_current_post_type() );
}
// Make sure ajax integrations are loaded.
return \wp_doing_ajax();
}
/**
* Retrieves the value of the pagenow variable.
*
* @codeCoverageIgnore
*
* @return string The value of pagenow.
*/
private function get_current_page() {
global $pagenow;
return $pagenow;
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Admin_Asset_Manager;
use Yoast\WP\SEO\Conditionals\Settings_Conditional;
use Yoast\WP\SEO\Helpers\Current_Page_Helper;
use Yoast\WP\SEO\Integrations\Integration_Interface;
/**
* Class Settings_Integration.
*/
class Settings_Integration implements Integration_Interface {
/**
* Holds the WPSEO_Admin_Asset_Manager.
*
* @var WPSEO_Admin_Asset_Manager
*/
protected $asset_manager;
/**
* Holds the Current_Page_Helper.
*
* @var Current_Page_Helper
*/
protected $current_page_helper;
/**
* Constructs Settings_Integration.
*
* @param WPSEO_Admin_Asset_Manager $asset_manager The WPSEO_Admin_Asset_Manager.
* @param Current_Page_Helper $current_page_helper The Current_Page_Helper.
*/
public function __construct( WPSEO_Admin_Asset_Manager $asset_manager, Current_Page_Helper $current_page_helper ) {
$this->asset_manager = $asset_manager;
$this->current_page_helper = $current_page_helper;
}
/**
* Returns the conditionals based on which this loadable should be active.
*
* @return array
*/
public static function get_conditionals() {
return [ Settings_Conditional::class ];
}
/**
* Initializes the integration.
*
* This is the place to register hooks and filters.
*
* @return void
*/
public function register_hooks() {
// Are we on the settings page?
if ( $this->current_page_helper->get_current_yoast_seo_page() === 'wpseo_page_settings' ) {
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
}
}
/**
* Enqueues the assets.
*
* @return void
*/
public function enqueue_assets() {
$this->asset_manager->enqueue_style( 'premium-settings' );
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Admin_Asset_Manager;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Helpers\Options_Helper;
use Yoast\WP\SEO\Integrations\Integration_Interface;
/**
* Thank_You_Page_Integration class
*
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
*/
class Thank_You_Page_Integration implements Integration_Interface {
// phpcs:enable
/**
* The options helper.
*
* @var Options_Helper
*/
protected $options_helper;
/**
* {@inheritDoc}
*/
public static function get_conditionals() {
return [ Admin_Conditional::class ];
}
/**
* Thank_You_Page_Integration constructor.
*
* @param Options_Helper $options_helper The options helper.
*/
public function __construct( Options_Helper $options_helper ) {
$this->options_helper = $options_helper;
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
\add_filter( 'admin_menu', [ $this, 'add_submenu_page' ], 9 );
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
\add_action( 'admin_init', [ $this, 'maybe_redirect' ] );
}
/**
* Redirects to the installation success page if an installation has just occured.
*
* @return void
*/
public function maybe_redirect() {
if ( ! $this->options_helper->get( 'should_redirect_after_install' ) ) {
return;
}
$this->options_helper->set( 'should_redirect_after_install', false );
if ( ! empty( $this->options_helper->get( 'activation_redirect_timestamp' ) ) ) {
return;
}
$this->options_helper->set( 'activation_redirect_timestamp', \time() );
\wp_safe_redirect( \admin_url( 'admin.php?page=wpseo_installation_successful' ), 302, 'Yoast SEO Premium' );
exit;
}
/**
* Adds the workouts submenu page.
*
* @param array $submenu_pages The Yoast SEO submenu pages.
*
* @return array the filtered submenu pages.
*/
public function add_submenu_page( $submenu_pages ) {
\add_submenu_page(
'',
\__( 'Installation Successful', 'wordpress-seo-premium' ),
'',
'manage_options',
'wpseo_installation_successful',
[ $this, 'render_page' ]
);
return $submenu_pages;
}
/**
* Enqueue assets on the Thank you page.
*/
public function enqueue_assets() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Date is not processed or saved.
if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'wpseo_installation_successful' ) {
return;
}
$asset_manager = new WPSEO_Admin_Asset_Manager();
$asset_manager->enqueue_style( 'monorepo' );
\wp_enqueue_style( 'yoast-seo-premium-thank-you' );
}
/**
* Renders the thank you page.
*/
public function render_page() {
require \WPSEO_PREMIUM_PATH . 'classes/views/thank-you.php';
}
}

View File

@@ -0,0 +1,177 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Admin_Asset_Manager;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Helpers\Capability_Helper;
use Yoast\WP\SEO\Helpers\Current_Page_Helper;
use Yoast\WP\SEO\Helpers\Options_Helper;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Premium\Helpers\Version_Helper;
use Yoast\WP\SEO\Presenters\Admin\Notice_Presenter;
/**
* Integration to display a notification urging to update Premium when a new version is available.
*/
class Update_Premium_Notification implements Integration_Interface {
/**
* The options' helper.
*
* @var Options_Helper
*/
private $options_helper;
/**
* The version helper.
*
* @var Version_Helper
*/
private $version_helper;
/**
* The capability helper.
*
* @var Capability_Helper
*/
private $capability_helper;
/**
* The admin asset manager.
*
* @var WPSEO_Admin_Asset_Manager
*/
private $admin_asset_manager;
/**
* The Current_Page_Helper.
*
* @var Current_Page_Helper
*/
private $current_page_helper;
/**
* {@inheritDoc}
*/
public static function get_conditionals() {
return [ Admin_Conditional::class ];
}
/**
* Update_Premium_Notification constructor.
*
* @param Options_Helper $options_helper The options helper.
* @param Version_Helper $version_helper The version helper.
* @param Capability_Helper $capability_helper The capability helper.
* @param WPSEO_Admin_Asset_Manager $admin_asset_manager The admin asset manager.
* @param Current_Page_Helper $current_page_helper The Current_Page_Helper.
*/
public function __construct(
Options_Helper $options_helper,
Version_Helper $version_helper,
Capability_Helper $capability_helper,
WPSEO_Admin_Asset_Manager $admin_asset_manager,
Current_Page_Helper $current_page_helper
) {
$this->options_helper = $options_helper;
$this->version_helper = $version_helper;
$this->capability_helper = $capability_helper;
$this->admin_asset_manager = $admin_asset_manager;
$this->current_page_helper = $current_page_helper;
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
\add_action( 'admin_notices', [ $this, 'maybe_display_notification' ] );
\add_action( 'wp_ajax_dismiss_update_premium_notification', [ $this, 'dismiss_update_premium_notification' ] );
}
/**
* Shows a notice if Free is newer than the minimum required version and Premium has an update available.
*
* @return void
*/
public function maybe_display_notification() {
if ( $this->current_page_helper->get_current_admin_page() === 'update.php' ) {
return;
}
if ( $this->notice_was_dismissed_on_current_premium_version() ) {
return;
}
if ( ! $this->capability_helper->current_user_can( 'wpseo_manage_options' ) ) {
return;
}
// Check whether Free is set to a version later than the minimum required and a Premium update is a available.
if ( $this->version_helper->is_free_upgraded() && $this->version_helper->is_premium_update_available() ) {
$this->admin_asset_manager->enqueue_style( 'monorepo' );
$is_plugins_page = $this->current_page_helper->get_current_admin_page() === 'plugins.php';
$content = \sprintf(
/* translators: 1: Yoast SEO Premium, 2 and 3: opening and closing anchor tag. */
\esc_html__( 'Please %2$supdate %1$s to the latest version%3$s to ensure you can fully use all Premium settings and features.', 'wordpress-seo-premium' ),
'Yoast SEO Premium',
( $is_plugins_page ) ? '' : '<a href="' . \esc_url( \self_admin_url( 'plugins.php' ) ) . '">',
( $is_plugins_page ) ? '' : '</a>'
);
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped -- Output of the title escaped in the Notice_Presenter.
echo new Notice_Presenter(
/* translators: 1: Yoast SEO Premium */
\sprintf( \__( 'Update to the latest version of %1$s!', 'wordpress-seo-premium' ), 'Yoast SEO Premium' ),
$content,
null,
null,
true,
'yoast-update-premium-notification'
);
// phpcs:enable
// Enable permanently dismissing the notice.
echo "<script>
function dismiss_update_premium_notification(){
var data = {
'action': 'dismiss_update_premium_notification',
};
jQuery.post( ajaxurl, data, function( response ) {
jQuery( '#yoast-update-premium-notification' ).hide();
});
}
jQuery( document ).ready( function() {
jQuery( 'body' ).on( 'click', '#yoast-update-premium-notification .notice-dismiss', function() {
dismiss_update_premium_notification();
} );
} );
</script>";
}
}
/**
* Dismisses the old premium notice.
*
* @return bool
*/
public function dismiss_update_premium_notification() {
return $this->options_helper->set( 'dismiss_update_premium_notification', WPSEO_PREMIUM_VERSION );
}
/**
* Returns whether the notification was dismissed in the current Premium version.
*
* @return bool Whether the notification was dismissed in the current Premium version.
*/
protected function notice_was_dismissed_on_current_premium_version() {
$dismissed_notification_version = $this->options_helper->get( 'dismiss_update_premium_notification', '' );
if ( ! empty( $dismissed_notification_version ) ) {
return \version_compare( $dismissed_notification_version, WPSEO_PREMIUM_VERSION, '>=' );
}
return false;
}
}

View File

@@ -174,8 +174,8 @@ class User_Profile_Integration implements Integration_Interface {
* @param int $user_id User ID of the updated user.
*/
public function process_user_option_update( $user_id ) {
$nonce_value = \filter_input( \INPUT_POST, self::NONCE_FIELD_NAME, \FILTER_SANITIZE_STRING );
if ( empty( $nonce_value ) ) {
// I'm keeping this to conform to the original logic.
if ( ! isset( $_POST[ self::NONCE_FIELD_NAME ] ) || ! \is_string( $_POST[ self::NONCE_FIELD_NAME ] ) ) {
return;
}
@@ -184,23 +184,6 @@ class User_Profile_Integration implements Integration_Interface {
\update_user_meta( $user_id, 'wpseo_user_schema', $this->get_posted_user_fields() );
}
/**
* Builds the arguments for filter_var_array which makes sure we only get the fields that we've defined above.
*
* @return array Filter arguments.
*/
private function build_filter_args() {
$args = [];
foreach ( $this->fields as $key => $field ) {
if ( $field['type'] === 'group' ) {
continue;
}
$args[ $key ] = \FILTER_SANITIZE_STRING;
}
return $args;
}
/**
* Gets the posted user fields and sanitizes them.
*
@@ -209,14 +192,12 @@ class User_Profile_Integration implements Integration_Interface {
* @return array The posted user fields, restricted to allowed fields.
*/
private function get_posted_user_fields() {
$args = [
'wpseo_user_schema' => [
'filter' => \FILTER_SANITIZE_STRING,
'flags' => \FILTER_FORCE_ARRAY,
],
];
$user_schema = \filter_input_array( \INPUT_POST, $args )['wpseo_user_schema'];
$user_schema = \filter_var_array( $user_schema, $this->build_filter_args(), false );
$user_schema = [];
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in process_user_option_update.
if ( isset( $_POST['wpseo_user_schema'] ) && \is_array( $_POST['wpseo_user_schema'] ) ) {
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in process_user_option_update.
$user_schema = \array_map( 'sanitize_text_field', \wp_unslash( $_POST['wpseo_user_schema'] ) );
}
foreach ( $this->fields as $key => $object ) {
switch ( $object['type'] ) {

View File

@@ -0,0 +1,180 @@
<?php
namespace Yoast\WP\SEO\Premium\Integrations\Admin;
use WPSEO_Premium_Asset_JS_L10n;
use WPSEO_Shortlinker;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Helpers\Options_Helper;
use Yoast\WP\SEO\Helpers\Post_Type_Helper;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Premium\Helpers\Prominent_Words_Helper;
use Yoast\WP\SEO\Repositories\Indexable_Repository;
/**
* WorkoutsIntegration class
*/
class Workouts_Integration implements Integration_Interface {
/**
* The indexable repository.
*
* @var Indexable_Repository The indexable repository.
*/
private $indexable_repository;
/**
* The shortlinker.
*
* @var WPSEO_Shortlinker
*/
private $shortlinker;
/**
* The options helper.
*
* @var Options_Helper
*/
private $options_helper;
/**
* The prominent words helper.
*
* @var Prominent_Words_Helper
*/
private $prominent_words_helper;
/**
* The post type helper.
*
* @var Post_Type_Helper
*/
private $post_type_helper;
/**
* {@inheritDoc}
*/
public static function get_conditionals() {
return [ Admin_Conditional::class ];
}
/**
* Workouts_Integration constructor.
*
* @param Indexable_Repository $indexable_repository The indexables repository.
* @param WPSEO_Shortlinker $shortlinker The shortlinker.
* @param Options_Helper $options_helper The options helper.
* @param Prominent_Words_Helper $prominent_words_helper The prominent words helper.
* @param Post_Type_Helper $post_type_helper The post type helper.
*/
public function __construct(
Indexable_Repository $indexable_repository,
WPSEO_Shortlinker $shortlinker,
Options_Helper $options_helper,
Prominent_Words_Helper $prominent_words_helper,
Post_Type_Helper $post_type_helper
) {
$this->indexable_repository = $indexable_repository;
$this->shortlinker = $shortlinker;
$this->options_helper = $options_helper;
$this->prominent_words_helper = $prominent_words_helper;
$this->post_type_helper = $post_type_helper;
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
}
/**
* Enqueue the workouts app.
*/
public function enqueue_assets() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Date is not processed or saved.
if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'wpseo_workouts' ) {
return;
}
$workouts_option = $this->options_helper->get( 'workouts' );
$indexable_ids_in_workouts = [ 0 ];
if ( isset( $workouts_option['orphaned']['indexablesByStep'] )
&& \is_array( $workouts_option['orphaned']['indexablesByStep'] )
&& isset( $workouts_option['cornerstone']['indexablesByStep'] )
&& \is_array( $workouts_option['cornerstone']['indexablesByStep'] )
) {
foreach ( [ 'orphaned', 'cornerstone' ] as $workout ) {
foreach ( $workouts_option[ $workout ]['indexablesByStep'] as $step => $indexables ) {
if ( $step === 'removed' ) {
continue;
}
foreach ( $indexables as $indexable_id ) {
$indexable_ids_in_workouts[] = $indexable_id;
}
}
}
}
$orphaned = $this->get_orphaned( $indexable_ids_in_workouts );
$premium_localization = new WPSEO_Premium_Asset_JS_L10n();
$premium_localization->localize_script( 'yoast-seo-premium-workouts' );
\wp_enqueue_script( 'yoast-seo-premium-workouts' );
\wp_localize_script(
'yoast-seo-premium-workouts',
'wpseoPremiumWorkoutsData',
[
'cornerstoneGuide' => $this->shortlinker->build_shortlink( 'https://yoa.st/4el' ),
'orphanedGuide' => $this->shortlinker->build_shortlink( 'https://yoa.st/4fa' ),
'orphanedUpdateContent' => $this->shortlinker->build_shortlink( 'https://yoa.st/4h9' ),
'cornerstoneOn' => $this->options_helper->get( 'enable_cornerstone_content' ),
'seoDataOptimizationNeeded' => ! $this->prominent_words_helper->is_indexing_completed(),
'orphaned' => $orphaned,
]
);
}
/**
* Retrieves the public indexable sub types.
*
* @return array The sub types.
*/
protected function get_public_sub_types() {
$object_sub_types = \array_values(
\array_merge(
$this->post_type_helper->get_public_post_types(),
\get_taxonomies( [ 'public' => true ] )
)
);
$excluded_post_types = \apply_filters( 'wpseo_indexable_excluded_post_types', [ 'attachment' ] );
$object_sub_types = \array_diff( $object_sub_types, $excluded_post_types );
return $object_sub_types;
}
/**
* Gets the orphaned indexables.
*
* @param array $indexable_ids_in_orphaned_workout The orphaned indexable ids.
* @param int $limit The limit.
*
* @return array The orphaned indexables.
*/
protected function get_orphaned( array $indexable_ids_in_orphaned_workout, $limit = 10 ) {
$orphaned = $this->indexable_repository->query()
->where_raw( '( incoming_link_count is NULL OR incoming_link_count < 3 )' )
->where_raw( '( post_status = \'publish\' OR post_status IS NULL )' )
->where_raw( '( is_robots_noindex = FALSE OR is_robots_noindex IS NULL )' )
->where_raw( 'NOT ( object_sub_type = \'page\' AND permalink = %s )', [ \home_url( '/' ) ] )
->where_in( 'object_sub_type', $this->get_public_sub_types() )
->where_in( 'object_type', [ 'post' ] )
->where_not_in( 'id', $indexable_ids_in_orphaned_workout )
->order_by_asc( 'created_at' )
->limit( $limit )
->find_many();
$orphaned = \array_map( [ $this->indexable_repository, 'ensure_permalink' ], $orphaned );
return $orphaned;
}
}