Coder Social home page Coder Social logo

php-liquid's Introduction

Liquid template engine for PHP Build Status

Liquid is a PHP port of the Liquid template engine for Ruby, which was written by Tobias Lutke. Although there are many other templating engines for PHP, including Smarty (from which Liquid was partially inspired), Liquid had some advantages that made porting worthwhile:

  • Readable and human friendly syntax, that is usable in any type of document, not just html, without need for escaping.
  • Quick and easy to use and maintain.
  • 100% secure, no possibility of embedding PHP code.
  • Clean OO design, rather than the mix of OO and procedural found in other templating engines.
  • Seperate compiling and rendering stages for improved performance.
  • Easy to extend with your own "tags and filters":https://github.com/harrydeluxe/php-liquid/wiki/Liquid-for-programmers.
  • 100% Markup compatibility with a Ruby templating engine, making templates usable for either.
  • Unit tested: Liquid is fully unit-tested. The library is stable and ready to be used in large projects.

Why Liquid?

Why another templating library?

Liquid was written to meet three templating library requirements: good performance, easy to extend, and simply to use.

Installing

You can install this lib via composer:

composer create-project liquid/liquid

Example template

{% if products %}
	<ul id="products">
	{% for product in products %}
	  <li>
		<h2>{{ product.name }}</h2>
		Only {{ product.price | price }}

		{{ product.description | prettyprint | paragraph }}

		{{ 'it rocks!' | paragraph }}

	  </li>
	{% endfor %}
	</ul>
{% endif %}

How to use Liquid

The main class is Liquid::Template class. There are two separate stages of working with Liquid templates: parsing and rendering. Here is a simple example:

use Liquid\Template;

$template = new Template();
$template->parse("Hello, {{ name }}!");
echo $template->render(array('name' => 'World');

// Will echo
// Hello, World!

To find more examples have a look at the examples directory or at the original Ruby implementation repository's wiki page.

Requirements

  • PHP 5.3+

Issues

Have a bug? Please create an issue here on GitHub!

https://github.com/harrydeluxe/php-liquid/issues

Fork notes and contributors

This fork is based on php-liquid by Mateo Murphy. kalimatas has contributed a lot in his fork to bring Liquid to the new state. Thank you so much!

It contains several improvements:

  • namespaces
  • installing via composer
  • new standard filters
  • raw tag added

Any help is appreciated!

php-liquid's People

Contributors

chenos avatar daniel-zahariev avatar harrydeluxe avatar jadb avatar nathanbaulch avatar quentinbellus avatar ryanmac avatar sanmai avatar v1o avatar warezthebeef avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

php-liquid's Issues

Use namespaces

  • Rewrite classes to use namespace Liquid
  • Rewrite tests
  • Fix minimum PHP required version to 5.3
  • Fix docs

The difference between master and develop branches

Thanks for the great project for processing liquid files in PHP.

There are two branches in the project. It seems like that the develop branch supports unless tag and the directory structure is also different with master branch. Because the unless tag was already implemented in 2015, does the unless tag feature plan to be merged into master branch?

If I would like to contribute the project, which branch should I fork?

Comparison Error in src/Liquid/LocalFileSystem.php

Hello guys,

there are comparison errors in the file src/Liquid/LocalFileSystem.php.
There are some comparisons like: if (!$rootRegex->match(realpath($fullPath)))
wich wont be true ever, because the function match() will never return a boolean.
It just returns 0 or 1... I know a bit stupid..

Unknown tag render


Fatal error: Uncaught Liquid\Exception\ParseException: Unknown tag render in /Applications/MAMP/htdocs/ehr_uphc/liquid/src/Liquid/AbstractBlock.php:210 Stack trace: #0 /Applications/MAMP/htdocs/ehr_uphc/liquid/src/Liquid/AbstractBlock.php(88): Liquid\AbstractBlock->unknownTag('render', ''ObservationVit...', Array) #1 /Applications/MAMP/htdocs/ehr_uphc/liquid/src/Liquid/Document.php(32): Liquid\AbstractBlock->parse(Array) #2 /Applications/MAMP/htdocs/ehr_uphc/liquid/src/Liquid/Template.php(213): Liquid\Document->__construct(Array, Object(Liquid\LocalFileSystem)) #3 /Applications/MAMP/htdocs/ehr_uphc/liquid/src/Liquid/Template.php(188): Liquid\Template->parseAlways('{\n "resource...') #4 /Applications/MAMP/htdocs/ehr_uphc/liquid/OPConsultRecord.php(194): Liquid\Template->parse('{\n "resource...') #5 {main} thrown in /Applications/MAMP/htdocs/ehr_uphc/liquid/src/Liquid/AbstractBlock.php on line 210

How does "include" work?

I am trying to use the "include" tag but I keep on getting exception.. where does it look for that file? Can you post an example for include?

Thanks

Colon not allowed in date format string?

Hello,

It seems as though {{ "now" | date: "%Y-%m-%d %H:%M" }} renders null but {{ "now" | date: "%Y-%m-%d %H%M" }} renders just fine. Is anyone else having this issue? It seems that the colon is causing it to render null.

variable inside an include tag cause an exception

Hi!

First of all thank you for your work!
I tried to used a variable (name of the template file) inside the include tag, but it throws an exception.

{% assign foo = 'builder' %}
{% include foo %}
{% include {{ foo }} %}

Of course this is working:
{% include 'builder' %}

I know that there is a block tag for this kind of operation, but I'd like to use the include tag instead (it would be a nice feature).

Thanks!
Krisz

Maintenance the project

Hi

Why not maintenance and archived?
It's really good project, I personally love to use Liquid template engine.

If you not have time to work, Maybe someone can join to work? There is anyone?

Best,
M.

include break if not exists

How do I ignore the exception if no files in include? I am planning to let my users keyin the liquid syntax

{% include 'header' %}

How to register an Extended AbstractTag?

Title says it all. I want to add a new tag, callable by {% entypo %} and I can't figure out how to register a AbstractTag. Here's the tag:

<?php

    namespace CMS\Liquid;

    use Liquid\AbstractTag;

    class EntypoTag extends AbstractTag {
            public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) {
                parent::__construct($markup, $tokens, $fileSystem);
            }

            public function render(Context $context) {
                die($context);
            }
    }

And here is how I'm registering it so far:

 $template = new Template();
 $template->parse(file_get_contents(__DIR__.'/../src/views/admin/dashboard.html'));
 $template->registerTag('entypo', new EntypoTag('entypo',$template->tokens));

 echo $template->render();

And bam, I get a Unkown tag entypo [E:\Webdev\CMS\vendor\liquid\liquid\src\Liquid\AbstractBlock.php:146]. How can I propely register it?

For - loop - else

{% for product in product %}
{{ product.name }}
{% else %}
No products found
{% endfor %}

does not work... would be great if could have that!

include from array

possible to render include tag from array? I don't want to load from a file

White space control as default

    /* Force whitespace control to be used by switching tags from {%- to {%
     * Also, will error out if you try {%- 
     * Need to figure out how to turn back on whitespaces with {%@ errors! not important...
     * Sorry, not an REGEX guy... wanted to use plus sign but it was escaping oddly even with an slash
     */
    \Liquid\Liquid::set('TAG_START', '(?:{%@)|\s*{%');
    \Liquid\Liquid::set('TAG_END', '(?:@%}|%}\s*)');

Math filters always return whole integers

So if you do:

{{ 1 | plus: 1.5 }}

You will get 2

I would recommend the (int) type castings for values returned by the Math Filters be changed to (float) to avoid this.

I'm pretty sure it's not the behaviour of the original Liquid implementation.

Unkown tag continue

It seems continue is not supported? Use case:

  {% for plan in site.data.public_plans %}
    {% if plan[1].slug == "sandbox" and showSandboxPlan == false %}
      {% continue %}
    {% endif %}
  {% endfor %}

Error in assign with objects

Hi,

I Have a problema with a assign function:

ERROR:

{% for item in section.blocks %}
	{% assign pro = content_products[item.settings.product] %}
        <h3>{{ pro.name }}</h3> 
{% endfor %}

{{ item.settings.product }} -> output id of product: 2,3,4...

In example "pro.name" returns null, but i change for: {% assign pro = content_products[2] %} works perfect...

Tks.

Install mode

Hi! i need to install this lib but i cant install with composer. Can i install this lib with another way that not be with composer?

Contains doesn't work if word is located at index 0

Hi,

When using contains on a word located at index 0, the contains function doesn't work.
Example:

 # myvar = 'my example'
  {% if myvar contains 'my' %}word found{% else %}not found {% endif %}

This will display "not found", which is wrong.

I believe the problem is located in the file "LiquidDecisionBlock.class.php", line 158:

case 'contains':
     return is_array($left) ? in_array($right, $left) : ($left == $right || strpos($left, $right));

Should be changed to:

case 'contains':
     return is_array($left) ? in_array($right, $left) : ($left == $right || strpos($left, $right)!==false);

Thanks.

500 error in response in codeigniter.

Hi @harrydeluxe

Thanks for this package.
I have used this package in my localhost and its working fine.
Now I want to use this package in CodeIgniter, so I have added this package at this path "application/third_party/php-liquid-compiler/liquid".
And now I have created a library for using this package.

Here is my library code, This code inside in "application/libraries/".

<?php 
if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 
class Phpliquidcompiler
{
    public function phpLiquid(){
        $path = __DIR__ . "/../third_party/php-liquid-compiler/liquid/";
        $loader = require  $path . 'vendor/autoload.php';
        $loader->addPsr4('Liquid\\',  $path . 'src/Liquid');
        
        print_r($loader);
        use Liquid\Liquid;    // At here I getting 500 error.
        use Liquid\Template; 

	Liquid::set('INCLUDE_SUFFIX', '');
	Liquid::set('INCLUDE_PREFIX', '');
	Liquid::set('INCLUDE_ALLOW_EXT', true);
	Liquid::set('ESCAPE_BY_DEFAULT', true);

	$liquid = new Template();
	$liquid->parse('{% assign special= "sd" %} {% if special != "" %} <div><a
	href="">[special]sdsdsd</a></div> {% endif %}');
	echo $liquid->render();
    }
}
?>

Calling above code from controller.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Welcome extends CI_Controller{
    public function index(){
	$this->load->library('phpliquidcompiler');
        $this->phpliquidcompiler->phpLiquid();
    }
}

?>

Will you please tell me where I am wrong ?

Thanks.

Environment & server variables are available in all templates

Because decrement tag uses $_SERVER to store values, it is possible to get any variable from it. We store some environment variables in $_SERVER and user could do {{ DB_PASSWORD }} or any other server variable and he would be able to see that value. Is this not considered a security issue ?Should decrement really touch $_SERVER? could it not store data in registers or assigns?

Quotes (escaped) inside "filtered" text or inside a filter's arguments

Example of trying to filter some text that has double escaped quotes inside of it:

{{ "let's try some \"quoted\" text" | my_filter }}

Example of trying to filter some text using an argument that has double escaped quotes inside of it:

{{ "text" | my_filter: "let's try some \"quoted\" argument" }}

These are scenarios that I have come across and it appears that the text and argument are both cut off at the first backslash \ because both 'QUOTED_STRING' => '"[^"]*"|\'[^\']*\'' and
'QUOTED_STRING_FILTER_ARGUMENT' => '"[^":]*"|\'[^\':]*\'', are greedy and stop after the first double quote " they find.

It seems that something like this might be a solution:

In \Liquid\Liquid change QUOTED_STRING and QUOTED_STRING_FILTER_ARGUMENT as follows:

'QUOTED_STRING' => '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'',
'QUOTED_STRING_FILTER_ARGUMENT' => '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'',

Thanks @bigwhoop for help on this.

toLiquid doesn't get called for objects inside objects

Let's say we have an object which have another object bound to one of the properties.

class NestedObject
{
	public $property;
	public $value = -1;

	public function toLiquid() {
		return array(
			'property' => $this->property,
			'value' => 42,
		);
	}
}

For the sake of example let's use the same object type.

$object = new NestedObject();
$object->property = new NestedObject();

Now, if we would try accessing embedded object's property...

{{ object.property.value }}

We'll get not 42 as we may expect from having it set in toLiquid but -1.

Support for Composer

Hey! Great job with php-liquid, ¿could you add support for composer? It could be great get it filed under your-name/project instead of my-fork/project

Where is LiquidBlock class location

In the article Liquid for programmers, this link: , "All tag blocks are parsed by Liquid. To create a new block, you just have to inherit from LiquidBlock and register your block with LiquidTemplate".
But i dit not find "LiquidBlock" class in library

Can't use variables as index in array

With the original Liquid implementation, you are able to set an integer as a variable, and then use it inside bracket notation of an array/object to output the value of that key. This doesn't work in the PHP version:

Example:

{% assign letters = 'A,B,C,D,E' | split: ',' %}                                                                
{{ letters[1] }}

B

{% assign index = 1 %}
{{ letters[index] }}

blank

I've fixed this by modifying the "variable" method in the LiquidContext class:

    /**
     * Resolved the namespaced queries gracefully.
     *
     * @param string $key
     * @return mixed
     */
    public function variable($key)
    {
        /* Support [0] style array indicies */
        if (preg_match("|\[[0-9]+\]|", $key))
        {
            $key = preg_replace("|\[([0-9]+)\]|", ".$1", $key);
        }
        /* Support [var] style array indicies */ 
        elseif (preg_match("|\[(.*)\]|", $key, $matches))
        {
            $var = $this->fetch($matches[1]);
            $key = preg_replace("|\[(.*)\]|", "." . $var, $key);
        }
       .....

Disable Casesensitive

When the data is:

$data = ["something" => "value"];

And using:
{{Something}}

The replacement not working.

Where I need to add strtolower before to disable the Casesensitive?

Thanks

Variables don't render in time for usage in context. I.e. cannot be used as Array keys.

When rendering templates the variables are not being rendered in time for use in context.
Example:

<ul class="nav">
  {% for link in navigation.main-navigation.links %}
<li class="cf">
      <a href="{{ link.url }}">{{ link.link_name }}</a> 
     <ul class="nav">
        {% for l in navigation[link.handle].links %}
          <li><a href="{{ l.url }}"{% if l.active %} class="current"{% endif %}>{{ l.link_name }}</a></li>
        {% endfor %}
    </ul>
    </li>
    {% endfor %}
   </ul>

The key issue in the above:
When attempting to utilise for loop variables as array keys they fail.

The desired affect (and how Shopify liquid works), is the variable is output as it's value, before further liquid markup is rendered, meaning the variable value can then be used right away in context. In this case, as an array key.
The correct output example:
{% for l in navigation[my-link-handle-value-after-being-rendered].links %}

Instead it's not rendered and you're left with the variable name itself.
Current output example:
{% for l in navigation[link.handle].links %}

Error when extending tag

tried this but return error, can you confirm LiquidBlock class?

class LiquidTagNodisplay extends LiquidBlock
{
    public function render(&$context)
    {
        return '';
    }
}
$text = " {% nodisplay %} don't show me! {% endnodisplay %} ";
$liquid = new LiquidTemplate();
$liquid->registerTag('nodisplay', 'LiquidTagNodisplay');
$liquid->parse($text);
echo $liquid->render();  // => ""

error_mode

do php-liquid have setting for the error mode?

Liquid::Template.error_mode = :strict # Raises a SyntaxError when invalid syntax is used
Liquid::Template.error_mode = :warn # Adds errors to template.errors but continues as normal
Liquid::Template.error_mode = :lax # The default mode, accepts almost anything.

Context tries to access private properties where public methods exists

Consider the following class definition.

class Example
{
	private $name = null;

	public function name()
	{
		return $this->name;
	}
}

If you happen to include an instance of this class in a template, then try to access the name like so:

{{ example.name }}

You will get a fatal error:

PHP Fatal error:  Uncaught Error: Cannot access private property Example::$name

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.