Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add troubleshooting mode in score endpoints #21891

Merged
merged 2 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,25 @@ public function set_repositories(
/**
* Returns the score results for a content type.
*
* @param Content_Type $content_type The content type.
* @param Taxonomy|null $taxonomy The taxonomy of the term we're filtering for.
* @param int|null $term_id The ID of the term we're filtering for.
* @param Content_Type $content_type The content type.
* @param Taxonomy|null $taxonomy The taxonomy of the term we're filtering for.
* @param int|null $term_id The ID of the term we're filtering for.
* @param bool|null $is_troubleshooting Whether we're in troubleshooting mode.
*
* @return array<array<string, string|int|array<string, string>>> The scores.
*
* @throws Exception When getting score results from the infrastructure fails.
*/
public function get_score_results( Content_Type $content_type, ?Taxonomy $taxonomy, ?int $term_id ): array {
$score_results = $this->score_results_collector->get_score_results( $this->score_groups, $content_type, $term_id );
public function get_score_results( Content_Type $content_type, ?Taxonomy $taxonomy, ?int $term_id, ?bool $is_troubleshooting ): array {
$score_results = $this->score_results_collector->get_score_results( $this->score_groups, $content_type, $term_id, $is_troubleshooting );

if ( $is_troubleshooting === true ) {
$score_results['score_ids'] = clone $score_results['scores'];

foreach ( $score_results['scores'] as &$score ) {
$score = ( $score !== null ) ? \count( \explode( ',', $score ) ) : 0;
}
}

$current_scores_list = $this->current_scores_repository->get_current_scores( $this->score_groups, $score_results, $content_type, $taxonomy, $term_id );
$score_result_object = new Score_Result( $current_scores_list, $score_results['query_time'], $score_results['cache_used'] );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ public function get_current_scores( array $score_groups, array $score_results, C
foreach ( $score_groups as $score_group ) {
$score_name = $score_group->get_name();
$current_score_links = $this->get_current_score_links( $score_group, $content_type, $taxonomy, $term_id );
$score_amount = (int) $score_results['scores']->$score_name;
$score_ids = ( isset( $score_results['score_ids'] ) ) ? $score_results['score_ids']->$score_name : null;

$current_score = new Current_Score( $score_name, (int) $score_results['scores']->$score_name, $current_score_links );
$current_score = new Current_Score( $score_name, $score_amount, $score_ids, $current_score_links );
$current_scores_list->add( $current_score, $score_group->get_position() );
}

Expand Down
20 changes: 19 additions & 1 deletion src/dashboard/domain/score-results/current-score.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ class Current_Score {
*/
private $amount;

/**
* The ids of the current score.
*
* @var string
*/
private $ids;

/**
* The links of the current score.
*
Expand All @@ -33,11 +40,13 @@ class Current_Score {
*
* @param string $name The name of the current score.
* @param int $amount The amount of the current score.
* @param string $ids The ids of the current score.
* @param array<string, string> $links The links of the current score.
*/
public function __construct( string $name, int $amount, ?array $links = null ) {
public function __construct( string $name, int $amount, ?string $ids = null, ?array $links = null ) {
$this->name = $name;
$this->amount = $amount;
$this->ids = $ids;
$this->links = $links;
}

Expand All @@ -59,6 +68,15 @@ public function get_amount(): int {
return $this->amount;
}

/**
* Gets the ids of the current score.
*
* @return string The ids of the current score.
*/
public function get_ids(): ?string {
return $this->ids;
}

/**
* Gets the links of the current score in the expected key value representation.
*
Expand Down
6 changes: 5 additions & 1 deletion src/dashboard/domain/score-results/current-scores-list.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,16 @@ public function to_array(): array {

\ksort( $this->current_scores );

foreach ( $this->current_scores as $current_score ) {
foreach ( $this->current_scores as $key => $current_score ) {
$array[] = [
'name' => $current_score->get_name(),
'amount' => $current_score->get_amount(),
'links' => $current_score->get_links_to_array(),
];

if ( $current_score->get_ids() !== null ) {
$array[ $key ]['ids'] = $current_score->get_ids();
}
}

return $array;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,29 @@ class Readability_Score_Results_Collector implements Score_Results_Collector_Int
* @param Readability_Score_Groups_Interface[] $readability_score_groups All readability score groups.
* @param Content_Type $content_type The content type.
* @param int|null $term_id The ID of the term we're filtering for.
* @param bool|null $is_troubleshooting Whether we're in troubleshooting mode.
*
* @return array<string, object|bool|float> The readability score results for a content type.
*
* @throws Score_Results_Not_Found_Exception When the query of getting score results fails.
*/
public function get_score_results( array $readability_score_groups, Content_Type $content_type, ?int $term_id ) {
public function get_score_results( array $readability_score_groups, Content_Type $content_type, ?int $term_id, ?bool $is_troubleshooting ) {
global $wpdb;
$results = [];

$content_type_name = $content_type->get_name();
$transient_name = self::READABILITY_SCORES_TRANSIENT . '_' . $content_type_name . ( ( $term_id === null ) ? '' : '_' . $term_id );

$transient = \get_transient( $transient_name );
if ( $transient !== false ) {
if ( $is_troubleshooting !== true && $transient !== false ) {
$results['scores'] = \json_decode( $transient, false );
$results['cache_used'] = true;
$results['query_time'] = 0;

return $results;
}

$select = $this->build_select( $readability_score_groups );
$select = $this->build_select( $readability_score_groups, $is_troubleshooting );

$replacements = \array_merge(
\array_values( $select['replacements'] ),
Expand Down Expand Up @@ -105,7 +106,9 @@ public function get_score_results( array $readability_score_groups, Content_Type

$end_time = \microtime( true );

\set_transient( $transient_name, WPSEO_Utils::format_json_encode( $current_scores ), \MINUTE_IN_SECONDS );
if ( $is_troubleshooting !== true ) {
\set_transient( $transient_name, WPSEO_Utils::format_json_encode( $current_scores ), \MINUTE_IN_SECONDS );
}

$results['scores'] = $current_scores;
$results['cache_used'] = false;
Expand All @@ -117,25 +120,30 @@ public function get_score_results( array $readability_score_groups, Content_Type
* Builds the select statement for the readability scores query.
*
* @param Readability_Score_Groups_Interface[] $readability_score_groups All readability score groups.
* @param bool|null $is_troubleshooting Whether we're in troubleshooting mode.
*
* @return array<string, string> The select statement for the readability scores query.
*/
private function build_select( array $readability_score_groups ): array {
private function build_select( array $readability_score_groups, ?bool $is_troubleshooting ): array {
$select_fields = [];
$select_replacements = [];

// When we don't troubleshoot, we're interested in the amount of posts in a group, when we troubleshoot we want to gather the actual IDs.
$select_operation = ( $is_troubleshooting === true ) ? 'GROUP_CONCAT' : 'COUNT';
$selected_info = ( $is_troubleshooting === true ) ? 'I.object_id' : '1';

foreach ( $readability_score_groups as $readability_score_group ) {
$min = $readability_score_group->get_min_score();
$max = $readability_score_group->get_max_score();
$name = $readability_score_group->get_name();

if ( $min === null && $max === null ) {
$select_fields[] = 'COUNT(CASE WHEN I.readability_score = 0 AND I.estimated_reading_time_minutes IS NULL THEN 1 END) AS %i';
$select_fields[] = "{$select_operation}(CASE WHEN I.readability_score = 0 AND I.estimated_reading_time_minutes IS NULL THEN {$selected_info} END) AS %i";
$select_replacements[] = $name;
}
else {
$needs_ert = ( $min === 1 ) ? ' OR (I.readability_score = 0 AND I.estimated_reading_time_minutes IS NOT NULL)' : '';
$select_fields[] = "COUNT(CASE WHEN ( I.readability_score >= %d AND I.readability_score <= %d ){$needs_ert} THEN 1 END) AS %i";
$select_fields[] = "{$select_operation}(CASE WHEN ( I.readability_score >= %d AND I.readability_score <= %d ){$needs_ert} THEN {$selected_info} END) AS %i";
$select_replacements[] = $min;
$select_replacements[] = $max;
$select_replacements[] = $name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ interface Score_Results_Collector_Interface {
/**
* Retrieves the score results for a content type.
*
* @param Score_Groups_Interface[] $score_groups All score groups.
* @param Content_Type $content_type The content type.
* @param int|null $term_id The ID of the term we're filtering for.
* @param Score_Groups_Interface[] $score_groups All score groups.
* @param Content_Type $content_type The content type.
* @param int|null $term_id The ID of the term we're filtering for.
* @param bool|null $is_troubleshooting Whether we're in troubleshooting mode.
*
* @return array<string, string> The score results for a content type.
*/
public function get_score_results( array $score_groups, Content_Type $content_type, ?int $term_id );
public function get_score_results( array $score_groups, Content_Type $content_type, ?int $term_id, ?bool $is_troubleshooting );
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,32 @@ class SEO_Score_Results_Collector implements Score_Results_Collector_Interface {
/**
* Retrieves the SEO score results for a content type.
*
* @param SEO_Score_Groups_Interface[] $seo_score_groups All SEO score groups.
* @param Content_Type $content_type The content type.
* @param int|null $term_id The ID of the term we're filtering for.
* @param SEO_Score_Groups_Interface[] $seo_score_groups All SEO score groups.
* @param Content_Type $content_type The content type.
* @param int|null $term_id The ID of the term we're filtering for.
* @param bool|null $is_troubleshooting Whether we're in troubleshooting mode.
*
* @return array<string, object|bool|float> The SEO score results for a content type.
*
* @throws Score_Results_Not_Found_Exception When the query of getting score results fails.
*/
public function get_score_results( array $seo_score_groups, Content_Type $content_type, ?int $term_id ) {
public function get_score_results( array $seo_score_groups, Content_Type $content_type, ?int $term_id, ?bool $is_troubleshooting ): array {
global $wpdb;
$results = [];

$content_type_name = $content_type->get_name();
$transient_name = self::SEO_SCORES_TRANSIENT . '_' . $content_type_name . ( ( $term_id === null ) ? '' : '_' . $term_id );

$transient = \get_transient( $transient_name );
if ( $transient !== false ) {
if ( $is_troubleshooting !== true && $transient !== false ) {
$results['scores'] = \json_decode( $transient, false );
$results['cache_used'] = true;
$results['query_time'] = 0;

return $results;
}

$select = $this->build_select( $seo_score_groups );
$select = $this->build_select( $seo_score_groups, $is_troubleshooting );

$replacements = \array_merge(
\array_values( $select['replacements'] ),
Expand Down Expand Up @@ -107,7 +108,9 @@ public function get_score_results( array $seo_score_groups, Content_Type $conten

$end_time = \microtime( true );

\set_transient( $transient_name, WPSEO_Utils::format_json_encode( $current_scores ), \MINUTE_IN_SECONDS );
if ( $is_troubleshooting !== true ) {
\set_transient( $transient_name, WPSEO_Utils::format_json_encode( $current_scores ), \MINUTE_IN_SECONDS );
}

$results['scores'] = $current_scores;
$results['cache_used'] = false;
Expand All @@ -118,25 +121,30 @@ public function get_score_results( array $seo_score_groups, Content_Type $conten
/**
* Builds the select statement for the SEO scores query.
*
* @param SEO_Score_Groups_Interface[] $seo_score_groups All SEO score groups.
* @param SEO_Score_Groups_Interface[] $seo_score_groups All SEO score groups.
* @param bool|null $is_troubleshooting Whether we're in troubleshooting mode.
*
* @return array<string, string> The select statement for the SEO scores query.
*/
private function build_select( array $seo_score_groups ): array {
private function build_select( array $seo_score_groups, ?bool $is_troubleshooting ): array {
$select_fields = [];
$select_replacements = [];

// When we don't troubleshoot, we're interested in the amount of posts in a group, when we troubleshoot we want to gather the actual IDs.
$select_operation = ( $is_troubleshooting === true ) ? 'GROUP_CONCAT' : 'COUNT';
$selected_info = ( $is_troubleshooting === true ) ? 'I.object_id' : '1';

foreach ( $seo_score_groups as $seo_score_group ) {
$min = $seo_score_group->get_min_score();
$max = $seo_score_group->get_max_score();
$name = $seo_score_group->get_name();

if ( $min === null || $max === null ) {
$select_fields[] = 'COUNT(CASE WHEN I.primary_focus_keyword_score = 0 OR I.primary_focus_keyword_score IS NULL THEN 1 END) AS %i';
$select_fields[] = "{$select_operation}(CASE WHEN I.primary_focus_keyword_score = 0 OR I.primary_focus_keyword_score IS NULL THEN {$selected_info} END) AS %i";
$select_replacements[] = $name;
}
else {
$select_fields[] = 'COUNT(CASE WHEN I.primary_focus_keyword_score >= %d AND I.primary_focus_keyword_score <= %d THEN 1 END) AS %i';
$select_fields[] = "{$select_operation}(CASE WHEN I.primary_focus_keyword_score >= %d AND I.primary_focus_keyword_score <= %d THEN {$selected_info} END) AS %i";
$select_replacements[] = $min;
$select_replacements[] = $max;
$select_replacements[] = $name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ public function register_routes() {
return \intval( $param );
},
],
'troubleshooting' => [
'required' => false,
'type' => 'bool',
'default' => null,
'sanitize_callback' => 'rest_sanitize_boolean',
],
],
],
]
Expand All @@ -169,7 +175,7 @@ public function get_scores( WP_REST_Request $request ) {
$taxonomy = $this->get_taxonomy( $request['taxonomy'], $content_type );
$term_id = $this->get_validated_term_id( $request['term'], $taxonomy );

$results = $this->score_results_repository->get_score_results( $content_type, $taxonomy, $term_id );
$results = $this->score_results_repository->get_score_results( $content_type, $taxonomy, $term_id, $request['troubleshooting'] );
} catch ( Exception $exception ) {
return new WP_REST_Response(
[
Expand Down
Loading