Gato GraphQL + Yoast SEO + ChatGPT + MasterStudy LMS demo
Creating Yoast SEO metadata for MasterStudy LMS courses and lessons using ChatGPT
Automatically generate and update SEO metadata in Yoast for MasterStudy LMS courses and lessons, using ChatGPT

Leonardo Losoviz -


We can use ChatGPT to automatically generate and update SEO metadata for MasterStudy LMS courses and lessons, and store the metadata in Yoast SEO, all with a single Gato GraphQL query.
In this demo, we use GraphQL to:
- Fetch a course or lesson data from MasterStudy LMS
- Call ChatGPT to generate SEO metadata based on the course or lesson data
- Update the Yoast SEO metadata for that course or lesson
We must provide the following variables:
courseOrLessonId
: The ID of the MasterStudy LMS course or lesson to updateopenAIAPIKey
: The API key for the OpenAI API
You must also enable accessing data for the required Custom Post Types: stm-courses
and stm-lessons
.
Here is the GraphQL query:
query GetCourseOrLessonData($courseOrLessonId: ID!) {
courseOrLesson: customPost(by: { id: $courseOrLessonId }, customPostTypes: ["stm-courses", "stm-lessons"]) {
id
...on CustomPost {
title
@export(as: "title")
content
@export(as: "content")
}
...WithMetaData
}
}
query GenerateCourseSEOWithChatGPT(
$openAIAPIKey: String!
$systemMessage: String! = "You are an SEO specialist"
$promptTemplate: String! = """
I'm working on creating the SEO metadata for courses and lessons in my Learning Management System.
Please evaluate the course or lesson data, and generate the following SEO metadata:
- Title
- Excerpt
- Focus Keyword
- Open Graph Title
- Open Graph Description
- Twitter Title
- Twitter Description
The data is:
- Title: {$title}
- Content: {$content}
"""
$model: String! = "gpt-4o-mini"
)
@depends(on: "GetCourseOrLessonData")
{
prompt: _strReplaceMultiple(
search: ["{$title}", "{$content}"],
replaceWith: [$title, $content],
in: $promptTemplate
)
openAIResponse: _sendJSONObjectItemHTTPRequest(input: {
url: "https://api.openai.com/v1/chat/completions",
method: POST,
options: {
auth: {
password: $openAIAPIKey
},
json: {
model: $model,
messages: [
{
role: "system",
content: $systemMessage
},
{
role: "user",
content: $__prompt
},
],
response_format: {
type: "json_schema",
json_schema: {
name: "seo_metadata_response",
strict: true,
schema: {
type: "object",
properties: {
seoMetadata: {
type: "object",
properties: {
title: {
type: "string"
},
excerpt: {
type: "string"
},
focusKeyword: {
type: "string"
},
openGraphTitle: {
type: "string"
},
openGraphDescription: {
type: "string"
},
twitterTitle: {
type: "string"
},
twitterDescription: {
type: "string"
}
},
required: ["title", "excerpt", "focusKeyword", "openGraphTitle", "openGraphDescription", "twitterTitle", "twitterDescription"],
additionalProperties: false
}
},
required: ["seoMetadata"],
additionalProperties: false
}
}
}
}
}
})
@underJSONObjectProperty(by: { key: "choices" })
@underArrayItem(index: 0)
@underJSONObjectProperty(by: { path: "message.content" })
@export(as: "jsonEncodedSeoMetadataResponse")
}
query ExtractSeoMetadata
@depends(on: "GenerateCourseSEOWithChatGPT")
{
decodedSeoMetadataResponse: _strDecodeJSONObject(string: $jsonEncodedSeoMetadataResponse)
@underJSONObjectProperty(by: { path: "seoMetadata" })
@export(as: "seoMetadata")
}
mutation GenerateSeoMetadataAndUpdateYoast(
$courseOrLessonId: ID!
)
@depends(on: "ExtractSeoMetadata")
{
seoMetadataTitle: _objectProperty(
object: $seoMetadata,
by: { key: "title" }
)
seoMetadataExcerpt: _objectProperty(
object: $seoMetadata,
by: { key: "excerpt" }
)
seoMetadataFocusKeyword: _objectProperty(
object: $seoMetadata,
by: { key: "focusKeyword" }
)
seoMetadataOpenGraphTitle: _objectProperty(
object: $seoMetadata,
by: { key: "openGraphTitle" }
)
seoMetadataOpenGraphDescription: _objectProperty(
object: $seoMetadata,
by: { key: "openGraphDescription" }
)
seoMetadataTwitterTitle: _objectProperty(
object: $seoMetadata,
by: { key: "twitterTitle" }
)
seoMetadataTwitterDescription: _objectProperty(
object: $seoMetadata,
by: { key: "twitterDescription" }
)
updateCustomPostMetas(inputs: [
{ id: $courseOrLessonId, key: "_yoast_wpseo_title", value: $__seoMetadataTitle },
{ id: $courseOrLessonId, key: "_yoast_wpseo_metadesc", value: $__seoMetadataExcerpt },
{ id: $courseOrLessonId, key: "_yoast_wpseo_focuskw", value: $__seoMetadataFocusKeyword },
{ id: $courseOrLessonId, key: "_yoast_wpseo_opengraph-title", value: $__seoMetadataOpenGraphTitle },
{ id: $courseOrLessonId, key: "_yoast_wpseo_opengraph-description", value: $__seoMetadataOpenGraphDescription },
{ id: $courseOrLessonId, key: "_yoast_wpseo_twitter-title", value: $__seoMetadataTwitterTitle },
{ id: $courseOrLessonId, key: "_yoast_wpseo_twitter-description", value: $__seoMetadataTwitterDescription }
]) {
status
errors {
__typename
...on ErrorPayload {
message
}
}
}
}
query GenerateAndUpdateCourseOrLessonSeoMetadataAndCheckResults($courseOrLessonId: ID!)
@depends(on: "GenerateSeoMetadataAndUpdateYoast")
{
courseOrLessonResults: customPost(by: { id: $courseOrLessonId }, customPostTypes: ["stm-courses", "stm-lessons"]) {
id
...WithMetaData
}
}
fragment WithMetaData on WithMeta {
metaTitle: metaValue(key: "_yoast_wpseo_title")
metaDesc: metaValue(key: "_yoast_wpseo_metadesc")
focusKeyword: metaValue(key: "_yoast_wpseo_focuskw")
socialFBTitle: metaValue(key: "_yoast_wpseo_opengraph-title")
socialFBDesc: metaValue(key: "_yoast_wpseo_opengraph-description")
socialTwitterTitle: metaValue(key: "_yoast_wpseo_twitter-title")
socialTwitterDesc: metaValue(key: "_yoast_wpseo_twitter-description")
}
The variables would look like this:
{
"courseOrLessonId": "123",
"openAIAPIKey": "sk-..."
}