Support for Yoast plugin REST API fields

Changes are done. @luisherranz, you can review them whenever you can.

It’s interesting to notice that this is the first non-theme package that also depends on @frontity/html2react.

And in state.source.api and state.frontity.url being correctly populated. We should start noting those things.

We should add that to the docs. And maybe we have to start thinking about our dependency system :smile:

Unforunately, this is a bad API for TypeScript. We have the same problem than when we do:

const data = state.source.get(state.router.link);

if (data.isPostType) {
  //...
}

So if we want to maintain this API, we are going to need to apply the same APIs than we are going to use for the other case:

import { isPostType } from "@frontity/source";

const data = state.source.get(state.router.link);

if (isPostType(data)) {
  //...
}

Maybe we can use the very same functions for both cases, to avoid two separate APIs:

import { isPostType } from "@frontity/source";

const entity = state.source.entity(state.router.link);

if (isPostType(entity)) {
  //...
}

But we need something. Manual casting is not good enough if our goal is to have good TypeScript support in Frontity.

I guess we can distinguish between post types, taxonomies, authors and so on just by looking at their props, can’t we?


I’m thinking about approving the PR now and solve this in this issue, which is also in the current sprint: TypeScript 3.9 breaks @frontity/source types.

@david we can tomorrow about this.

Oh, my mistake, we can’t use the same functions because we need the arg is Type syntax and the types are different.

function isTaxonomy(data: Data): data is TaxonomyData {
  return (data as TaxonomyData).isTaxonomy === true;
}

function isTaxonomy(entity: Entity): entity is TaxonomyEntity {
  return !!(entity as TaxonomyEntity).taxonomy;
}

Then maybe we need to distinguish between those with different entry points:

import { isPostType } from "@frontity/source/data";

const data = state.source.get(state.router.link);

if (isPostType(data)) {
  //...
}
import { isPostType } from "@frontity/source/entity";

const entity = state.source.entity(state.router.link);

if (isPostType(entity)) {
  //...
}

Or different namings:

import { isPostTypeData } from "@frontity/source";

const data = state.source.get(state.router.link);

if (isPostTypeData(data)) {
  //...
}
import { isPostTypeEntity } from "@frontity/source";

const entity = state.source.entity(state.router.link);

if (isPostTypeEntity(entity)) {
  //...
}

Right, I see your point.

I implemented state.source.entity() this way because for me it wasn’t clear how to know the type of an entity depending on the given link but I didn’t realize it is the same case as state.source.data!

Using type guards here it’s a good idea. :+1:

By the way, would it be a good idea to add a warning when the yoast_head tag is not found?

In case people have not installed Yoast or the version is lower than 14…

It makes sense to me. Maybe also do the opposite in the head-tags package? If yoast_head is found we could recommend to use this package instead.

The new implementation has been released :tada: : Read the full Release Announcement .

This means that if you are using Yoast ^14.0, you should use this new package . And, if you’re using a previous version where the REST API is not supported by the Yoast plugin, or you use other SEO plugin, you can use the @frontity/head-tags package.

A quick demo of it:

2 Likes

Revisiting this thread, I think I forgot something important to mention!

In order to embed the post types – which are the entities that contain the yoast_meta field for post type archives (i.e. the homepage or the archive of a custom post type) – in the REST API responses, you would need to include some code in your WordPress site similar to the following one:

add_action( 'rest_api_init', function () {
  foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) {
    if ( 'post' === $post_type->name || $post_type->has_archive ) {
      add_filter( "rest_prepare_{$post_type->name}", function ( $response ) {
        $type      = $response->data['type'];
        $types_url = rest_url( "wp/v2/types/$type" );

        $response->add_links(
          array(
            'type' => array(
              'href'       => $types_url,
              'embeddable' => true,
            ),
          )
        );

        return $response;
      } );
    }
  }
} );

That code adds the type inside the _links field of post entities and makes it embeddable so type entities are included when Frontity makes calls to the WordPress REST API.

3 Likes

I’m trying to use the transformLinks.base property but it doesn’t seem to work, and when I tried to find in the code how that is working, I couldn’t find where that transformation is being done. Could you help me here?

Hi @orballo :wave:

The @frontity/yoast package transforms links inside the useYoastHead hook, defined in /src/hooks/index.ts:

The function transformAllLinks() is defined in /src/utils/index.ts and uses transformLink() – defined in the @frontity/head-tags package – under the hood.

The property state.yoast.transformLinks.base is not documented yet but it is explained in the TSDocs:

WordPress URL base that must be replaced by the Frontity URL base (specified in state.frontity.url). If this value is not set, it is computed from state.source.api.


What’s exactly the problem you have? Is there a way to reproduce it?

1 Like

Thanks! I don’t know exactly what I was doing, I think I forgot to add the base to the slim version of the site, and therefore it wasn’t working :sweat_smile:

But everything works fine now!

Glad to hear that. :smile:

I’ve just noticed that we are not saying anything in the Readme about the snippet that needs to be added in PHP, this one: Support for Yoast plugin REST API fields.

I think that is misleading because there are no docs yet for @frontity/yoast and all people have is the readme: https://www.npmjs.com/package/@frontity/yoast

@juanma what do you think? Should we fix this now or should we wait for the official docs?

@luisherranz

The docs for @frontity/yoast are currently being prepared and will cover the PHP snippet.

Perfect, thank you :slightly_smiling_face:

Do you guys think that it makes sense to say in the docs that in the future that snippet will be included in the Frontity WordPress Plugin? Or is it better not to mention the Frontity WordPress Plugin?

cc: @juanma

I would leave it out of the docs for now. Currently it needs to be added to the WP theme’s functions.php file so I would leave it at that.

@David

I don’t completely understand what you’re saying in this post.

By “post types” do you mean Custom Post Types? I can’t find any other reference to the yoast_meta field. Can you explain what that is.

When you refer to “the homepage or the archive of a custom post type” are you intending “homepage” and “archive” to mean the same thing, or are they different things?

I’m also not sure what this means: " That code adds the type inside the _links field of post entities".

It would be great if you could provide more clarity here.

By “post types” I mean the entities that represent the types, i.e. those returned by the /wp-json/wp/v2/types endpoint.

You can see an example here: https://test.frontity.org/wp-json/wp/v2/types

When I said homepage I was refering to the the archive of posts, which is usually the homepage. It could be rephrased as “the archive of posts, or the archive of a custom post type”.

Those archives are like categories or tags, but the entity with the name, description, and so on, is returned by the types endpoint (as mentioned before).

I’m not sure if that way is more clear or not. :sweat_smile:

In the entities that the WP REST API returns, there is a field called _links that basically links it with other related entities (more info here). Those links make the linked entity to be included when using the _embed=true query param.

In this case, when any post is requested using _embed=true, the post type entity is embedded as well and populated in the frontity store. That way, you don’t have to do a different request to get the post type entity. Something similar happens with categories and tags, but those are linked by default.

By the way, the specific code that adds the link is this one:

$response->add_links(
  array(
    'type' => array(
      'href'       => $types_url,
      'embeddable' => true,
    ),
  )
);

Hope this clarifies your questions! :raised_hands:

I think it’s better not to do references to things that are not available for the user.

In the meantime, I’ve opened this issue so we can add notes of those things we’d like to add to the documentation referencing to the Embedded Mode (or the Frontity plugin, that I understand it’s the same thing) once that documentation is available

1 Like