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

REST API: yoast_head performance issues #15780

Open
stephenheron opened this issue Aug 3, 2020 · 4 comments
Open

REST API: yoast_head performance issues #15780

stephenheron opened this issue Aug 3, 2020 · 4 comments

Comments

@stephenheron
Copy link

Hi,

We use the REST API to get a list of all our posts.

Without the “REST API: Head endpoint” feature enabled it takes us around 400ms - 600ms to get 500 posts via the API. Unfortunately when we enable the “REST API: Head endpoint” this jumps up to around 14 seconds which is quite an increase.

I understand that this time increase might be unavoidable and our use case is probably very rare however it would be good to have a way to disable the ‘yoast_head’ field without having to disable the entire Yoast REST API. An option may already exist but I could not find it.

Thanks,
Stephen

@Djennez
Copy link
Member

Djennez commented Aug 3, 2020

There is no such option available at the moment. I'll mark this as a feature request.

@PrakashKumar0143
Copy link

Hello Yoast,
This is really headache for my mobile app development. It is really taking a lot of time for fetching the posts from my wordpress website using REST API. So could you please suggest me any options to disable the yoast_head or please add it asap. Or else, we will forcefully change it to Rank Math or something else. I hope u r understanding and please help me out here.

@lucymtc
Copy link
Contributor

lucymtc commented Oct 14, 2021

Also having issues when listing posts, seems like yoast_head and yoast_head_json should be added for a post when requesting a single post by id or slug (as well as adding it to single author, etc) but seems like an overkill when listing posts by category for example, the response right now for a list of posts is massive.

@lucymtc
Copy link
Contributor

lucymtc commented Feb 18, 2022

I am sure there is a cleaner solution but this is a quick patch I came up with to only add yoast_head and yoast_head_json data to single post requests (applies to all public post types) if it helps anyone with the same problem.
I forked the plugin and changed the function register_routes inside of wordpress-seo/src/routes/yoast-head-rest-field.php

/**
 * Registers routes with WordPress.
 * 
 * @return void
 */
public function register_routes() {
        global $wp_post_types;

	$public_post_types = $this->post_type_helper->get_public_post_types();

	$parsed         = wp_parse_url( $_SERVER['REQUEST_URI'] );
	$path_prefix = '/wp-json/wp/v2/';
	$paths           = [];
		
	$is_single_post_request = false;
		
	// Creates an array of post type paths which check against later, using the rest_base or rewrite slug.
	if ( ! empty( $public_post_types ) ) {
		foreach ( $public_post_types as $public_post_type => $item ) {
			if ( empty( $wp_post_types[ $public_post_type ] ) ) {
				continue;
			}

			switch (true) {
				case ! empty( $wp_post_types[ $public_post_type ]->rest_base ):
					$slug = $wp_post_types[ $public_post_type ]->rest_base;
					break;
				case ! empty( $wp_post_types[ $public_post_type ]->rewrite ) &&
					 ! empty( $wp_post_types[ $public_post_type ]->rewrite['slug'] ):
						$slug = $wp_post_types[ $public_post_type ]->rewrite['slug'];
					break;
				default:
					$slug = $public_post_type;	
					break;	
			}

			$paths[ $slug ] = $path_prefix . $slug;	
		}
	}

	// Check if the request is by slug.
	if ( in_array( rtrim( $parsed['path'], '/' ), $paths ) && ! empty( $parsed['query'] ) ) {
		$is_single_post_request = false !== strpos( $parsed['query'], 'slug=' );
	}

	// Check if request is by ID.
	if ( ! $is_single_post_request ) {
		$regex_id = '/\/wp-json\/wp\/v2\/(' . join( '|', array_keys( $paths ) ) . ')\/(?P<ID>\d+)/';
		preg_match( $regex_id, $parsed['path'], $matches, PREG_OFFSET_CAPTURE );
		$is_single_post_request = ! empty( $matches['ID'] );
	}

	if ( $is_single_post_request ) {
		foreach ( $public_post_types as $post_type ) {
			$this->register_rest_fields( $post_type, 'for_post' );
		}
	}

	$public_taxonomies = $this->taxonomy_helper->get_public_taxonomies();

	foreach ( $public_taxonomies as $taxonomy ) {
		if ( $taxonomy === 'post_tag' ) {
			$taxonomy = 'tag';
		}
		$this->register_rest_fields( $taxonomy, 'for_term' );
	}

	$this->register_rest_fields( 'user', 'for_author' );
	$this->register_rest_fields( 'type', 'for_post_type_archive' );
}

You can also just hardcode the list of post types in $paths instead of going through that loop.

$paths = [
	'/wp-json/wp/v2/posts',
	'/wp-json/wp/v2/pages',
	'/wp-json/wp/v2/events',
	......
];

If you do so then just replace the regex where join( '|', array_keys( $paths ) with:
$regex_id = '/\/wp-json\/wp\/v2\/(posts|pages|events)\/(?P<ID>\d+)/';

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants