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

feat: override get_head search request metadata #663

Merged
merged 9 commits into from
Jan 26, 2024
5 changes: 5 additions & 0 deletions .changeset/serious-feet-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@headstartwp/headstartwp": patch
---

Override Yoast head values to fix seo data for search results page.
120 changes: 120 additions & 0 deletions wp/headless-wp/includes/classes/Integrations/YoastSEO.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ public function register() {
add_filter( 'wpseo_sitemap_url', array( $this, 'maybe_override_sitemap_url' ), 10, 2 );

add_filter( 'robots_txt', array( $this, 'maybe_override_sitemap_robots_url' ), 999999 );

// Override Search results yoast head, get_head endpoint currently does't detect search page.
add_filter( 'wpseo_canonical', array( $this, 'override_search_canonical' ), 10, 1 );
add_filter( 'wpseo_title', array( $this, 'override_search_title' ), 10, 1 );
add_filter( 'wpseo_opengraph_title', array( $this, 'override_search_title' ), 10, 1 );
add_filter( 'wpseo_opengraph_url', array( $this, 'override_search_canonical' ), 10, 1 );
}

/**
Expand Down Expand Up @@ -162,4 +168,118 @@ public function maybe_override_sitemap_robots_url( $output ) {

return $output;
}

/**
* Return list of query vars if the request is /yoast/v1/get_head?url and for search URL based on ?s= parameter.
*
* @return boolean|array False if it's not a yoast search rest api request. Search $query_vars if otherwise.
*/
public function get_yoast_search_query_vars() {

if ( ! ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
return false;
}

$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''; // phpcs:ignore

if ( false === strpos( $request_uri, '/yoast/v1/get_head' ) ) {
return false;
}

$url_param = isset( $_GET['url'] ) ? esc_url( wp_unslash( $_GET['url'] ) ) : ''; // phpcs:ignore

if ( filter_var( $url_param, FILTER_VALIDATE_URL ) !== false ) {
$query = wp_parse_url( $url_param, PHP_URL_QUERY );
parse_str( $query, $query_vars );

// Return query vars if search request.
if ( isset( $query_vars['s'] ) ) {
// Get page number into the query vars to build the title.
preg_match( '/\/page\/(\d+)/', $url_param, $matches );
if ( ! empty( $matches ) ) {
$query_vars['page'] = (int) $matches[1];
}

return apply_filters( 'tenup_headless_wp_search_request_query_vars', $query_vars );
}
}

return false;
}

/**
* Custom helper to replace Yoast search title placeholders.
* Assuming only some of the basic variables.
*
* @param string $title The search SEO title
* @param array $query_vars The search query vars.
*
* @return string
*/
public function replace_yoast_search_title_placeholders( $title, $query_vars ) {

$str_replace_mapping = apply_filters(
'tenup_headless_wp_search_title_variables_replacments',
array(
'%%sitename%%' => get_bloginfo( 'name' ),
'%%searchphrase%%' => $query_vars['s'] ?? '',
' %%page%%' => ! empty( $query_vars['page'] ) ? sprintf( ' %s %d', __( 'Page', 'headless-wp' ), $query_vars['page'] ) : '',
'%%sep%%' => \YoastSEO()->helpers->options->get_title_separator() ?? ' ',
)
);

return str_replace( array_keys( $str_replace_mapping ), array_values( $str_replace_mapping ), $title );
}

/**
* Set the missing Yoast Search title.
*
* @param string $title The title.
* @return string
*/
public function override_search_title( $title ) {

$search_request_query_vars = $this->get_yoast_search_query_vars();

if ( ! $search_request_query_vars ) {
return $title;
}

$wpseo_titles = get_option( 'wpseo_titles' );

$title_search_wpseo = '';

// Get user setting for search title, fallback to default search from Yoast SEO.
if ( ! empty( $wpseo_titles ) && ! empty( $wpseo_titles['title-search-wpseo'] ) ) {
$title_search_wpseo = $wpseo_titles['title-search-wpseo'];
} else {
$default_titles = \WPSEO_Option_Titles::get_instance()->get_defaults();
if ( ! empty( $default_titles['title-search-wpseo'] ) ) {
$title_search_wpseo = $default_titles['title-search-wpseo'];
}
}

if ( empty( $title_search_wpseo ) ) {
return $title;
}

return $this->replace_yoast_search_title_placeholders( $title_search_wpseo, $search_request_query_vars );
}

/**
* Yoast doesn't have a canonical for search and returns URL as the homepage URL. Generally https://gus.test/?s=test
* But with headstartwp nextjs app usually there is a route for search page.
* Default is 'search'.
*
* @param string $canonical The canonical URL.
* @return string
*/
public function override_search_canonical( $canonical ) {
if ( $this->get_yoast_search_query_vars() ) {
$search_route = apply_filters( 'tenup_headless_wp_search_route', 'search' );
$canonical = rtrim( $canonical, '/' ) . '/' . $search_route;
}

return $canonical;
}
}
Loading