{"id":19253515,"url":"https://github.com/givanz/vtpl","last_synced_at":"2025-04-21T14:32:07.945Z","repository":{"id":940443,"uuid":"715500","full_name":"givanz/vtpl","owner":"givanz","description":"Vtpl is a php template engine that ensures proper separations of concerns, the frontend logic is separated from presentation. The goal is to keep the html unchanged for better maintainability for both backend and frontend developers","archived":false,"fork":false,"pushed_at":"2024-03-11T14:37:36.000Z","size":57,"stargazers_count":19,"open_issues_count":2,"forks_count":5,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-01T13:51:13.986Z","etag":null,"topics":["css","dom","dom-manipulation","dsl","front-end","front-end-development","frontend","handlebars","html","html-template","layout","liquid","mustache","php","template","template-engine","template-language","templating","vtpl"],"latest_commit_sha":null,"homepage":"https://www.vvveb.com","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/givanz.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2010-06-11T11:55:19.000Z","updated_at":"2025-03-05T11:59:46.000Z","dependencies_parsed_at":"2024-11-09T18:33:22.603Z","dependency_job_id":"511b9ff9-27df-46fc-badc-045dd2fc3cf8","html_url":"https://github.com/givanz/vtpl","commit_stats":null,"previous_names":["givanz/vtpl"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/givanz%2Fvtpl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/givanz%2Fvtpl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/givanz%2Fvtpl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/givanz%2Fvtpl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/givanz","download_url":"https://codeload.github.com/givanz/vtpl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250070271,"owners_count":21369845,"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":["css","dom","dom-manipulation","dsl","front-end","front-end-development","frontend","handlebars","html","html-template","layout","liquid","mustache","php","template","template-engine","template-language","templating","vtpl"],"created_at":"2024-11-09T18:31:29.417Z","updated_at":"2025-04-21T14:32:07.653Z","avatar_url":"https://github.com/givanz.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Vtpl template engine  \r\n \r\n \r\n## Description\r\n \r\nVtpl is template engine for php that acts as a binding language between php and html.\r\n \r\nUnlike most template engines that work by adding placeholders like `{$myvar}` inside html code, Vtpl uses css selectors to specify where to insert php code or variables into the html code.\r\n \r\nThe goal is to keep the html unchanged for better maintainability for both backend and frontend developers.\r\n \r\nWith Vtpl when the frontend design or theme of your app is changed you don’t have to change anything, the logic for the html file will be automatically applied for these new html files.   \r\n \r\nVtpl ensures proper separations of concerns, the frontend logic is separated from presentation.\r\n \r\nTemplates are just lists of css selectors and php code and variable names to insert.\r\n \r\nThis makes it possible to build a CMS like [Vvveb](https://www.vvveb.com) where any html page of the CMS can be changed to the last element without affecting the rendering of dynamic content from the database.\r\n \r\n \r\n## Documentation\r\n \r\nVtpl templates are just a list of `key = value` pairs.   \r\n \r\nOn the left you need to specify the CSS selector and on the right the code or variable that must be inserted for the selector.   \r\n \r\n`#css_selector = $php_variable`\r\n \r\nThe code to be inserted can be one of the following\r\n \r\n##### Simple strings\r\n \r\n```\r\ndiv#id \u003e span.class a = \"lorem ipsum\"\r\n```\r\n \r\n##### Php variables\r\n \r\n```css\r\ndiv#id \u003e span.class a = $variable\r\n \r\n```\r\n \r\n##### Php code for complex logic\r\n \r\n```css\r\ndiv#id \u003e span.class a = \u003c?php if (isset($var)) echo htmlentities($var);?\u003e\r\n```\r\n \r\n \r\n\u003e **Note**\r\n\u003e It's a good practice to adopt a standard for the css selectors from the beginning, for example use data attributes like `[data-product-name]` instead of generic id's or css classes to keep things clean.\r\n \r\n##### Include external html sections for better reuse by using `from`\r\n \r\n```css\r\n/*\r\nfrom, a special command that copies html from other templates,\r\nuseful to include up to date html code into all templates from the currently maintained template for the specified section \r\na common use is to apply the header from homepage to all other other html templates\r\n*/\r\n \r\ndiv#top \u003e div.header = from(homepage.html|div#top \u003e div.header)\r\n \r\n/*\r\nOr you can skip the selector part, in this case the same selector (eg div#top \u003e div.header) is assumed.\r\n*/\r\ndiv#top \u003e div.header = from(homepage.html)\r\n \r\n```\r\n \r\n \r\n## List of modifiers   \r\n \r\n##### innerHTML\r\n \r\n```css\r\n/*\r\nby default code is inserted into the specified elements without replacing the current elements (innerHTML)  \r\nto replace the entire elements with the specified code use outerHTML modifier\r\n*/\r\n \r\ndiv#id \u003e span.class a|innerHTML = \"lorem ipsum\"\r\n```\r\n \r\n \r\n##### Before\r\n \r\n```css\r\n/*\r\nInserts the code before the element(s)\r\n*/\r\ndiv#id \u003e span.class a|before = \"lorem ipsum\"\r\n \r\n```\r\n \r\n##### Prepend\r\n \r\n```css\r\n/*\r\nInserts the code at the beginning inside the element(s)\r\n*/\r\ndiv#id \u003e span.class a|prepend = \"lorem ipsum\"\r\n \r\n```\r\n \r\n##### After\r\n \r\n```css\r\n/*\r\nInserts the code after the element(s)\r\n*/\r\ndiv#id \u003e span.class a|after = \"lorem ipsum\"\r\n \r\n```\r\n##### Append\r\n \r\n```css\r\n/*\r\nInserts the code at the end in the element(s)\r\n*/\r\ndiv#id \u003e span.class a|append = \"lorem ipsum\"\r\n```\r\n \r\n \r\n##### deleteAllButFirst\r\n \r\n```css\r\n/* Deletes all elements for the specified selector except for the first elements,  \r\nusually in mockups front end developers add multiple elements to better show the final page look,  \r\nthe programmer just needs one element to iterate and fill data*/\r\n \r\ndiv#id \u003e span.class a|deleteAllButFirst\r\n \r\n/*\r\n \r\n\u003c!-- this --\u003e\r\n\u003cdiv id=\"id\"\u003e\r\n\u003cspan class=\"class\"\u003e\r\n\u003ca\u003elink 1\u003c/a\u003e\r\n\u003ca\u003elink 2\u003c/a\u003e\r\n\u003ca\u003elink 3\u003c/a\u003e\r\n\u003c/span\u003e\r\n\u003c/div\r\n \r\n**wil result into this**\r\n \r\n\u003cdiv id=\"id\"\u003e\r\n\u003cspan class=\"class\"\u003e\r\n\u003ca\u003elink 1\u003c/a\u003e\r\n\u003c/span\u003e\r\n\u003c/div\u003e\r\n*/\r\n```\r\n \r\n \r\n##### deleteAllButFirstChild\r\n\r\nThe same as `deleteAllButFirst` but will keep the first element (child element) for each set, all parent elements will keep only one child element in contrast with `deleteAllButFirst` that works globally.\r\n \r\n#### hide\r\n \r\n```css\r\n/*removes the specified elements if the variable ($articles) is false*/\r\ndiv.articles|if_exists = $articles\r\n```\r\n \r\n \r\n#### delete\r\n \r\n```css\r\n/* removes the specified elements*/\r\ndiv.articles|delete\r\n```\r\n \r\n \r\n#### attributes\r\n \r\n```css\r\n/*\r\nto inject code into a tag's attribute you must specify the attribute as modifier\r\n*/\r\ndiv#id \u003e span.class a|href = \"www.thewebsite.com\"\r\n \r\ndiv#id \u003e span.class a|title = \"The website\"\r\n```\r\n \r\nYou can also use variables directly in the attributes\r\n```html\r\n \r\n\u003cimg alt=\"$image.alt\" src=\"\"\u003e\r\n \r\n\u003ca href=\"$this.product.url\"\u003elink\u003c/a\u003e\r\n \r\n\u003cspan title=\"$date_modified\"\u003e\u003c/span\u003e\r\n \r\n```\r\n \r\n## Additional commands   \r\n \r\n#### Import\r\n \r\nIncludes additional files, useful to separate logic when things get bigger and harder to maintain in one file\r\n \r\n```css\r\nimport(profile/activity_tab.tpl)\r\n```\r\n \r\n \r\n## Comments\r\n \r\nVtpl can have comments   \r\n \r\n```\r\n //single line   \r\n /* Or multiple line   \r\n comments   \r\n */   \r\n```\r\n \r\n## Placeholders\r\n \r\nWith placeholders you can use the value of attributes, attribute names or html node values/text inside the php code.\r\nFor example if you need to display a specific image size based on an attribute set on the img tag you can use something like\r\n \r\n```html\r\n\u003cimg src=\"puppy.jpg\" data-size=\"thumb\"\u003e  \r\n```\r\n \r\n```php\r\nimg|src = \u003c?php\r\n    echo getScaledImage('@@__src__@@', '@@__data-size__@@');\r\n?\u003e\r\n```\r\n \r\nYou can also use them to avoid code repetition for example to replace all variables with a specified prefix with one line.\r\n \r\n```html\r\n\u003ch3 data-v-product-title\u003eMy product\u003c/h3\u003e\r\n\u003cspan data-v-product-price\u003e$100\u003c/span\u003e\r\n\u003cp data-v-product-desciption\u003eLorem ipsum\u003c/p\u003e\r\n```\r\n \r\n```php\r\n[data-v-product-*] = $product['@@__data-product-(*)__@@']\r\n \r\n```\r\n \r\nThen the resulted php code will be  \r\n \r\n```php\r\n\u003ch3 data-v-product-title\u003e\u003c?php echo $product['title'];?\u003e\u003c/h3\u003e\r\n\u003cspan data-v-product-price\u003e\u003c?php echo $product['price'];?\u003e\u003c/span\u003e\r\n\u003cp data-v-product-desciption\u003e\u003c?php echo $product['description'];?\u003e\u003c/p\u003e\r\n```\r\n \r\n \r\nAvailable placeholders:  \r\n * `@@__innerText__@@`           - inner html of the node\r\n * `@@__innerText__@@`           - inner text of the node\r\n * `@@__my-attribute__@@`        - value of my-attribute of current node\r\n * `@@__data-v-plugin-(*)__@@`   - (*) matches any charachter for example for data-v-plugin-name it will return `name`\r\n * `@@__data-v-plugin-(.+)__@@`  - run any regex inside () and return first match \\1 for example for data-v-plugin-name it will return `name`\r\n * `@@__my-*:my-(.*)__@@`        - get attribute name that starts with 'my-' and run the regex after ':' used to extract attribute name from current node\r\n \r\n \r\n## Filters  \r\n \r\nWith filters you can pass the content of the html tag through a php function.\r\nFor example to make the first letter uppercase of all title on the page you can use the ucfirst filter like.\r\nThis is useful if the html is edited by a designer that wants to apply filters like uppercase, friendly dates etc to the html without touching the templates.\r\n \r\n```html\r\n\u003ch3 data-post-title data-v-filter-ucfirst\u003emy title\u003c/h3\u003e\r\n\u003cspan data-post-date_modified data-v-filter-friendly_date\u003e2024-06-01\u003c/span\u003e\r\n```\r\n \r\nEven if you have defined php variables for *post-title* and *post-date* the filters will be applied if theu are added to html by the user or designer\r\n \r\n```php\r\n[data-post-title] = $post['title']\r\n[data-post-date_modified] = $post['date_modified']\r\n \r\n//or more simply\r\n[data-post-*] = $post['@@__data-post-(*)__@@']\r\n```\r\n \r\n### Json\r\n \r\nSometimes you might need to give the user or designer the possibilty to add more complex options to html, in this case you can use json in html attributes like  \r\n \r\n```\r\n\u003cdiv data-my-product data-v-myjson='{var:{subvar1:val1, subvar2:val2}}'\u003e\u003c/div\u003e\r\n```\r\n \r\nThen in the template you can use something like `@@myjson.var.subvar1@@` will return val1 the configuration passed in the attribute to fill the content of the div with\r\n \r\n```php\r\n[data-my-product] = \u003c?php\r\n$parameter1 = '@@myjson.var.subvar1@@;//will be 'val1'\r\n$parameter2 = '@@myjson.var.subvar2@@;//will be 'val2'\r\n$alloptions = @@myjson@@;//this will be a php array with the values from json\r\n \r\necho displayProduct($parameter1, $parameter2);\r\n```\r\n \r\nProcess `data-filter-*` attributes defined in filters array.\r\n\r\nProcess attributes with json and transforms them to php arrays ex: `data-my-data='{var:\"value\"}'`\r\n\r\nProcess macro definitions like `@@macro Mymacro('var1', 'var2')` Mymacro must be a function defined with name vtplMymacro and must accept two variables like in definition\r\n\r\nProcess json path, for a node with `data-v-myjson='{var:{subvar1:val1, subvar2:val2}}'` `@@myjson.var.subvar1@@` will return `val1`\r\n \r\n \r\n## Macros\r\n \r\nWith macros you can call php functions while the template is being processed, the macro definition is replaced with the returned result from the function.\r\nThey are used if you want to process some attribute values or content from the html.\r\n \r\nYou can define your own macros with `@@macro myPhpfunction('myparameter')@@;` then you need to define a php function named `vtplmyPhpfunction` that will be called when the macro is run.\r\nYou can also use the `@@__my-attribute-name__@@` placeholder to pass attribute values to the macro function like `@@macro myPhpfunction(\"@@__href__@@\")@@`\r\n \r\nFor example to have a if conditional attribute in the html to use it like `\u003cdiv data-v-if=\"price \u003e 100\"\u003eFree shipping\u003c/div\u003e`\r\nyou need to process the contents of `data-v-if` attribute and show the tag only if the condition is met for this you can use a macro like this:\r\n \r\n```php\r\n//if  \r\n[data-v-if]|before = \u003c?php  \r\n$condition = @@macro IfCondition(\"@@__data-v-if__@@\")@@;\r\nif  ($condition) {\r\n?\u003e  \r\n \r\n[data-v-if]|after = \u003c?php } ?\u003e\r\n```\r\n \r\nAnd in `vtplIfCondition` php function you can just transform `price \u003e 100` to php code a boolean conditional like `$this-\u003eprice \u003e 100` in this way the final php code that will be inserted in the compiled html/php will be\r\n \r\n```php\r\n//if  \r\n\u003c?php  \r\n$condition = $this-\u003eprice \u003e 100;\r\nif ($condition) {\r\n?\u003e\r\n\r\n```\r\nSome macros like if and if class are available by default\r\n\r\n### If macro\r\n\r\n`data-v-if=\"condition\"`\r\n\r\n`data-v-if-not=\"condition\"`\r\n\r\nTo show/hide an element only if the condition is met\r\n\r\n```html\r\n\u003cspan data-v-if=\"product.price \u003e 20\"\u003eFree shipping for this product\u003c/span\u003e\r\n```\r\n```html\r\n\u003cspan data-v-if=\"product.price \u003e 20\"\u003eFree shipping for this product\u003c/span\u003e\r\n```\r\n\r\n### If class macro\r\n\r\n`data-v-class-if-class_name=\"condition\"`\r\n\r\n`data-v-class-if-not-class_name=\"condition\"`\r\n\r\n\r\nTo add class `premium` to a div if price is higher than 30 \r\n\r\n```html\r\n\u003cdiv data-v-class-if-premium=\"product.price \u003e 30\"\u003e\u003c/div\u003e\r\n\r\n\u003cdiv data-v-class-if-not-standard=\"this.product.price \u003e 30\"\u003e\u003c/div\u003e\r\n```\r\n\r\nWill result in \r\n\r\n```html\r\n\u003cdiv class=\"premium\"\u003e\u003c/div\u003e\r\n```\r\n\r\n \r\n## Interpolation\r\n\r\nSometimes you need to pass data to javascript for this cases you can use a simple `{$variable}` syntax\r\n\r\n```php\r\n\u003c?php\r\n$this-\u003edate_created = 'Today';\r\n$this-\u003emy_object = ['date_created' =\u003e '10:00', 'date_modified' =\u003e '12:30'];\r\n?\u003e\r\n```\r\n\r\n```html\r\n\u003cbody\u003e\r\n\u003cdiv\u003e\u003c/div\u003e\r\n\u003cscript\u003e\r\nlet date_created = '{$this.date_created}';//the output will be text/string and needs quotes\r\nlet my_object = {$this.my_object};//the php array will be converted to json object\r\n\u003c/script\u003e\r\n\u003c/body\u003e\r\n```\r\n\r\n## Attribute interpolation\r\n\r\nWhen you need to quickly insert some data in a node attribute at some position to avoid concatenating and embeding existing attribute text in the template.\r\n\r\n```php\r\n\u003c?php\r\n$this-\u003edate_created = '12:30';\r\n?\u003e\r\n```\r\n\r\n```html\r\n\u003ca title=\"Created at {$this.date_created}\"\u003eDate\u003ca\u003e\r\n```\r\n\r\n## Debugging\r\n \r\nIf a global `VTPL_DEBUG` constant is true then a console will show on the bottom of the page with all the insert operations made on the html.\r\n \r\nWhen in debug mode, you will have a list of all template injections made on the html to visualize.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgivanz%2Fvtpl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgivanz%2Fvtpl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgivanz%2Fvtpl/lists"}