PHPackages                             keepsuit/liquid - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Templating &amp; Views](/categories/templating)
4. /
5. keepsuit/liquid

ActiveLibrary[Templating &amp; Views](/categories/templating)

keepsuit/liquid
===============

PHP implementation of liquid markup language

v0.10.0(2w ago)1888.7k↑227%2[2 issues](https://github.com/keepsuit/php-liquid/issues)3MITPHPPHP ^8.2CI passing

Since Aug 30Pushed 1w ago3 watchersCompare

[ Source](https://github.com/keepsuit/php-liquid)[ Packagist](https://packagist.org/packages/keepsuit/liquid)[ Docs](https://github.com/keepsuit/php-liquid)[ RSS](/packages/keepsuit-liquid/feed)WikiDiscussions main Synced yesterday

READMEChangelog (10)Dependencies (25)Versions (33)Used By (3)

PHP implementation of Liquid markup language
============================================

[](#php-implementation-of-liquid-markup-language)

[![Latest Version on Packagist](https://camo.githubusercontent.com/e2cd8cf205232b591ab88986f5edca23fa7735d7c32488bacef8979bf40b5199/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b656570737569742f6c69717569642e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/keepsuit/liquid)[![Tests](https://camo.githubusercontent.com/c17495e199b7cc2f2810ff77b8f120e8555414f980ea34c4e633c7575c83e8b9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6b656570737569742f7068702d6c69717569642f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/keepsuit/liquid/actions/workflows/run-tests.yml)[![Total Downloads](https://camo.githubusercontent.com/f5c039492ad6a74fac8018a5573cfeb8df2485ed0b77c049d37100ef873b4321/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6b656570737569742f6c69717569642e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/keepsuit/liquid)

This is a PHP porting of the [Shopify Liquid template engine](https://github.com/Shopify/liquid).

If you are using laravel, you can use the [laravel-liquid](https://github.com/keepsuit/laravel-liquid) package.

Liquid is a template engine with interesting advantages:

- It is easy to learn and has a simple syntax.
- It is safe since it does not allow users to run insecure code on your server.
- It is extensible, allowing you to add your own filters and tags.

Shopify Liquid version compatibility
------------------------------------

[](#shopify-liquid-version-compatibility)

PHP LiquidShopify Liquidv0.10v5.12v0.9v5.8v0.8v5.7v0.7v5.6v0.1 - v0.6v5.5#### Differences from Shopify Liquid

[](#differences-from-shopify-liquid)

- **Error Modes** are not implemented, the parsing is always strict.
- `include` tag is not implemented because it is deprecated and can be replaced with `render`.

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require keepsuit/liquid
```

Usage
-----

[](#usage)

Create a new environment factory instance:

```
$environment = \Keepsuit\Liquid\EnvironmentFactory::new()
    // enable strict variables mode (disabled by default)
    ->setStrictVariables(true)
    // enable strict filters mode (disabled by default)
    ->setStrictFilters(true)
    // rethrow exceptions instead of rendering them (disabled by default)
    ->setRethrowErrors(true)
    // disable lazy parsing (enabled by default)
    ->setLazyParsing(false)
    // replace the default error handler
    ->setErrorHandler(new \Keepsuit\Liquid\ErrorHandlers\DefaultErrorHandler())
    // set filesystem used to load templates
    ->setFilesystem(new \Keepsuit\Liquid\FileSystems\LocalFileSystem(__DIR__ . '/views'))
    // set the resource limits
    ->setResourceLimits(new \Keepsuit\Liquid\Render\ResourceLimits(
        renderLengthLimit: 100_000,
        renderScoreLimit: 50_000,
        assignScoreLimit: 5_000,
        cumulativeRenderScoreLimit: 100_000,
        cumulativeAssignScoreLimit: 10_000,
    ))
    // register a custom extension
    ->addExtension(new CustomExtension())
    // register a custom tag
    ->registerTag(CustomTag::class)
    // register a custom filters provider
    ->registerFilters(CustomFilters::class)
    // build the environment
    ->build();
```

Then create a new template instance parsing a liquid template:

```
/** @var \Keepsuit\Liquid\Environment $environment */

// Parse from string
$template = $environment->parseString('Hello {{ name }}!');

// Parse from template (loaded from filesystem)
$template = $environment->parseTemplate('index');
```

And finally render the template:

```
/** @var \Keepsuit\Liquid\Environment $environment */
/** @var \Keepsuit\Liquid\Template $template */

// Create the render context
$context = $environment->newRenderContext(
    // Data available only in the current context
    data: [
        'name' => 'John',
    ],
    // Data shared with all sub-contexts
    staticData: []
)

$view = $template->render($context);
// $view = 'Hello John!';
```

For advanced use cases, you can also stream the rendering output (still experimental):

```
/** @var \Keepsuit\Liquid\Template $template */
/** @var \Keepsuit\Liquid\Render\RenderContext $context */

$stream = $template->stream($context);
// $stream is a Generator
```

Drops
-----

[](#drops)

Liquid support almost any kind of object but in order to have a better control over the accessible data in the templates, you can pass your data as `Drop` objects and have a better control over the accessible data. Drops are standard php objects that extend the `Keepsuit\Liquid\Drop` class. Public properties and public methods of the class will be accessible in the template as a property. You can also override the `liquidMethodMissing` method to handle undefined properties.

Liquid provides some attributes to control the behavior of the drops:

- `Hidden`: Hide the method or the property from the template, it cannot be accessed from liquid.
- `Cache`: Cache the result of the method, it will be called only once and the result will be stored in the drop.

```
use Keepsuit\Liquid\Drop;

class ProductDrop extends Drop {
    public function __construct(private Product $product) {}

    public function title(): string {
        return $this->product->title;
    }

    public function price(): float {
        return round($this->product->price, 2);
    }

    #[\Keepsuit\Liquid\Attributes\Cache]
    public function expensiveOperation(){
        // complex operation
    }

    #[\Keepsuit\Liquid\Attributes\Hidden]
    public function buy(){
        // Do something
    }
}
```

If you implement the `MapsToLiquid` interface in your domain classes, the liquid renderer will automatically convert your objects to drops.

```
use Keepsuit\Liquid\Contracts\MapsToLiquid;

class Product implements MapsToLiquid {
    public function __construct(public string $title, public float $price) {}

    public function toLiquid(): ProductDrop {
        return new ProductDrop($this);
    }
}
```

Advanced usage
--------------

[](#advanced-usage)

### Custom tags

[](#custom-tags)

To 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).

```
use Keepsuit\Liquid\Parse\TagParseContext;
use Keepsuit\Liquid\Render\RenderContext;
use Keepsuit\Liquid\Tag;

class CustomTag extends Tag
{
    public static function tagName(): string
    {
        return 'custom';
    }

    public function render(RenderContext $context): string
    {
        return '';
    }

    public function parse(TagParseContext $context): static
    {
        return $this;
    }
}
```

Note

Take a look at the implementation of default tags to see how to implement `parse` and `render` methods.

Then you need to register the tag in the environment:

```
// register when building the environment
$environment = \Keepsuit\Liquid\EnvironmentFactory::new()
    ->registerTag(CustomTag::class)
    ->build();

// or directly in the environment
$environment->tagRegistry->register(CustomTag::class);
```

### Custom filters

[](#custom-filters)

To create a custom filter, you need to create a class that extends the `Keepsuit\Liquid\Filters\FiltersProvider` abstract class.

Each public method of the class will be registered as a filter. You can "hide" a public method with the `Hidden` attribute, so it will not be registered as filter.

```
use Keepsuit\Liquid\Filters\FiltersProvider;

class CustomFilters extends FiltersProvider
{
    public function customFilter(string $value): string
    {
        return 'custom '.$value;
    }

    #[\Keepsuit\Liquid\Attributes\Hidden]
    public function notAFilter(string $value): string
    {
        return 'hidden '.$value;
    }
}
```

Then you need to register the filters provider in the environment:

```
// register when building the environment
$environment = \Keepsuit\Liquid\EnvironmentFactory::new()
    ->registerFilters(CustomFilters::class)
    ->build();

// or directly in the environment
$environment->filterRegistry->register(CustomFilters::class);
```

### Extensions

[](#extensions)

Extensions allow you to add custom tags, filters, and other features to the liquid environment.

To create a custom extension, you need to create a class that extends the `Keepsuit\Liquid\Extensions\Extension` abstract class.

```
class CustomExtension extends \Keepsuit\Liquid\Extensions\Extension
{
    public function getTags() : array{
        return [
            CustomTag::class,
        ];
    }

    public function getFiltersProviders() : array{
        return [
            CustomFilters::class,
        ];
    }

    // custom registers passed to render context
    public function getRegisters() : array {
        return [
            'custom' => fn() => 'custom value',
        ];
    }
}
```

Then you need to register the extension in the environment:

```
// register when building the environment
$environment = \Keepsuit\Liquid\EnvironmentFactory::new()
    ->addExtension(new CustomExtension())
    ->build();

// or directly in the environment
$environment->addExtension(new CustomExtension());
```

Resource limits
---------------

[](#resource-limits)

`Keepsuit\Liquid\Render\ResourceLimits` supports both per-render limits and cumulative resource limits.

- `renderLengthLimit`: limits the rendered output size for a render pass.
- `renderScoreLimit`: limits render work for a render pass.
- `assignScoreLimit`: limits assignment and capture work for a render pass.
- `cumulativeRenderScoreLimit`: limits total render work across a full render tree, including partial renders.
- `cumulativeAssignScoreLimit`: limits total assignment and capture work across a full render tree, including partial renders.

Per-render counters can be reset between renders. Cumulative counters are intended for a full render lifecycle so repeated partial renders can share the same budget.

Custom tags and filters
-----------------------

[](#custom-tags-and-filters)

By default, only the standard liquid tags and filters are available. But this package provides some custom tags and filters that you can use.

### Tags

[](#tags)

- `DynamicRender`: This tag replace the default `Render` tag and allows to render dynamic templates (eg. read template name from a variable).

### Filters

[](#filters)

- `TernaryFilter`
    - `ternary`: adds a ternary operator. ```
        {{ condition | ternary: true_value, false_value }}

        # Example
        {{ true | ternary: 'yes', 'no' }} # yes
        {{ false | ternary: 'yes', 'no' }} # no
        ```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Credits
-------

[](#credits)

- [Shopify](https://github.com/Shopify/liquid)
- [Fabio Capucci](https://github.com/cappuc)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

57

—

FairBetter than 98% of packages

Maintenance95

Actively maintained with recent releases

Popularity42

Moderate usage in the ecosystem

Community22

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 89.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~34 days

Recently: every ~118 days

Total

31

Last Release

20d ago

PHP version history (2 changes)v0.1.0PHP ^8.1

v0.10.0PHP ^8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/4271608?v=4)[Fabio Capucci](/maintainers/cappuc)[@cappuc](https://github.com/cappuc)

---

Top Contributors

[![cappuc](https://avatars.githubusercontent.com/u/4271608?v=4)](https://github.com/cappuc "cappuc (339 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (22 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (10 commits)")[![ryo-morimoto](https://avatars.githubusercontent.com/u/86156534?v=4)](https://github.com/ryo-morimoto "ryo-morimoto (4 commits)")[![tillschander](https://avatars.githubusercontent.com/u/7063293?v=4)](https://github.com/tillschander "tillschander (4 commits)")

---

Tags

liquidkeepsuit

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/keepsuit-liquid/health.svg)

```
[![Health](https://phpackages.com/badges/keepsuit-liquid/health.svg)](https://phpackages.com/packages/keepsuit-liquid)
```

###  Alternatives

[laravel/framework

The Laravel Framework.

34.8k543.8M20.0k](/packages/laravel-framework)[symfony/symfony

The Symfony PHP framework

31.4k87.2M2.2k](/packages/symfony-symfony)[symfony/framework-bundle

Provides a tight integration between Symfony components and the Symfony full-stack framework

3.6k251.7M11.6k](/packages/symfony-framework-bundle)[illuminate/database

The Illuminate Database package.

2.8k54.9M11.6k](/packages/illuminate-database)[illuminate/support

The Illuminate Support package.

630113.0M41.2k](/packages/illuminate-support)[infection/infection

Infection is a Mutation Testing framework for PHP. The mutation adequacy score can be used to measure the effectiveness of a test set in terms of its ability to detect faults.

2.2k28.9M2.3k](/packages/infection-infection)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
