{"id":18750687,"url":"https://github.com/webiny/htpl","last_synced_at":"2025-08-30T22:11:49.519Z","repository":{"id":22645976,"uuid":"25988957","full_name":"webiny/Htpl","owner":"webiny","description":"PHP Template Engine using nothing more than HTML5 tags.","archived":false,"fork":false,"pushed_at":"2015-08-07T17:25:16.000Z","size":300,"stargazers_count":11,"open_issues_count":6,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-08-30T22:09:20.629Z","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/webiny.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-10-30T20:42:36.000Z","updated_at":"2021-03-22T11:30:16.000Z","dependencies_parsed_at":"2022-08-21T09:30:49.217Z","dependency_job_id":null,"html_url":"https://github.com/webiny/Htpl","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/webiny/Htpl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webiny%2FHtpl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webiny%2FHtpl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webiny%2FHtpl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webiny%2FHtpl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webiny","download_url":"https://codeload.github.com/webiny/Htpl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webiny%2FHtpl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272913822,"owners_count":25014338,"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","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-11-07T17:12:49.552Z","updated_at":"2025-08-30T22:11:49.461Z","avatar_url":"https://github.com/webiny.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"HTPL \n=====\n\nHTPL is a PHP template engine that uses HTML5 tags. Here is a simple example:\n\n```html\n\u003cul\u003e\n    \u003cw-loop items=\"entries\" var=\"v\" key=\"k\"\u003e\n        \u003cw-if cond=\"k=='name' || k=='id'\"\u003e\n            \u003cli\u003e\u003cstrong\u003e{k}:\u003c/strong\u003e {v}\u003c/li\u003e\n        \u003c/w-if\u003e\n    \u003c/w-loop\u003e\n\u003c/ul\u003e\n```\n\nWe wrote this template engine because we had a need for an engine that is light and extensible when it comes to file storage.\nFor example, we want to be able to retrieve the source templates from a cloud storage and write compiled templates into memcache for faster execution.\nAnother reason was that we wanted something that is very easy for designers to learn and to use.\n \n## Main features\n\n1. It's secure, all values are automatically escaped before output\n2. Supports layout inheritance\n3. Easy to extend, no need to write any lexers\n4. Very fast (in some cases it outperforms Smarty, Twig and Blade) \n5. Simple and intuitive syntax\n\n# The Basics\n\nThe engine uses an instance of `TemplateProvider` to retrieve the source template, and it uses a `Cache` instance\nto store the compiled template for faster execution.\n\n```php\n$provider = new \\Webiny\\Htpl\\TemplateProviders\\FilesystemProvider([__DIR__ . '/template']);\n$cache = new \\Webiny\\Htpl\\Cache\\FilesystemCache(__DIR__ . '/temp/compiled');\n\n$htpl = new \\Webiny\\Htpl\\Htpl($provider, $cache);\n\n$htpl-\u003edisplay('template.htpl');\n```\n\nThere are a couple of built in template providers and cache providers. If you wish to build your own, just create a class\n and implement `\\Webiny\\Htpl\\TemplateProviders\\TemplateProviderInterface` for a template provider, or `\\Webiny\\Htpl\\Cache\\CacheInterface` for the cache.\n\nSee more:\n- [Variables and modifiers](#variables-and-modifiers)\n- [Functions](#functions)\n- [Template inheritance](#template-inheritance)\n- [License and Contributions](#license-and-contributions)\n- [Resources](#resources)\n\n \n## Variables and modifiers\n\nVariable values are printed using `{varName}` syntax. You can also attach different modifiers to variables, for example:\n\n```\n{someVar|lower|replace({\"john\":\"doe\", \"bird\":\"fish:})}\n```\n\nThe above code takes the value of `someVar`, makes it lowercase and replaces the word `john` with `doe`, and \nthe word `bird` with `fish`.\n\nAs you can see, the modifiers are very easy to apply, and they can be chained together.\n\n### Modifiers\n\nThe following modifiers are built in:\n\n#### numbers\n\n- [Abs](#abs)\n- [Round](#round)\n- [Number format](#number-format)\n\n#### strings\n\n- [Capitalize](#capitalize)\n- [Lower](#lower)\n- [Upper](#upper)\n- [First upper](#first-upper)\n- [Format](#format)\n- [Length](#length)\n- [Nl2br](#nl2br)\n- [Raw](#raw)\n- [Replace](#replace)\n- [Strip tags](#strip-tags)\n- [Trim](#trim)\n\n#### array\n\n- [First](#first)\n- [Last](#last)\n- [Join](#join)\n- [Keys](#keys)\n- [Values](#values)\n- [Length](#length)\n- [Json encode](#json-encode)\n\n#### date / time\n- [Date](#date)\n- [Time ago](#time-ago)\n\n#### other\n\n- [Default](#default-value)\n\nSee also [building a custom modifier](#custom-modifiers).\n\n#### Abs\n\nAbsolute value\n\n`someNum = -4`;\n```\n{someNum|abs} // 4  \n```\n\n#### Round\n\nRound the number.\n\n`someNum = 3.555`;\n```\n{someNum|round} // 4\n{someNum|round(2)} // 4.00\n{someNum|round(2)} // 3.56\n{someNum|round(2, \"down\")} // 3.549\n```\n\nThe round modifier takes the `precision` point as the first parameter, and `mode` as the second parameter.\nThe available `mode` values are: `up` or `down` and they define if the modifier should round up or round down.\n\n#### Number format\n\nFormat the given number.\n\n`num = 3500.1`\n```\n{num|numberFormat(2)} // 3,500.10\n{num|numberFormat(3, \",\", \".\")} // 3.500,100\n```\n\nThe modifier takes three parameters: `decimals`, `decimal point` and `thousands separator`.\n\n\n#### Capitalize\n\nCapitalize the string.\n\n`str = \"some string\"`\n```\n{str|capitalize} // Some String\n```\n\n#### Lower\n\nString to lowercase.\n\n`str = \"SOME STRING\"`\n```\n{str|lower} // some string\n```\n\n#### Upper\n\nString to uppercase.\n\n`str = \"some string\"`\n```\n{str|upper} // SOME STRING \n```\n\n#### First upper\n\nFirst letter to upper case.\n\n`str = \"some string\"`\n```\n{str|firstUpper} // Some string\n```\n\n#### Format\n\nFormat a string by replacing the placeholders with given values.\n\n`var = \"My name is %s\"`\n```\n{var|format({\"John Snow\"})} // My name is John Snow\n```\n\nThe modifier takes an array of strings that should be replaced in the same order as the placeholders appear in the input string.\n\n#### Length\n\nReturns the string length or the number or elements inside an array.\n\n`arr = [\"one\", \"two\", \"three\"]`\n```\n{arr|length} // 3 \n```\n\n`str = \"some string\"`\n```\n{str|length} // 11 \n```\n\n#### Nl2br\n\nConverts new lines to HTML's `br` tag.\n\n`str = \"Some\\nString\"`\n```\n{str|nl2br} // Some\u003cbr /\u003e\\nString\n```\n\n#### Raw\n\nUn-escapes the variable output.\n\n`var = \"\u003cdiv\u003e\u003cp\u003estring\u003c/p\u003e\u003c/div\u003e\"`\n```\n{var} // \u0026lt;div\u0026gt;\u0026lt;p\u0026gt;string\u0026lt;/p\u0026gt;\u0026lt;/div\u0026gt;\n{var|raw} // \u003cdiv\u003e\u003cp\u003estring\u003c/p\u003e\u003c/div\u003e\n```\n\n#### Replace\n\nPerform a find and replace on the given string.\n\n`var = \"John loves Khaleesi\"`\n```\n{var|replace({\"Khaleesi\":\"Tyrion\"})} // John loves Tyrion\n```\n\nThe modifier takes an array of key=\u003evalue pairs defining what should be replaced.\n\n#### Strip tags\n\nStrips the HTML tags from the string.\n\n`var = \"Some \u003cdiv\u003eHTML\u003c/div\u003e string\"`\n```\n{var|stripTags} // Some HTML string\n{var|stripTags(\"\u003cdiv\u003e\")} // Some \u003cdiv\u003eHTML\u003c/div\u003e string\n```\n\nThe modifier takes a comma separated list of allowed tags that shouldn't be replaced.\n\n\n#### Trim\n\nTrims the given character from the beginning, end or from both sides of the string.\n\n`str = \"|Some string|\"`\n```\n{str|trim(\"|\")} // Some string\n{str|trim(\"|\", \"left\")} // Some string|\n{str|trim(\"|\", \"right\")} // |Some string\n```\n\nThe modifier takes the char that should be trimmed as the first parameter, and the trim direction as the second parameter.\n\n\n#### First\n\nReturn the first value from the array.\n\n`arr = [\"one\", \"two\", \"three\"]`\n\n```\n{arr|first} // one\n```\n\n#### Last\n\nReturn the last value from the array.\n\n`arr = [\"one\", \"two\", \"three\"]`\n\n```\n{arr|last} // three\n```\n\n#### Join\n\nJoin the array pieces with the given glue.\n\n`arr = [\"one\", \"two\", \"three\"]`\n```\n{arr|join(\",\")} // one,two,three \n```\n\nThe modifier takes the glue as the parameter.\n\n#### Keys\n\nReturn the array keys.\n\n`arr = [\"keyOne\"=\u003e\"one\", \"keyTwo\"=\u003e\"two\", \"keyThree\"=\u003e\"three\"]`\n```\n{arr|keys} // [\"keyOne\", \"keyTwo\", \"keyThree\"]\n```\n\n#### Values\n\nReturn the array values.\n\n`arr = [\"keyOne\"=\u003e\"one\", \"keyTwo\"=\u003e\"two\", \"keyThree\"=\u003e\"three\"]`\n```\n{arr|values} // [\"one\", \"two\", \"three\"]\n```\n\n#### Json encode\n\nJson encode the given array.\n\n`arr = [\"one\", \"two\", \"three\"]`\n```\n{arr|jsonEncode} // {\"one\", \"two\", \"three\"} \n```\n\n#### Date\n\nDisplay the date.\n\n`date = \"2015-01-01 14:25\"`\n```\n{date|date(\"F j, Y, g:i a\")} // January 1, 2015, 2:25 pm\n```\n\nThe `date` modifier uses PHP date internally, meaning you can pass any PHP date format and it will parse it.\n \n#### Time ago\n\nThis is a helper modifier for displaying the date/time in a `time ago` format.\n\n`date = \"2015-01-01 14:25\"`\n```\n{date|timeAgo} // 4 months ago\n```\n\n#### Default value\n\nReturn a default value if the variable is empty.\n\n`var` is not defined.\n```\n{var|default(\"some value\")} // some value\n```\n\n\n\n#### Custom modifiers\n\nTo add a custom modifier, create a class that implements `\\Webiny\\Htpl\\Modifiers\\ModifierPackInterface` and assign the class\ninstance to your Htpl instance:\n\n```php\n$myModifierPack = new MockModifierPack();\n$htpl-\u003eregisterModifierPack($myModifierPack);\n```\n\nIt's worth checking out the built-in [CorePack](src/Webiny/Htpl/Modifiers/CorePack.php) to get a sense of the implementation. \n\n\n## Functions\n\nThe template engine provides just a few core functions that are sufficient in about 95% of your needs. \nFor the remaining 5%, HTPL provides a simple way to integrate any custom function.\n\nLets take a look at what is supported.\n\n### If, Else, ElseIf\n\nThe `if` function, and its siblings `else` and `elseif`, provide a way for executing/showing a particular part of the template,\nbased on whether or not the logical condition is met.\n\n```html\n\u003cw-if cond=\"someVar=='someString'\"\u003e\n    \u003cli\u003ethe value of someVar equals to someString\u003c/li\u003e\n\u003cw-elseif cond=\"someVar\u003e100\" /\u003e\n    \u003cli\u003esomeVar is larger than 100\u003c/li\u003e\n\u003cw-else/\u003e\n    \u003cli\u003esomething else - in case both upper conditions are false\u003c/li\u003e\n\u003c/w-if\u003e\n```\n\n### Include a template\n\nAn external template can be included using the `w-include` tag. \n\n```html\n\u003cul\u003e\n    \u003cw-include file=\"myLists.htpl\"/\u003e\n\u003c/ul\u003e\n```\n\nIf the value of the `file` attribute doesn't have an `.htpl` extension, it will be read as a variable, and the engine will\ntry to retrieve the template name from the variable and include it. \n**Note:** Only `.htpl` files can be included. The `.htpl` files cannot contain any PHP code.\n\n```html\n\u003cul\u003e\n    \u003cw-include file=\"someVariable\"/\u003e\n\u003c/ul\u003e\n```\n\n### Loops\n\nThe loop parameter takes the `items` attribute, which is the object you wish to loop through, and the `var` attribute, which \nmarks the current object value inside the loop. Also an optional attribute `key` can be passed, that holds the object's key value.\n\n```html\n\u003cw-loop items=\"entries\" var=\"v\" key=\"k\"\u003e\n    \u003cli\u003e\u003cstrong\u003e{k}:\u003c/strong\u003e {v}\u003c/li\u003e\n\u003c/w-loop\u003e\n```\n\n### Literal\n\nThe `w-literal` tag marks the content that should not be parsed. This is useful when you are using curly braces `{}` inside\nyour JavaScript code, so that the template engine doesn't raise an error.\n\n```html\n\u003cw-literal\u003e\n    \u003cscript\u003e\n        var object = {\"name\":\"john\"};\n    \u003c/script\u003e\n\u003c/w-literal\u003e\n```\n\n### Minify\n\nThis is a handy function that minifies and concatenates all marked JavaScript or CSS files into one file and strips out\ncomments and new lines, making the file much faster to download.\n\nA sample template like this: \n\n```html\n\u003cw-minify\u003e\n    \u003cscript src=\"assets/js/skel.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"assets/js/jquery.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"assets/js/init.js\"\u003e\u003c/script\u003e\n\u003c/w-minify\u003e\n\n\u003cw-minify\u003e\n    \u003clink rel=\"stylesheet\" href=\"assets/css/style.css\"/\u003e\n    \u003clink rel=\"stylesheet\" href=\"assets/css/navigation.css\"/\u003e\n    \u003clink rel=\"stylesheet\" href=\"assets/css/modals.css\"/\u003e\n\u003c/minify\u003e\n```\n\nWould output something like this:\n```html\n\u003cscript src=\"assets/minified/asda1kjh12k3jh1k3jh12k.js\"\u003e\u003c/script\u003e\n\u003clink rel=\"stylesheet\" href=\"assets/minified/klh123iuoi13k1j23lk.css\"/\u003e\n```\n\nThe script automatically tracks when the file was changed and creates a new minified file, with a different name, \nso it's automatically refreshed in the user's browser.\n**Note:** Don't place js and css files together inside the same `w-minify` block.\n\n#### Configuring minify\n\nThe minify function needs to be configured before it can be used. \n\n```php\n// get your Htpl instance\n$htpl = new \\Webiny\\Htpl\\Htpl($provider, $cache);\n\n// define the minify options\n$htpl-\u003esetOptions([\n    'minify' =\u003e [\n        'driver'    =\u003e 'Webiny\\Htpl\\Functions\\WMinify\\WMinify',\n        'provider'  =\u003e $providerInstance,\n        'cache'     =\u003e $cacheInstance,\n        'webRoot'   =\u003e '/minified/'\n    ]\n]);\n```\n\nThe `driver` parameter is an optional parameter. If not defined, it will use the internal minification class. In case you\nwish to use some other minification class, you can create your own driver by extending `\\Webiny\\Htpl\\Functions\\WMinify\\WMinifyAbstract`.\n\nThe `provider` parameter is an instance of a template provider, which can be a different instance from the one used for the Htpl instance.\nThis `provider` tells the minifier where to look for source files.\n\nThe `cache` parameter is an instance of a cache, which can also be a different instance than the one used for Htpl instance.\nThe `cache` tells the minifier where to save the minified files. \n\nWhen a minified file is created, it will be stored somewhere by the cache provider. In order to point to that directory using a web URL,\n  the minify component needs to know the web absolute path to that location. That path is set inside the `webRoot` option.\n\n## Template inheritance\n\nTemplate inheritance is done using layouts and blocks.\n\nFor example:\n\n`layout.htpl` content:\n```html\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003e\u003cw-block=\"title\"\u003e\u003c/w-block\u003e\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cw-block=\"content\"\u003e\u003c/w-block\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n`template.htpl` content:\n```html\n\u003cw-layout template=\"layout.htpl\"\u003e\n    \u003cw-block=\"title\"\u003eHello World\u003c/w-block\u003e\n    \n    \u003cw-block=\"content\"\u003e\n        This is my content\n    \u003c/w-block\u003e\n\u003c/w-layout\u003e\n```\n\nThe output:\n```html\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eHello World\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    This is my content\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n**Note**: inside the `w-layout` tag, all content that is not inside a `w-block` tag will get dropped. \n\n\n## License and Contributions\n\nContributing \u003e Feel free to send PRs.\n\nLicense \u003e [MIT](LICENSE)\n\n## Resources\n\nTo run unit tests, you need to use the following command:\n```\n$ cd path/to/Htpl/\n$ composer install\n$ phpunit\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebiny%2Fhtpl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebiny%2Fhtpl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebiny%2Fhtpl/lists"}