I’m attempting to automatically add alt-texts to the images on my Ghost blog posts using the Admin API, but somehow this all fails when I try a PUT request to update the post – the PUT request works in general (e.g. for updating featured_image_alt), but fails completely on html or mobiledoc.
In short, I can GET the post data just fine, in html or lexical, but PUTting it fails completely. If I send the updated HTML or mobiledoc (converted from HTML), none of it gets through.
Here’s a Python code snippet:
url = f"{ghost_url}ghost/api/admin/posts/{post_id}/"
post = get_post(post_id)
# this works just fine
html = add_alt_texts_to_html(post_id)
data = {}
data["html"] = html
data["mobiledoc"] = html_to_mobiledoc(html)
data["updated_at"] = post["updated_at"]
ghost_token = get_ghost_token(ghost_api_key)
ghost_headers = {
"Authorization": f"Ghost {ghost_token}",
"Content-Type": "application/json",
}
response = requests.put(url, headers=ghost_headers, json=data)
# here it includes the post's original lexical data, without added alt tags. Viewing page in editor also shows no alt tags
print(response.json())
I’m not too fussed about which format I read/write, whether it’s Lexical/Mobiledoc/HTML. I’d prefer HTML, but I’ll go with whatever works at this point
The html field isn’t writeable as it’s generated from the lexical/mobiledoc data which is always the source of truth.
If you want to send HTML and have Ghost convert it to lexical/mobiledoc you need to use PUT /ghost/api/admin/posts/:id/?source=html, just be aware that it’s a conversion so can be lossy if you’re sending unsupported html.
And here’s the function that actually rewrites the post content:
def add_alts(post_id):
post = get_post(post_id)
print(f"- Processing [blue]{post['title']}[/blue]")
# Process post featured image
if not post["feature_image_alt"]:
print("- Adding featured image alt text")
post["feature_image_alt"] = create_alt_text(post["feature_image"])[
:125
] # Ghost is strict on this so I'm putting in hard limit
# Process post body
# convert string to dict
post["lexical"] = json.loads(post["lexical"])
for row in post["lexical"]["root"]["children"]:
if row["type"] == "image":
if not row["alt"]:
alt_text = create_alt_text(row["src"])
row["alt"] = alt_text
# convert dict back to string
post["lexical"] = json.dumps(post["lexical"])
return post