{"id":15022405,"url":"https://github.com/contentful/rich-text.php","last_synced_at":"2025-04-06T13:11:05.569Z","repository":{"id":39674721,"uuid":"147483124","full_name":"contentful/rich-text.php","owner":"contentful","description":"Utilities for the Contentful Rich Text","archived":false,"fork":false,"pushed_at":"2024-12-10T16:06:36.000Z","size":1515,"stargazers_count":12,"open_issues_count":2,"forks_count":9,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-30T12:07:37.224Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.contentful.com","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/contentful.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-05T08:10:37.000Z","updated_at":"2024-12-10T16:06:41.000Z","dependencies_parsed_at":"2023-01-30T11:15:35.396Z","dependency_job_id":"587faed1-419c-4d77-9475-319812bdb195","html_url":"https://github.com/contentful/rich-text.php","commit_stats":{"total_commits":122,"total_committers":11,"mean_commits":"11.090909090909092","dds":0.6147540983606558,"last_synced_commit":"6efb98fcbed91939667c269ff6badde2dbd83542"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contentful%2Frich-text.php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contentful%2Frich-text.php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contentful%2Frich-text.php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contentful%2Frich-text.php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/contentful","download_url":"https://codeload.github.com/contentful/rich-text.php/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247485287,"owners_count":20946398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-24T19:57:54.560Z","updated_at":"2025-04-06T13:11:05.551Z","avatar_url":"https://github.com/contentful.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rich-text.php\n\n[![Packagist](https://img.shields.io/packagist/v/contentful/rich-text.svg?style=for-the-badge)](https://packagist.org/packages/contentful/rich-text)\n[![PHP minimum version](https://img.shields.io/packagist/php-v/contentful/rich-text.svg?style=for-the-badge)](https://packagist.org/packages/contentful/rich-text)\n[![CircleCI](https://img.shields.io/circleci/project/github/contentful/rich-text.php/master.svg?style=for-the-badge)](https://circleci.com/gh/contentful/rich-text.php)\n[![License](https://img.shields.io/github/license/contentful/rich-text.php.svg?style=for-the-badge)](https://packagist.org/packages/contentful/rich-text.php)\n\n\u003e This library is built to help you with the parsing and rendering of the [rich text](https://www.contentful.com/developers/docs/concepts/rich-text/) field type in Contentful. It requires PHP 7.2 and up or PHP 8.0 and up.\n\n## Setup\n\nAdd this package to your application by using [Composer](https://getcomposer.org/) and executing the following command:\n\n``` bash\ncomposer require contentful/rich-text\n```\n\nThen, if you haven't already, include the Composer autoloader:\n\n``` php\nrequire_once 'vendor/autoload.php';\n```\n\n### Parsing\n\nThe method `Contentful\\RichText\\Parser::parseLocalized(array $data, string|null $locale)` accepts a valid, unserialized rich text data structure, and returns an object which implements `Contentful\\RichText\\Node\\NodeInterface`.\nYou will also need a link resolver to instanciate the parser.\n\n``` php\n$parser = new Contentful\\RichText\\Parser($linkResolver);\n\n// Fetch some data from an entry field from Contentful\n\n/** @var Contentful\\RichText\\Node\\NodeInterface $node */\n$node = $parser-\u003eparseLocalized($data, $locale);\n```\n\nThe parser will also automatically resolve any linked assets and entries. To do this correctly, you will need to supply the current locale - otherwise, the parser will resolve the links in the default locale for the given space.\n\nDepending of which type of node it actually is, the hierarchy can be navigated using getter methods. Please refer to the [full list of available nodes](https://github.com/contentful/rich-text.php/tree/master/src/Node) for a complete reference.\n\n### Rendering\n\nThe main purpose of this library is to provide an automated way of rendering nodes. The simplest setup involves just creating an instance of the `Contentful\\RichText\\Renderer` class:\n\n``` php\n$renderer = new Contentful\\RichText\\Renderer();\n\n$output = $renderer-\u003erender($node);\n```\n\nThe library provides defaults for all types of supported nodes. However, it is likely that you will need to override some of these defaults, in order to customize the output. To do this, you will create `NodeRenderer` classes, which implement the `Contentful\\RichText\\NodeRenderer\\NodeRendererInterface` interface:\n\n``` php\nnamespace Contentful\\RichText\\NodeRenderer;\n\nuse Contentful\\RichText\\Node\\NodeInterface;\nuse Contentful\\RichText\\RendererInterface;\n\n/**\n * NodeRendererInterface.\n *\n * A class implementing this interface is responsible for\n * turning a limited subset of objects implementing NodeInterface\n * into a string.\n *\n * The node renderer makes the support for a certain node explicit by\n * implementing the \"supports\" method.\n *\n * The node renderer can also throw an exception during rendering if\n * the given node is not supported.\n */\ninterface NodeRendererInterface\n{\n    /**\n     * Returns whether the current renderer\n     * supports rendering the given node.\n     *\n     * @param NodeInterface $node The node which will be tested\n     *\n     * @return bool\n     */\n    public function supports(NodeInterface $node): bool;\n\n    /**\n     * Renders a node into a string.\n     *\n     * @param RendererInterface $renderer The generic renderer object, which is used for\n     *                                    delegating rendering of nested nodes (such as ListItem in lists)\n     * @param NodeInterface     $node     The node which must be rendered\n     * @param array             $context  Optionally, extra context variables (useful with custom node renderers)\n     *\n     * @throws \\InvalidArgumentException when the given $node is not supported\n     *\n     * @return string\n     */\n    public function render(RendererInterface $renderer, NodeInterface $node, array $context = []): string;\n}\n```\n\nFor instance, if you want to add a class to all `h1` tags, you will have something similar to this:\n\n``` php\nuse Contentful\\RichText\\NodeRenderer\\NodeRendererInterface;\nuse Contentful\\RichText\\Node\\NodeInterface;\nuse Contentful\\RichText\\Node\\Heading1;\nuse Contentful\\RichText\\RendererInterface;\n\nclass CustomHeading1 implements NodeRendererInterface\n{\n    public function supports(NodeInterface $node): bool\n    {\n        return $node instanceof Heading1;\n    }\n\n    public function render(RendererInterface $renderer, NodeInterface $node, array $context = []): string\n    {\n        return '\u003ch1 class=\"my-custom-class\"\u003e'.$renderer-\u003erenderCollection($node-\u003egetContent()).'\u003c/h1\u003e';\n    }\n}\n```\n\nFinally, you will need to tell the main renderer to use your custom node renderer:\n\n``` php\n$renderer-\u003epushNodeRenderer(new CustomHeading1());\n```\n\nNow all instances of `Heading1` node will be rendered using the custom node renderer. You can implement any sort of logic in the `supports` method, and since only an interface is required, you can inject any sort of dependency in the constructor. This is done, for instance, for allowing the use of templating engines such as Twig or Plates:\n\n``` php\nuse Twig\\Environment;\nuse Contentful\\RichText\\NodeRenderer\\NodeRendererInterface;\nuse Contentful\\RichText\\Node\\NodeInterface;\nuse Contentful\\RichText\\Node\\Heading1;\nuse Contentful\\RichText\\RendererInterface;\n\nclass TwigCustomHeading1 implements NodeRendererInterface\n{\n    /**\n     * @var Environment\n     */\n    private $twig;\n\n    public function __construct(Environment $twig)\n    {\n        $this-\u003etwig = $twig;\n    }\n\n    public function supports(NodeInterface $node): bool\n    {\n        return $node instanceof Heading1;\n    }\n\n    public function render(RendererInterface $renderer, NodeInterface $node, array $context = []): string\n    {\n        $context['node'] = $node;\n\n        return $this-\u003etwig-\u003erender('heading1.html.twig', $context);\n    }\n}\n```\n\nThis library provides out-of-the-box support for Twig and Plates, which allow you to call `RenderInterface::render()` and `RenderInterface::renderCollection()` methods from a template. To enable the appropriate extension, just let the Twig environment or Plates engine know about it as described below.\n\n### Twig integration\n\nSetup:\n\n``` php\n$renderer = new Contentful\\RichText\\Renderer();\n\n// Register the Twig extension, which will provide functions\n// rich_text_render() and rich_text_render_collection()\n// in a Twig template\n$extension = new Contentful\\RichText\\Bridge\\TwigExtension($renderer);\n\n/** @var Twig\\Environment $twig */\n$twig-\u003eaddExtension($extension);\n\n// Finally, tell the main renderer about your custom node renderer\n$customTwigHeading1NodeRenderer = new TwigCustomHeading1($twig);\n$renderer-\u003epushNodeRenderer($customTwigHeading1NodeRenderer);\n```\n\nTemplate:\n\n``` twig\n\u003ch1 class=\"my-custom-class\"\u003e{{ rich_text_render_collection(node.content) }}\u003c/h1\u003e  \n```\n\nFor an example implementation of a Twig-based rendering process, check the [test node renderer](https://github.com/contentful/rich-text.php/blob/master/tests/Implementation/TwigNodeRenderer.php) and the [complete integration test](https://github.com/contentful/rich-text.php/blob/master/tests/Integration/TwigNodeRendererTest.php).\n\n### Plates integration\n\nSetup:\n\n``` php\n$renderer = new \\Contentful\\RichText\\Renderer();\n\n// Register the Plates extension, which will provide functions\n// $this-\u003erichTextRender() and $this-\u003erichTextRenderCollection()\n// in a Plates template\n$extension = new \\Contentful\\RichText\\Bridge\\PlatesExtension($renderer);\n\n/** @var League\\Plates\\Engine $plates */\n$plates-\u003eloadExtension($extension);\n\n// Finally, tell the main renderer about your custom node renderer\n$customPlatesHeading1NodeRenderer = new PlatesCustomHeading1($plates);\n$renderer-\u003epushNodeRenderer($customPlatesHeading1NodeRenderer);\n```\n\nTemplate:\n\n``` php\n// The function will output HTML, so remember *not* to escape it using $this-\u003ee()\n\u003c?= $this-\u003erichTextRenderCollection($node-\u003egetContent()) ?\u003e\n```\n\nFor an example implementation of a Plates-based rendering process, check the [test node renderer](https://github.com/contentful/rich-text.php/blob/master/tests/Implementation/PlatesNodeRenderer.php) and the [complete integration test](https://github.com/contentful/rich-text.php/blob/master/tests/Integration/PlatesNodeRendererTest.php).\n\n## How to avoid having the main renderer throw an exception on unknown nodes\n\nThe default renderer behavior for when it does not find an appropriate node renderer is to throw an exception. To avoid this, you must set it up to use a special catch-all node renderer:\n\n``` php\n$renderer = new Contentful\\RichText\\Renderer();\n$renderer-\u003eappendNodeRenderer(new Contentful\\RichText\\NodeRenderer\\CatchAll());\n```\n\nThe special `Contentful\\RichText\\NodeRenderer\\CatchAll` node renderer will return an empty string regardless of the node type. It's important to use the `appendNodeRenderer` instead of the usual `pushNodeRenderer` method to make this special node renderer have the lowest priority, therefore avoiding it intercepting regular node renderers.\n\n## Glossary\n\n| Name | Interface | Description |\n|---|---|---|\n| Node | `Contentful\\RichText\\Node\\NodeInterface` | The PHP representation of a rich text node |\n| Renderer | `Contentful\\RichText\\RendererInterface` | A class which accepts all sorts of nodes, and then delegates rendering to the appropriate node renderer |\n| Node renderer | `Contentful\\RichText\\NodeRenderer\\NodeRendererInterface` | A class whose purpose is to be able to render a specific type of node |\n| Parser | `Contentful\\RichText\\ParserInterface` | A class that's responsible for turning an array of unserialized JSON data into a tree of node objects |\n\n## About Contentful\n\n[Contentful](https://www.contentful.com) is a content management platform for web applications, mobile apps and connected devices. It allows you to create, edit \u0026 manage content in the cloud and publish it anywhere via powerful API. Contentful offers tools for managing editorial teams and enabling cooperation between organizations.\n\n## License\n\nCopyright (c) 2015-2019 Contentful GmbH. Code released under the MIT license. See [LICENSE](LICENSE) for further details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontentful%2Frich-text.php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcontentful%2Frich-text.php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontentful%2Frich-text.php/lists"}