{"id":27437408,"url":"https://github.com/keepsuit/php-liquid","last_synced_at":"2025-08-04T10:38:50.481Z","repository":{"id":183952222,"uuid":"670980466","full_name":"keepsuit/php-liquid","owner":"keepsuit","description":"PHP implementation of Liquid markup language","archived":false,"fork":false,"pushed_at":"2024-04-04T13:05:36.000Z","size":438,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-04-05T14:22:03.305Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/keepsuit.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-07-26T09:13:24.000Z","updated_at":"2024-04-15T11:17:11.749Z","dependencies_parsed_at":"2023-07-26T14:25:19.029Z","dependency_job_id":"9980cb65-113b-4709-99ba-24c071357d6e","html_url":"https://github.com/keepsuit/php-liquid","commit_stats":null,"previous_names":["keepsuit/php-liquid"],"tags_count":14,"template":false,"template_full_name":"spatie/package-skeleton-php","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keepsuit%2Fphp-liquid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keepsuit%2Fphp-liquid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keepsuit%2Fphp-liquid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keepsuit%2Fphp-liquid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/keepsuit","download_url":"https://codeload.github.com/keepsuit/php-liquid/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248954869,"owners_count":21188876,"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":"2025-04-14T20:29:07.904Z","updated_at":"2025-08-04T10:38:50.469Z","avatar_url":"https://github.com/keepsuit.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PHP implementation of Liquid markup language\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/keepsuit/liquid.svg?style=flat-square)](https://packagist.org/packages/keepsuit/liquid)\n[![Tests](https://img.shields.io/github/actions/workflow/status/keepsuit/php-liquid/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/keepsuit/liquid/actions/workflows/run-tests.yml)\n[![Total Downloads](https://img.shields.io/packagist/dt/keepsuit/liquid.svg?style=flat-square)](https://packagist.org/packages/keepsuit/liquid)\n\nThis is a PHP porting of the [Shopify Liquid template engine](https://github.com/Shopify/liquid).\n\nIf you are using laravel, you can use the [laravel-liquid](https://github.com/keepsuit/laravel-liquid) package.\n\nLiquid is a template engine with interesting advantages:\n\n- It is easy to learn and has a simple syntax.\n- It is safe since it does not allow users to run insecure code on your server.\n- It is extensible, allowing you to add your own filters and tags.\n\n## Shopify Liquid version compatibility\n\n|  PHP Liquid | Shopify Liquid |\n|------------:|---------------:|\n|        v0.9 |           v5.8 |\n|        v0.8 |           v5.7 |\n|        v0.7 |           v5.6 |\n| v0.1 - v0.6 |           v5.5 |\n\n#### Differences from Shopify Liquid\n\n- **Error Modes** are not implemented, the parsing is always strict.\n- `include` tag is not implemented because it is deprecated and can be replaced with `render`.\n\n## Installation\n\nYou can install the package via composer:\n\n```bash\ncomposer require keepsuit/liquid\n```\n\n## Usage\n\nCreate a new environment factory instance:\n\n```php\n$environment = \\Keepsuit\\Liquid\\EnvironmentFactory::new()\n    // enable strict variables mode (disabled by default)\n    -\u003esetStrictVariables(true)\n    // enable strict filters mode (disabled by default)\n    -\u003esetStrictFilters(true)\n    // rethrow exceptions instead of rendering them (disabled by default)\n    -\u003esetRethrowErrors(true)\n    // disable lazy parsing (enabled by default)\n    -\u003esetLazyParsing(false)\n    // replace the default error handler\n    -\u003esetErrorHandler(new \\Keepsuit\\Liquid\\ErrorHandlers\\DefaultErrorHandler())\n    // set filesystem used to load templates\n    -\u003esetFilesystem(new \\Keepsuit\\Liquid\\FileSystems\\LocalFileSystem(__DIR__ . '/views'))\n    // set the resource limits\n    -\u003esetResourceLimits(new \\Keepsuit\\Liquid\\ResourceLimits())\n    // register a custom extension\n    -\u003eaddExtension(new CustomExtension())\n    // register a custom tag\n    -\u003eregisterTag(CustomTag::class)\n    // register a custom filters provider\n    -\u003eregisterFilters(CustomFilters::class)\n    // build the environment\n    -\u003ebuild();\n```\n\nThen create a new template instance parsing a liquid template:\n\n```php\n/** @var \\Keepsuit\\Liquid\\Environment $environment */\n\n// Parse from string\n$template = $environment-\u003eparseString('Hello {{ name }}!');\n\n// Parse from template (loaded from filesystem)\n$template = $environment-\u003eparseTemplate('index');\n```\n\nAnd finally render the template:\n\n```php\n/** @var \\Keepsuit\\Liquid\\Environment $environment */\n/** @var \\Keepsuit\\Liquid\\Template $template */\n\n// Create the render context\n$context = $environment-\u003enewRenderContext(\n    // Data available only in the current context\n    data: [\n        'name' =\u003e 'John',\n    ],\n    // Data shared with all sub-contexts\n    staticData: []\n)\n\n$view = $template-\u003erender($context);\n// $view = 'Hello John!';\n```\n\nFor advanced use cases, you can also stream the rendering output (still experimental):\n\n```php\n/** @var \\Keepsuit\\Liquid\\Template $template */\n/** @var \\Keepsuit\\Liquid\\Render\\RenderContext $context */\n\n$stream = $template-\u003estream($context);\n// $stream is a Generator\u003cstring\u003e\n```\n\n## Drops\n\nLiquid support almost any kind of object but in order to have a better control over the accessible data in the templates,\nyou can pass your data as `Drop` objects and have a better control over the accessible data.\nDrops are standard php objects that extend the `Keepsuit\\Liquid\\Drop` class.\nPublic properties and public methods of the class will be accessible in the template as a property.\nYou can also override the `liquidMethodMissing` method to handle undefined properties.\n\nLiquid provides some attributes to control the behavior of the drops:\n- `Hidden`: Hide the method or the property from the template, it cannot be accessed from liquid.\n- `Cache`: Cache the result of the method, it will be called only once and the result will be stored in the drop.\n\n```php\nuse Keepsuit\\Liquid\\Drop;\n\nclass ProductDrop extends Drop {\n    public function __construct(private Product $product) {}\n\n    public function title(): string {\n        return $this-\u003eproduct-\u003etitle;\n    }\n\n    public function price(): float {\n        return round($this-\u003eproduct-\u003eprice, 2);\n    }\n    \n    #[\\Keepsuit\\Liquid\\Attributes\\Cache]\n    public function expensiveOperation(){\n        // complex operation\n    }\n    \n    #[\\Keepsuit\\Liquid\\Attributes\\Hidden]\n    public function buy(){\n        // Do something\n    }\n}\n```\n\nIf you implement the `MapsToLiquid` interface in your domain classes, \nthe liquid renderer will automatically convert your objects to drops.\n\n```php\nuse Keepsuit\\Liquid\\Contracts\\MapsToLiquid;\n\nclass Product implements MapsToLiquid {\n    public function __construct(public string $title, public float $price) {}\n\n    public function toLiquid(): ProductDrop {\n        return new ProductDrop($this);\n    }\n}\n```\n\n## Advanced usage\n\n### Custom tags\n\nTo create a custom tag, you need to create a class that extends the `Keepsuit\\Liquid\\Tag` abstract class (or `Keepsuit\\Liquid\\TagBlock` if tag has a body).\n\n```php\nuse Keepsuit\\Liquid\\Parse\\TagParseContext;\nuse Keepsuit\\Liquid\\Render\\RenderContext;\nuse Keepsuit\\Liquid\\Tag;\n\nclass CustomTag extends Tag\n{\n    public static function tagName(): string\n    {\n        return 'custom';\n    }\n\n    public function render(RenderContext $context): string\n    {\n        return '';\n    }\n\n    public function parse(TagParseContext $context): static\n    {\n        return $this;\n    }\n}\n\n```\n\n\u003e [!NOTE]\n\u003e Take a look at the implementation of default tags to see how to implement `parse` and `render` methods.\n\nThen you need to register the tag in the environment:\n\n```php\n// register when building the environment\n$environment = \\Keepsuit\\Liquid\\EnvironmentFactory::new()\n    -\u003eregisterTag(CustomTag::class)\n    -\u003ebuild();\n\n// or directly in the environment\n$environment-\u003etagRegistry-\u003eregister(CustomTag::class);\n```\n\n### Custom filters\n\nTo create a custom filter, you need to create a class that extends the `Keepsuit\\Liquid\\Filters\\FiltersProvider` abstract class.\n\nEach public method of the class will be registered as a filter. \nYou can \"hide\" a public method with the `Hidden` attribute, so it will not be registered as filter.\n\n```php\nuse Keepsuit\\Liquid\\Filters\\FiltersProvider;\n\nclass CustomFilters extends FiltersProvider\n{\n    public function customFilter(string $value): string\n    {\n        return 'custom '.$value;\n    }\n    \n    #[\\Keepsuit\\Liquid\\Attributes\\Hidden]\n    public function notAFilter(string $value): string\n    {\n        return 'hidden '.$value;\n    }\n}\n```\n\nThen you need to register the filters provider in the environment:\n\n```php\n// register when building the environment\n$environment = \\Keepsuit\\Liquid\\EnvironmentFactory::new()\n    -\u003eregisterFilters(CustomFilters::class)\n    -\u003ebuild();\n\n// or directly in the environment\n$environment-\u003efilterRegistry-\u003eregister(CustomFilters::class);\n```\n\n### Extensions\n\nExtensions allow you to add custom tags, filters, and other features to the liquid environment.\n\nTo create a custom extension, you need to create a class that extends the `Keepsuit\\Liquid\\Extensions\\Extension` abstract class.\n\n```php\nclass CustomExtension extends \\Keepsuit\\Liquid\\Extensions\\Extension\n{\n    public function getTags() : array{\n        return [\n            CustomTag::class,\n        ];\n    }\n    \n    public function getFiltersProviders() : array{\n        return [\n            CustomFilters::class,\n        ];\n    }\n    \n    // custom registers passed to render context\n    public function getRegisters() : array {\n        return [\n            'custom' =\u003e fn() =\u003e 'custom value',\n        ];\n    }\n}\n```\n\nThen you need to register the extension in the environment:\n```php\n// register when building the environment\n$environment = \\Keepsuit\\Liquid\\EnvironmentFactory::new()\n    -\u003eaddExtension(new CustomExtension())\n    -\u003ebuild();\n\n// or directly in the environment\n$environment-\u003eaddExtension(new CustomExtension());\n```\n\n## Custom tags and filters\n\nBy default, only the standard liquid tags and filters are available.\nBut this package provides some custom tags and filters that you can use.\n\n### Tags\n\n- `DynamicRender`: This tag replace the default `Render` tag and allows to render dynamic templates (eg. read template name from a variable).\n\n### Filters\n\n- `TernaryFilter`\n  - `ternary`: adds a ternary operator.\n      ```liquid\n      {{ condition | ternary: true_value, false_value }}\n    \n      # Example\n      {{ true | ternary: 'yes', 'no' }} # yes\n      {{ false | ternary: 'yes', 'no' }} # no\n      ```\n\n## Testing\n\n```bash\ncomposer test\n```\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## Credits\n\n- [Shopify](https://github.com/Shopify/liquid)\n- [Fabio Capucci](https://github.com/cappuc)\n- [All Contributors](../../contributors)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkeepsuit%2Fphp-liquid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkeepsuit%2Fphp-liquid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkeepsuit%2Fphp-liquid/lists"}