{"id":18949923,"url":"https://github.com/salesforce/handlebars-php","last_synced_at":"2025-04-05T04:14:27.573Z","repository":{"id":35123122,"uuid":"197289837","full_name":"salesforce/handlebars-php","owner":"salesforce","description":"A simple, logic-less, yet powerful templating engine for PHP","archived":false,"fork":false,"pushed_at":"2024-07-09T09:01:42.000Z","size":155,"stargazers_count":73,"open_issues_count":11,"forks_count":33,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-29T03:09:28.065Z","etag":null,"topics":["han","must","php"],"latest_commit_sha":null,"homepage":"","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/salesforce.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-17T01:08:31.000Z","updated_at":"2024-12-28T13:56:17.000Z","dependencies_parsed_at":"2023-01-15T14:17:26.400Z","dependency_job_id":"3dbdc44f-ee26-48b2-be51-03aecc23f830","html_url":"https://github.com/salesforce/handlebars-php","commit_stats":{"total_commits":129,"total_committers":24,"mean_commits":5.375,"dds":0.6976744186046512,"last_synced_commit":"d3a0552d85472249617ef6b56197c844d62d2ac3"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salesforce%2Fhandlebars-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salesforce%2Fhandlebars-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salesforce%2Fhandlebars-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salesforce%2Fhandlebars-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/salesforce","download_url":"https://codeload.github.com/salesforce/handlebars-php/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247284953,"owners_count":20913704,"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":["han","must","php"],"created_at":"2024-11-08T13:19:40.552Z","updated_at":"2025-04-05T04:14:27.554Z","avatar_url":"https://github.com/salesforce.png","language":"PHP","readme":"[![PHPUnit](https://github.com/salesforce/handlebars-php/actions/workflows/ci.yml/badge.svg)](https://github.com/salesforce/handlebars-php/actions/workflows/ci.yml)\n\n---\n\n#handlebars-php\n\n---\n\n#### A simple, logic-less, yet powerful templating engine for PHP\n\n---\n\nName: **handlebars-php**\n\nLicense: MIT\n\nRequirements: PHP \u003e= 5.4\n\n---\n\n\n## About Handlebars\n\nHandlebars provides the power necessary to let you build semantic templates effectively with no frustration,\nthat keep the view and the code separated like we all know they should be.\n\n\nFork of: [Handlebars.php by XaminProject](https://github.com/mardix/Handlebars)\n\nHandlebars, is the PHP port of [Handlebars.js](http://handlebarsjs.com/)\n\n---\n\n## Install Handlebars\n\n\nYou can just download Handlebars.php as is, or with Composer.\n\nTo install with composer, add the following in the require key in your **composer.json** file\n\n`\"salesforce/handlebars-php\": \"1.*\"`\n\ncomposer.json\n\n```json\n{\n    \"name\": \"myapp/name\",\n    \"description\": \"My awesome app name\",\n    \"require\": {\n        \"salesforce/handlebars-php\": \"1.*\"\n    }\n}\n```\n\n-----\n\n## Getting Started\n\nAt the minimum, we are required to have an array model and a template string. Alternatively we can have a file containing handlebars (or html, text, etc) expression.\n\n\n\n#### Template\n\nHandlebars templates look like regular HTML, with embedded handlebars expressions.\n\nHandlebars HTML-escapes values returned by a {{expression}}.\n\n```html\n\u003cdiv class=\"entry\"\u003e\n  \u003ch1\u003e{{title}}\u003c/h1\u003e\n  \u003cdiv class=\"body\"\u003e\n    Hello, my name is {{name}}\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\nThe string above can be used as is in your PHP file, or be put in a file (ie: */templates/main.tpl*), to be called upon rendering.\n\n#### PHP file\n\nNow the we've created our template file, in a php file (index.php) we'll create the data to passed to the model. The model is a key/value array.\n\nBelow we are going to create the Handlebars object, set the partials loader, and put some data in the model.\n\n**/index.php**\n\n```php\n\u003c?php\n\n# With composer we can autoload the Handlebars package\nrequire_once (\"./vendor/autoload.php\");\n\n# If not using composer, you can still load it manually.\n# require 'src/Handlebars/Autoloader.php';\n# Handlebars\\Autoloader::register();\n\nuse Handlebars\\Handlebars;\nuse Handlebars\\Loader\\FilesystemLoader;\n\n# Set the partials files\n$partialsDir = __DIR__.\"/templates\";\n$partialsLoader = new FilesystemLoader($partialsDir,\n    [\n        \"extension\" =\u003e \"html\"\n    ]\n);\n\n# We'll use $handlebars throughout this the examples, assuming the will be all set this way\n$handlebars = new Handlebars([\n    \"loader\" =\u003e $partialsLoader,\n    \"partials_loader\" =\u003e $partialsLoader\n]);\n\n# Will render the model to the templates/main.tpl template\n$model = [...];\necho $handlebars-\u003erender(\"main\", $model);\n```\n\n#### Assign Data\n\nThe simplest way to assign data is to create an Array model. The model will contain all the data that will be passed to the template.\n```php\n\u003c?php\n\n$model = [\n    \"name\" =\u003e \"Yolo Baggins\",\n    \"title\" =\u003e \"I'm Title\",\n    \"permalink\" =\u003e \"blog/\",\n    \"foo\" =\u003e \"bar\",\n    \"article\" =\u003e [\n        \"title\" =\u003e \"My Article Title\"\n    ],\n    \"posts\" =\u003e [\n        [\n            \"title\" =\u003e \"Post #1\",\n            \"id\" =\u003e 1,\n            \"content\" =\u003e \"Content\"\n        ],\n        [\n            \"title\" =\u003e \"Post 2\",\n            \"id\" =\u003e 2,\n            \"content\" =\u003e \"Content\"\n        ]\n    ]\n];\n```\n\n#### Render Template\n\nUse the method `Handlebars\\Handlebars::render($template, $model)` to render you template once everything is created.\n\n***$template*** : Template can be the name of the file or a string containing the handlebars/html.\n\n***$model*** : Is the array that we will pass into the template\n\nThe code below will render the model to the *templates/main.tpl* template\n\n```php\necho $handlebars-\u003erender(\"main\", $model);\n```\n\n\nAlternatively you can use $handlebars itself without invoking the render method\n\n```php\necho $handlebars(\"main\", $model);\n```\n\n---\n\n## Expressions\n\nLet's use this simple model for the following examples, assuming everything is already set like above.\n\n```php\n\u003c?php\n\n$model = [\n    \"title\" =\u003e \"I'm Title\",\n    \"permalink\" =\u003e \"/blog/\",\n    \"foo\" =\u003e \"bar\",\n    \"article\" =\u003e [\n        \"title\" =\u003e \"My Article Title\"\n    ],\n    \"posts\" =\u003e [\n        [\n            \"title\" =\u003e \"Post #1\",\n            \"id\" =\u003e 1,\n            \"content\" =\u003e \"Content\"\n        ],\n        [\n            \"title\" =\u003e \"Post 2\",\n            \"id\" =\u003e 2,\n            \"content\" =\u003e \"Content\"\n        ]\n    ]\n];\n```\n\nLet's work with the template.\n\nHandlebars expressions are the basic unit of a Handlebars template. You can use them alone in a {{mustache}}, pass them to a Handlebars helper, or use them as values in hash arguments.\n\n\nThe simplest Handlebars expression is a simple identifier:\n\n```html\n{{title}}\n\n-\u003e I'm Title\n```\n\nHandlebars nested expressions which are dot-separated paths.\n\n```html\n{{article.title}}\n\n-\u003e My Article Title\n```\n\nHandlebars nested expressions in an array.\n\n```html\n{{posts.0.title}}\n\n-\u003e Post #1\n```\n\nHandlebars also allows for name conflict resolution between helpers and data fields via a this reference:\n\n```html\n{{./name}} or {{this/name}} or {{this.name}}\n```\n\nHandlebars expressions with a helper. In this case we're using the upper helper\n\n```html\n{{#upper title}}\n\n-\u003e I'M TITLE\n```\n\nNested handlebars paths can also include ../ segments, which evaluate their paths against a parent context.\n\n```html\n{{#each posts}}\n    \u003ca href=\"/posts/{{../permalink}}/{{id}}\"\u003e{{title}}\u003c/a\u003e\n    {{content}}\n{{/each}}\n```\n\nHandlebars HTML-escapes values returned by a {{expression}}. If you don't want Handlebars to escape a value, use the \"triple-stash\", {{{ }}}\n\n```html\n{{{foo}}}\n```\n\n---\n\n\n## Control Structures\n\n`if/else` and `unless` control structures are implemented as regular Handlebars helpers\n\n### IF/ELSE\n\nYou can use the if helper to conditionally render a block. If its argument returns false, null, \"\" or [] (a \"falsy\" value), Handlebars will not render the block.\n\n**Example**\n\n```html\n{{#if isActive}}\n    This part will be shown if it is active\n{{#else if isValid}}\n    This part will be shown if it is valid\n{{else}}\n    This part will be shown if isActive and isValid are both \"falsy\" values\n{{/if}}\n```\n\n```php\n\u003c?php\n\n$model = [\n    \"isActive\" =\u003e true,\n    \"isValid\" =\u003e false\n];\n\necho $handlebars-\u003erender($template, $model);\n```\n\n### UNLESS\n\nYou can use the unless helper as the inverse of the if helper. Its block will be rendered if the expression returns a falsy value.\n\n```html\n{{#unless isActive}}\n    This part will not show if isActive is true\n{{/unless}}\n```\n\n---\n##Iterators: EACH\n\nYou can iterate over a list using the built-in each helper. Inside the block, you can use {{this}} or {{.}} to reference the element being iterated over.\n\n**Example**\n\n```html\n\u003ch2\u003eAll genres:\u003c/h2\u003e\n{{#each genres}}\n    {{.}}\n{{/each}}\n\n\n{{#each cars}}\n    \u003ch3\u003e{{category}}\u003c/h3\u003e\n    Total: {{count}}\n    \u003cul\u003e\n    {{#each list}}\n        {{.}}\n    {{/each}}\n    \u003c/ul\u003e\n{{/each}}\n```\n\n```php\n\u003c?php\n\n$model = [\n    \"genres\" =\u003e [\n        \"Hip-Hop\",\n        \"Rap\",\n        \"Techno\",\n        \"Country\"\n    ],\n    \"cars\" =\u003e [\n        \"category\" =\u003e \"Foreign\",\n        \"count\" =\u003e 4,\n        \"list\" =\u003e [\n            \"Toyota\",\n            \"Kia\",\n            \"Honda\",\n            \"Mazda\"\n        ],\n        \"category\" =\u003e \"WTF\",\n        \"count\" =\u003e 1,\n        \"list\" =\u003e [\n            \"Fiat\"\n        ],\n        \"category\" =\u003e \"Luxury\",\n        \"count\" =\u003e 2,\n        \"list\" =\u003e [\n            \"Mercedes Benz\",\n            \"BMW\"\n        ]\n    ],\n];\n\n    echo $engine-\u003erender($template, $model);    \n```\n\n### EACH/ELSE\n\nYou can optionally provide an {{else}} section which will display only when the list is empty.\n\n```html\n\u003ch2\u003eAll genres:\u003c/h2\u003e\n{{#each genres}}\n    {{.}}\n{{else}}\n    No genres found!\n{{/each}}\n```\n\n### Slice EACH Array[start:end]\n\nThe #each helper (php only) also has the ability to slice the data\n\n * {{#each Array[start:end]}} = starts at start through end -1\n * {{#each Array[start:]}} = Starts at start though the rest of the array\n * {{#each Array[:end]}} = Starts at the beginning through end -1\n * {{#each Array[:]}} = A copy of the whole array\n * {{#each Array[-1]}}\n * {{#each Array[-2:]}} = Last two items\n * {{#each Array[:-2]}} = Everything except last two items\n\n```html\n\u003ch2\u003eAll genres:\u003c/h2\u003e\n{{#each genres[0:10]}}\n    {{.}}\n{{else}}\n    No genres found!\n{{/each}}\n```\n\n#### {{@INDEX}} and {{@KEY}}\n\nWhen looping through items in each, you can optionally reference the current loop index via {{@index}}\n\n```html\n{{#each array}}\n  {{@index}}: {{this}}\n{{/each}}\n\n\n{{#each object}}\n  {{@key}}: {{this}}\n{{/each}}\n```\n\n---\n\n## Change Context: WITH\n\nYou can shift the context for a section of a template by using the built-in with block helper.\n\n```php\n\u003c?php\n\n$model = [\n    \"genres\" =\u003e [\n        \"Hip-Hop\",\n        \"Rap\",\n        \"Techno\",\n        \"Country\"\n    ],\n    \"other_genres\" =\u003e [\n        \"genres\" =\u003e [\n        \"Hip-Hop\",\n        \"Rap\",\n        \"Techno\",\n        \"Country\"\n        ]\n]\n];\n```\n\n```html\n\u003ch2\u003eAll genres:\u003c/h2\u003e\n{{#with other_genres}}\n{{#each genres}}\n    {{.}}\n{{/each}}\n{{/with}}\n```\n\n---\n\n## Handlebars Built-in Helpers\n\n### If\n```html\n{{#if isActive}}\n    This part will be shown if it is active\n{{#else if isValid}}\n    This part will be shown if it is valid\n{{else}}\n    This part will be shown if isActive and isValid are both \"falsy\" values\n{{/if}}\n```\n\n### Unless\n```html\n{{#unless isActive}}\n    This part will show when isActive is false\n{{else}}\n    Otherwise this one will show\n{{/unless}}\n```\n\n### Each\n```html\n{{#each genres[0:10]}}\n    {{.}}\n{{else}}\n    No genres found!\n{{/each}}\n```\n\n### With\n```html\n{{#with other_genres}}\n{{#each genres}}\n    {{.}}\n{{/each}}\n{{/with}}\n```\n\n---\n\n## Other Helpers\n\n#### For convenience, Voodoo\\Handlebars added some extra helpers.\n\n---\n\n### Upper\n\nTo format string to uppercase\n```html\n{{#upper title}}\n```\n\n### Lower\n\nTo format string to lowercase\n```html\n{{#lower title}}\n```\n\n\n### Capitalize\n\nTo capitalize the first letter\n```html\n{{#capitalize title}}\n```\n\n### Capitalize_Words\n\nTo capitalize each words in a string\n```html\n{{#capitalize_words title}}\n```\n\n### Reverse\n\nTo reverse the order of string\n```html\n{{#reverse title}}\n```\n\n### Format_Date\n\nTo format date: `{{#format_date date '$format'}}`\n```html\n{{#format_date date 'Y-m-d H:i:s'}}\n```\n\n### Inflect\n\nTo singularize or plurialize words based on count `{{#inflect count $singular $plurial}}`\n```html\n{{#inflect count '%d book' '%d books'}}\n```\n\n### Truncate\n\nTo truncate a string: `{{#truncate title $length $ellipsis}}`\n```html\n{{#truncate title 21 '...'}}\n```\n\n### Default\n\nTo use a default value if  the string is empty: `{{#default title $defaultValue}}`\n```html\n{{#default title 'No title'}}\n```\n\n### Raw\n\nThis helper return handlebars expression as is. The expression will not be parsed\n```html\n{{#raw}}\n    {{#each cars}}\n        {{model}}\n    {{/each}}\n{{/raw}}\n\n-\u003e\n\n{{#each cars}}\n    {{model}}\n{{/each}}\n```\n\n\n### Repeat\n\nTo truncate a string: `{{#repeat $count}}{{/repeat}}`\n```html\n{{#repeat 5}}\n    Hello World!\n{{/repeat}}\n```\n\nVariable and blocks can still be used\n```html\n{{#repeat 5}}\n    Hello {{name}}!\n{{/repeat}}\n```\n\n\n### Define/Invoke\n\nAllow to define a block of content and use it later. It helps follow the DRY (Don't repeat yourself) principle.\n\n\nDefine\n```html\n{{#define $definedName}}\n    content\n{{/define}}\n```\n\nInvoke\n```html\n{{#invoke $definedName}}\n```\n\n\nExample:\n```html\n{{#define hello}}\n    Hello World! How do you do?\n{{/define}}\n\n{{#invoke hello}}\n\n-\u003e\n\nHello World! How do you do?\n```\n\n---\n\n### Template Comments\nYou can use comments in your handlebars code just as you would in your code. Since there is generally some level of logic, this is a good practice.\n\n```html\n{{!-- only output this author names if an author exists --}}\n```\n\n---\n\n### Partials\n\nPartials are other templates you can include inside of the main template.\n\nTo do so:\n\n```html\n{{\u003e my_partial}}\n```\n\nwhich is a file under /templates/my_partial.html\n\n---\n\n## Writing your own helpers\n\nBlock helpers make it possible to define custom iterators and other helpers that can invoke the passed block with a new context.\n\nTo create your own helper, use the method: `Handlebars::addHelper($name, $callback)`\n\nThe following helper will UPPERCASE a string\n\n```php\n$handlebars-\u003eaddHelper(\"upper\",\n    function($template, $context, $args, $source){\n        return strtoupper($context-\u003eget($args));\n    }\n);\n```\n\nAnd now we can use the helper like this:\n\n```html\n{{#upper title}}\n```\n\n---\n\n## Data Variables for #each\n\nIn Handlebars JS v1.1, data variables `@first` and `@last` were added for the #each helper. Due to the these variables\nnot being backwards compatible, these data variables are disabled by default and must be enabled manually.\n\nTo enable the new data variables, set the `enableDataVariables` option to `true` when instantiating the Handlebars\ninstance.\n\n```php\n$handlebars = new Handlebars([\n    \"loader\" =\u003e $partialsLoader,\n    \"partials_loader\" =\u003e $partialsLoader,\n    \"enableDataVariables\" =\u003e true\n]);\n``` \n\nGiven the following template and data:\n```\n{{#each data}}{{#if @first}}FIRST: {{/if}}{{this}}\u003cbr\u003e{{/each}}\n```\n```php\n'data' =\u003e ['apple', 'banana', 'carrot', 'zucchini']\n```\nThe output will be\n```html\nFIRST: apple\u003cbr\u003ebanana\u003cbr\u003ecarrot\u003cbr\u003ezucchini\u003cbr\u003e\n```\n\nGiven the following template and the data above:\n```\n{{#each data}}{{@first}}: {{this}}\u003cbr\u003e{{/each}}\n```\nThe output will be\n```html\ntrue: apple\u003cbr\u003ebanana\u003cbr\u003ecarrot\u003cbr\u003ezucchini\u003cbr\u003e\n```\n\nData variables also support relative referencing within multiple #each statements.\nGiven\n```\n{{#each data}}{{#each this}}outer: {{@../first}},inner: {{@first}};{{/each}}{{/each}}\n```\n```php\n'data' =\u003e [['apple', 'banana'], ['carrot', 'zucchini']]\n```\nThe output will be \n```\nouter: true,inner: true;outer: true,inner: false;outer: false,inner: true;outer: false,inner: false;\n```\n\nBe aware that when data variables are enabled, variables starting with `@` are considered restricted and will override\nvalues specified in the data.\n\nFor example, given the following template and the following data, the output will be different depending on if data\nvariables are enabled.\n\n```\n{{#each objects}}{{@first}}, {{@last}}, {{@index}}, {{@unknown}}{{/each}}\n```\n\n```php\n$object = new stdClass;\n$object-\u003e{'@first'} = 'apple';\n$object-\u003e{'@last'} = 'banana';\n$object-\u003e{'@index'} = 'carrot';\n$object-\u003e{'@unknown'} = 'zucchini';\n$data = ['objects' =\u003e [$object]];\n\n$engine = new \\Handlebars\\Handlebars(array(\n    'loader' =\u003e new \\Handlebars\\Loader\\StringLoader(),\n    'helpers' =\u003e new \\Handlebars\\Helpers(),\n    'enableDataVariables'=\u003e $enabled,\n));\n$engine-\u003erender($template, $data)\n``` \n\nWhen `enableDataVariables` is `false`, existing behavior is not changed where some variables will be return. \n\n```\napple, banana, 0, zucchini\n```\n\n\nWhen `enableDataVariables` is `true`, the behavior matches HandlebarsJS 1.1 behavior, where all data variables replace\nvariables defined in the data and any data variable prefixed with `@` that is unknown will be blank.\n\n```\ntrue, true, 0,\n```\n\n\n#### Credits\n\n* Fork of [Handlebars.php by XaminProject](https://github.com/XaminProject/handlebars.php)\n* The documentation was edited by [Mardix](http://github.com/mardix).\n\n#### Contribution\n\nContributions are more than welcome!","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalesforce%2Fhandlebars-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsalesforce%2Fhandlebars-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalesforce%2Fhandlebars-php/lists"}