Conversations about creating, managing, and using metafields to store and retrieve custom data for apps and themes.
Hi All,
I was looking to use GraphQL to update a rich text metafield, however found that the metafield required JSON but not in a format converted directly from HTML.
I looked for a solution but failed to find one, I implemented my own solution in PHP and thought I'd share here in case anyone else needs it or could improve my code.
An example of the JSON required by Shopify:
{
"type": "root",
"children": [
{
"type": "heading",
"children": [
{
"type": "text",
"value": "Heading"
}
],
"level": 1
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "bold ",
"bold": true
},
{
"type": "text",
"value": "normal text "
},
{
"type": "text",
"value": "italics",
"italic": true
}
]
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": ""
},
{
"url": "link url",
"title": "link title",
"type": "link",
"children": [
{
"type": "text",
"value": "link",
"italic": true
}
]
},
{
"type": "text",
"value": ""
}
]
},
{
"listType": "unordered",
"type": "list",
"children": [
{
"type": "list-item",
"children": [
{
"type": "text",
"value": "unordered list 1"
}
]
},
{
"type": "list-item",
"children": [
{
"type": "text",
"value": "unordered list 2"
}
]
}
]
},
{
"listType": "ordered",
"type": "list",
"children": [
{
"type": "list-item",
"children": [
{
"type": "text",
"value": "list item 1"
}
]
},
{
"type": "list-item",
"children": [
{
"type": "text",
"value": "list item 2"
}
]
}
]
}
]
}
Solved! Go to the solution
This is an accepted solution.
Here is my solution where you pass the html required for your rich text to html_to_obj and then get the first child within the returned object.
function html_to_obj($html)
{
$dom = new DOMDocument();
$dom->loadHTML($html);
return element_to_obj($dom->documentElement);
}
function element_to_obj($element)
{
$loop = true;
if ($element->tagName == "body") {
$obj = array("type" => "root");
} else {
if (str_starts_with($element->tagName, "h2")) {
$obj = array("type" => "heading", "level" => 2);
} elseif (str_starts_with($element->tagName, "h3")) {
$obj = array("type" => "heading", "level" => 3);
} elseif (str_starts_with($element->tagName, "p")) {
$obj = array("type" => "paragraph");
} elseif (str_starts_with($element->tagName, "a")) {
$obj = array("type" => "link");
} elseif (str_starts_with($element->tagName, "ol")) {
$obj = array("type" => "list", "listType" => "ordered");
} elseif (str_starts_with($element->tagName, "ul")) {
$obj = array("type" => "list", "listType" => "unordered");
} elseif (str_starts_with($element->tagName, "li")) {
$obj = array("type" => "list-item");
} elseif (str_starts_with($element->tagName, "strong")) {
$obj = array("type" => "text", "bold" => true, "value" => $element->childNodes[0]->wholeText);
$loop = false;
} elseif (str_starts_with($element->tagName, "em")) {
$obj = array("type" => "text", "italic" => true, "value" => $element->childNodes[0]->wholeText);
$loop = false;
}
}
if ($loop == true) {
foreach ($element->attributes as $attribute) {
if ($attribute->name == "href") {
$obj["url"] = $attribute->value;
} else {
$obj[$attribute->name] = $attribute->value;
}
}
foreach ($element->childNodes as $subElement) {
echo $subElement->nodeType;
if ($subElement->nodeType == XML_TEXT_NODE) {
$obj["children"][] = array("type" => "text", "value" => $subElement->wholeText);
} elseif ($subElement->nodeType == XML_TEXT_NODE) {
$obj["type"] = "paragraph";
$obj["children"][] = element_to_obj($subElement);
} else {
$obj["children"][] = element_to_obj($subElement);
}
}
}
return $obj;
}
$json = html_to_obj('<h2>Heading</h2><h3>subheadfing</h3><p><strong>Bold </strong>normal text <em>italics</em></p><p><a href="https://www.linkurl.com">link</a></p><ul><li>unordered list 1</li><li>unordered list 2</li></ul><ol><li>list item 1</li><li>list item 2</li></ol>');
echo json_encode($json["children"][0]);
This is an accepted solution.
Here is my solution where you pass the html required for your rich text to html_to_obj and then get the first child within the returned object.
function html_to_obj($html)
{
$dom = new DOMDocument();
$dom->loadHTML($html);
return element_to_obj($dom->documentElement);
}
function element_to_obj($element)
{
$loop = true;
if ($element->tagName == "body") {
$obj = array("type" => "root");
} else {
if (str_starts_with($element->tagName, "h2")) {
$obj = array("type" => "heading", "level" => 2);
} elseif (str_starts_with($element->tagName, "h3")) {
$obj = array("type" => "heading", "level" => 3);
} elseif (str_starts_with($element->tagName, "p")) {
$obj = array("type" => "paragraph");
} elseif (str_starts_with($element->tagName, "a")) {
$obj = array("type" => "link");
} elseif (str_starts_with($element->tagName, "ol")) {
$obj = array("type" => "list", "listType" => "ordered");
} elseif (str_starts_with($element->tagName, "ul")) {
$obj = array("type" => "list", "listType" => "unordered");
} elseif (str_starts_with($element->tagName, "li")) {
$obj = array("type" => "list-item");
} elseif (str_starts_with($element->tagName, "strong")) {
$obj = array("type" => "text", "bold" => true, "value" => $element->childNodes[0]->wholeText);
$loop = false;
} elseif (str_starts_with($element->tagName, "em")) {
$obj = array("type" => "text", "italic" => true, "value" => $element->childNodes[0]->wholeText);
$loop = false;
}
}
if ($loop == true) {
foreach ($element->attributes as $attribute) {
if ($attribute->name == "href") {
$obj["url"] = $attribute->value;
} else {
$obj[$attribute->name] = $attribute->value;
}
}
foreach ($element->childNodes as $subElement) {
echo $subElement->nodeType;
if ($subElement->nodeType == XML_TEXT_NODE) {
$obj["children"][] = array("type" => "text", "value" => $subElement->wholeText);
} elseif ($subElement->nodeType == XML_TEXT_NODE) {
$obj["type"] = "paragraph";
$obj["children"][] = element_to_obj($subElement);
} else {
$obj["children"][] = element_to_obj($subElement);
}
}
}
return $obj;
}
$json = html_to_obj('<h2>Heading</h2><h3>subheadfing</h3><p><strong>Bold </strong>normal text <em>italics</em></p><p><a href="https://www.linkurl.com">link</a></p><ul><li>unordered list 1</li><li>unordered list 2</li></ul><ol><li>list item 1</li><li>list item 2</li></ol>');
echo json_encode($json["children"][0]);