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. keepsuit/liquid

ActiveLibrary

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

PHP implementation of liquid markup language

v0.9.1(5mo ago)1951.5k↑56.9%2[2 issues](https://github.com/keepsuit/php-liquid/issues)3MITPHPPHP ^8.1CI passing

Since Aug 30Pushed 2mo 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 1mo ago

READMEChangelog (10)Dependencies (12)Versions (32)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.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\ResourceLimits())
    // 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());
```

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

50

—

FairBetter than 96% of packages

Maintenance75

Regular maintenance activity

Popularity40

Moderate usage in the ecosystem

Community21

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 89.7% 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 ~28 days

Recently: every ~71 days

Total

30

Last Release

168d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/9881c8ffdbe3f838feabbfba94c7a602db2bd84f991913a75cbfd1e21c593e66?d=identicon)[cappuc](/maintainers/cappuc)

---

Top Contributors

[![cappuc](https://avatars.githubusercontent.com/u/4271608?v=4)](https://github.com/cappuc "cappuc (322 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (20 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (9 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

[liquid/liquid

Liquid template engine for PHP

1854.8M25](/packages/liquid-liquid)[keepsuit/laravel-opentelemetry

OpenTelemetry integration for laravel

142347.8k](/packages/keepsuit-laravel-opentelemetry)[keepsuit/laravel-temporal

Laravel temporal.io

4875.0k](/packages/keepsuit-laravel-temporal)[simexis/laravel-liquid

Liquid template engine for Laravel

181.5k](/packages/simexis-laravel-liquid)

PHPackages © 2026

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