Adding Content To Yoast SEO Analysis Using YoastSEOJS

/ Javascript, PHP, Wordpress / by Paul Robinson / 18 Comments
This post was published back on April 12, 2016 and may be outdated. Please use caution when following older tutorials or using older code. After reading be sure to check for newer procedures or updates to code.

I recently received a request from a previous client asking if I could debug why their custom field content had stopped being analysed by their Yoast SEO plugin. It turns out they had updated the plugin and Yoast made a breaking change in regards to adding content to be analysed. To quote Yoast directly:

In the upcoming 3.0 release of Yoast SEO (for WordPress), we’re moving the entire content analysis from the server to the client side. This way our users can get instant feedback on the content they’re writing, while they’re writing it.

With the moving of content analysis to the client side Yoast removed the WordPress hook previously used to add content for analysis. This was obviously the cause of the issue the client was experiencing. To fix this you must create a plugin using Yoast’s new YoastSEOJS system. At the time of creating the plugin there wasn’t much in the way of documentation on how to do it, so I figured I would share my experience to help anyone else having issues.

The short version of what you need to do is register a plugin with YoastSEOJS and have your plugin return the modified content. Unfortunately this plugin is not a standard WordPress plugin and is a special one used by Yoast.

This post has been re-written to be more informative and provide better code. Please follow along again if you previously read this tutorial.

The code for the client was quite specific so I’m instead going to show an example I put together on my local install. First let’s attach our JavaScript file, we haven’t wrote it yet but we can still enqueue it first without any issues.

In your theme’s functions.php file add the following:

Feel free to change the prefix on the function and also the path as needed. Even better add it to a Theme Setup Class but that is outside the scope of this tutorial. The dependency is required and was previously yoast-seo but I recently couldn’t get it to work until I changed it to yoast-seo-admin-script, YMMV.

Note: If the fields are only available on a specific post type, then feel free to add in a conditional to only enqueue the script when it will be needed.

Now for the JavaScript code. Make you JS file and store it where ever you pointed to when en-queuing the script. Now add the following code:

Now there are a lot of areas where they will be specific to the project you are working on, however I know a lot of developers like to use Advanced Custom Fields so I went with that as an example. I’m not going to go into massive detail here since the code is pretty simple (except maybe the use of Prototypes).

Anyway. Here we are registering a plugin with Yoast SEO using a method called registerPlugin. The plugin is called myYoastPlugin, feel free to change the name as you wish. Note that the name of your JavaScript Object (MyYoastPlugin) does not have to match this, but it would be best to keep them at least related if not the same. We then execute a method to grab the data we want to analyse, I’ve just called it getData.

getData should do whatever you need to grab the data. If you need to call something via AJAX, say from an external service, that is fine. If the content is on the page you can just grab the text via JavaScript. Here I have two example Advanced Custom Fields set up. One is a simple text field, the other a TinyMCE editor. Getting content from the text field is easy. Just use a jQuery expression to select it, in ACF’s case it uses acf-field-{field_name} for its IDs, where field name is the name (not label) you gave the field. We assign this to a object variable called custom_content, tell the plugin we are ready and the register our modification method, which will finally add our extra content to the default content area, with Yoast.

Now you might be wondering why we don’t get the TinyMCE field data there. Well from my experience, you cannot. TinyMCE appears to not be initialized at that point and so we instead do it when the getCustomContent method is called. In the case of the ACF TinyMCE field, we need to know its name so we can get the content from the global tinymce object. To do that we target the placeholder textarea that TinyMCE hooks to and get its ID as that happens to be the ID used to in the editors array.

If you are registering the field yourself, the principle should be the same. The only difference would be you wouldn’t need to grab the ID for your TinyMCE field as you’ll have registered it so you would be able to hard-code the name. You could hard-code it with ACF too, but if you change the name via the interface this way it should automatically change in the JS code too.

One last thing we do is actually instantiate our Yoast Plugin, to do that we have to wait until Yoast is initialized. So we listen for Yoast firing its ready event and then instantiate.

That’s it. This tutorial has been rewritten as it was far to specific to my clients needs, thanks to Kevin in the comments below for pointing it out and for help with cleaning up the code. Also the documentation on how to use the Yoast JS system was pretty lacklustre at the time of writing so there may well be better ways to do this, but this seems to work well enough.

If you have any questions, just let me know in the comments below and I will help however I can. Also if you can fit it into 140 characters you can ask me on Twitter @paulbrobinson.

18 Comments

Author’s gravatar

Hi, Paul. Thanks for your post. I’ve been struggling with adding content to Yoast SEO’s content analysis. Specifically, I have two other TinyMCE editors on a custom post type that I want to include in the analysis. I won’t pretend to know as much about this as you but I’m confused about one aspect of your script: It pulls the content to be analyzed from the post meta field “my_super_awesome_post_data”. This doesn’t seem to fit the concept of live content analysis. Is this the only option? Wouldn’t it require that the content would have been saved at some point in order to pull it in? Why not refer to the field on the post editor page that contains the data to be analyzed?

Also, if I’m not mistaken, you’re call to wp_localize_script is missing a couple parentheses at the end of the line.

Reply
Author’s gravatar author

Hi Kevin,

First. Thanks for spotting the mistake on the localize script. I copied this code from my library of scripts and must have missed them. It’s fixed now at least.

Yep. You can grab the data however you wish. In this case the client wanted it to work as it did previously. Yes, that means doing the analysis on save. So I just chose to grab the data from the custom field via AJAX.

By all means grab the content however you feel suits the project or the requests of your client. For standard text fields just grab it via jQuery. In fact you are spot on that I should re-factor this as it is very specific to the client and in no way follows the real-time analysis aspect of Yoast. I’ll get onto rewriting it tonight.

Anyway. Thanks for your comments & hopefully, once re-factored, it will be helpful to you.

Author’s gravatar

I think that was the fastest response I’ve ever gotten to a comment. 🙂 Thanks! First off, your post was a HUGE help once I realized it was doing a couple things I didn’t need. I’m including what I did in my comments below for anyone else who has my issue and finds your post. I hope you don’t mind. Fair warning to others: this could be a clunky implementation but it worked for me.

First, I ended up removing the add_custom_content_to_analysis() function altogether. Again, I’m no expert but I couldn’t seem to get this function to work. To be fair, I didn’t spend much time trying to figure it out. Is there something missing in the example that would make an Ajax call to this function or should it work as written?

Then, I revised the way the javascript file was being enqueued so it only gets included when editing a specific post type. This way I can be sure that the TinyMCE editors the script looks for are on the page.

Finally, I revised the call to getCustomContent to reference the two additional TinyMCE editors that I wanted to analyze thanks to this article: http://stackoverflow.com/questions/5759297/getting-wp-tinymces-content. I changed this…

to this…

Once I did this, the script worked like a charm. It seems like it could be easily changed to accommodate any other fields I might want to include. Now I can stop banging my head on the wall! You have no idea what a lifesaver this post was. Thanks so much!

Reply
Author’s gravatar author

Haha, no worries. I’m busy working so I’m doing other stuff, answering comments etc in between waiting for responses to emails. 😉

Ah, glad it was helpful in some way. AJAX in WP can be a royal pain sometimes, it is probably best not to use that if not needed though, as I mentioned it was specific to the client hence why I want to re-factor the code a little.

Thanks for the code examples. If you are okay with it I’d love to use it to help improve the tutorial.

Also I changed your code so it was code highlighted. I know it messes up the width of the comments, I need to fix that while I have some spare time.

Author’s gravatar

Thanks, Paul! I’m looking forward to seeing how you rewrite the example. Feel free to use what I wrote, such as it is. Again, I really appreciate your help on this!

Author’s gravatar author

Haha. It won’t be anything spectacular, but hopefully it will get the idea across. I decided to go with using Advanced Custom Fields as an example since I know a lot of developers that use if for clients due to how easily it can be integrated into a theme. The same ideas should apply regardless of how the meta boxes are added though.

Still, even if it only helps a little, it’ll be worth the effort.

Author’s gravatar

Just trying to figure this guide out a bit more, as I can’t seem to get it to work at the moment, and I’ve tried different ID’s and combinations to get it to work.

JS loads on the backend just fine, just doesnt seem to update the post count when adding in the new tinymce id from my custom textbox.

Reply
Author’s gravatar author

Hi James,

Have you tried any debugging techniques such as adding in console log calls to make sure the various hooks are being called by Yoast? Is the TinyMCE field being found correctly, if you log it do you get data from it?

Sorry if these are already debugging techniques you have tried, without seeing code it is pretty hard for me to guess any further since, as far as I’m aware, the above code still works. Although I haven’t needed to do this recently so it could have changed.

Author’s gravatar

Hi Paul,
thank you for this tutorial. Concerning the disastrous docs and readme files in Github I was definatly in need of it. And your tutorial gave a nice startpoint.

With view modifications and after a few days ;-)… . I figured out to add a lot of CarbonFields.

In my opinion the most critical thing here are tinymce and rich_text field. It would have been marvellous, if you would have given an example with AJAX.
Once more many thanks for this important und underdescribed Topic here.

Reply
Author’s gravatar author

Hi Friedrich,

Glad the article was helpful. Most of the code I ended up with was very specific to the client so this was really just a quick bit of code I whipped up on my local install to make sure it would work correctly.

In regards to AJAX, was there anything in particular you had trouble with? I didn’t include any AJAX examples as there are a huge number of ways you might grab data and they are generally specific to the project at hand.

Author’s gravatar

Hi Paul,

Thank you for your kind reply. The main part with my AJAX Problems was probably, that I never die used it before. The second critical part was, that together with CarbonField I had no chance to load the richt_text without AJAX, as you did it in your above code. So I firstly ran into wrong direction.

A further intersting and for me not finally determinable thing is the dependency in functions.php. In my case the solution only works, if I have -divergent to your code – no further explicit dependency to any yoast scripts.

Anyway, without your post it would never come to a working solution. Once more many thanks!

Author’s gravatar author

Hi Friedrich,

Ah, I see. I’m afraid I haven’t used CarbonFields so I wasn’t aware of that. I’m glad you managed to work around it though.

A further intersting and for me not finally determinable thing is the dependency in functions.php. In my case the solution only works, if I have -divergent to your code – no further explicit dependency to any yoast scripts.

I’m not 100% sure what you mean here. In my case this was a plugin I created for a client… Well this code is based on code I created for a client. Do you mean it only works if you do not set the script dependency to the Yoast script on wp_enqueue_script? If so then it is possible they have changed the dependency name again.

Author’s gravatar

Hi Paul,

Thank you for putting this guide together. It has been very helpful in making Yoast content analysis work with my custom CMS elements.

Apologies if this has been covered and I have missed it, but is it possible to use the YoastSEO js to account for custom images in the CMS?

At the moment I have some pages that have several images attached through custom CMS inputs (though using the standard WP media uploader window with a customised script), but the content analysis says there are no images attached – I presume it just looks for either a thumbnail image or images loaded into a wysiwyg editor at the moment?

Thanks
Dan

Reply
Author’s gravatar author

Hi Dan,

I haven’t revisited this in a little while. That being said, and this is probably an awful way to go about this, you could grab your image attachment IDs and generate WordPress image tags for them, then append them to the content sent to Yoast.

Like I said, probably not the most elegant or best plan, but I believe you are right in that Yoast detects images in the post content. So if they images will end up in the post content due to how the theme is created I can’t see any reason why you can’t append them to the content Yoast sees.

Does that make sense at all?

Author’s gravatar

Thanks a lot, Paul!

I modified your code to make it recursive on multiple custom wp_editor boxes: it works smoothly!

Reply
Author’s gravatar author

Hi Francesco,

Glad the code helped and I’m glad to know it is still useful even with Yoast being up to version 10 now.

Author’s gravatar

I am so glad to read that this code still works for othersin 2019. I am trying to get Yoast Readability to see my CPT fields, and have modified your code using the code in the comments as well so came up with the following, but it is not working – Yoast still sees 0 text.

I used your first bit of code to load the .js file only on the admin page for that post type. The file is loading fine on my:

But, I don’t seem to have the code in the .JS file right. I am weak on JS /jquery, so have a hard time troubleshooting. I have had problems in the past with (function ($) so I changed that, but still not working. I don’t have any text fields so left that line in, but empty.

Do you see any obvious problems with this code? Thank You!

Admin Note: Adjusted code blocks to use Crayon Syntax Highlighting.

Reply
Author’s gravatar author

Hi KallyM,

I’m afraid I can’t see any issues there. As you’ve said this is quite old and I’m afraid my work hasn’t required me to do any extending to Yoast recently so I’m not 100% up-to-date on if anything has changed.

I will take a look as soon as I can and get back to you, but unfortunately I’m on vacation next week so I may not be as quick as might be needed.

Older Comments
Newer Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

I'll keep your WordPress site up-to-date and working to its best.

Find out more