{"id":20520999,"url":"https://github.com/markjivko/themewarlock","last_synced_at":"2026-04-22T09:07:25.135Z","repository":{"id":229041170,"uuid":"453470189","full_name":"markjivko/themewarlock","owner":"markjivko","description":"WordPress Theme Builder","archived":false,"fork":false,"pushed_at":"2022-02-23T15:20:34.000Z","size":22651,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-06T00:26:20.349Z","etag":null,"topics":["markjivko","php","theme-builder","wordpress","wordpress-php","wordpress-theme"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markjivko.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}},"created_at":"2022-01-29T17:36:06.000Z","updated_at":"2022-01-29T20:26:31.000Z","dependencies_parsed_at":"2024-03-21T19:05:35.372Z","dependency_job_id":null,"html_url":"https://github.com/markjivko/themewarlock","commit_stats":null,"previous_names":["markjivko/themewarlock"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/markjivko/themewarlock","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markjivko%2Fthemewarlock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markjivko%2Fthemewarlock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markjivko%2Fthemewarlock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markjivko%2Fthemewarlock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markjivko","download_url":"https://codeload.github.com/markjivko/themewarlock/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markjivko%2Fthemewarlock/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32128742,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T08:34:57.708Z","status":"ssl_error","status_checked_at":"2026-04-22T08:34:55.583Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["markjivko","php","theme-builder","wordpress","wordpress-php","wordpress-theme"],"created_at":"2024-11-15T22:25:12.976Z","updated_at":"2026-04-22T09:07:25.118Z","avatar_url":"https://github.com/markjivko.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ThemeWarlock\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/markjivko/themewarlock\"\u003e\n        \u003cimg src=\"https://repository-images.githubusercontent.com/453470189/5584e2e8-3016-4be2-a956-b471a9d63c33\"/\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\nThemeWarlock is a theme builder designed for quick preview and deployment of WordPress themes.\n\n**This project is in beta, not ready for public testing**\n\n# Addons\n\nAddons are a way to dynamically alter the functionality of your WordPress theme.\n\nThey can be enabled and configured through the web editor.\n\nEach addon's configuration options are stored in **Model_Project_Config_Item** \nobjects.\n\nYou can customize each addon's deployment with the use of **{tags}**.\n\n## Folder structure\n\nEnabled addon's files are automatically copied over to the final project destination\nand all custom tags are replaced with their respective values.\n\nFile names also support **data tags**.\n\nThe **go.php** file and the **go** folder will be skipped.\n\n## The go folder\n\nThe **go** folder is optional and it has the following structure:\n\n * / **PresetName**\n    * / **style.css**\n    * / **\\_style.css**\n    * / **customizer.css**\n    * / **functions.js**\n    * / **\\_functions.js**\n * / ...\n\nThe **PresetName** can be any string describing that CSS/JS addon preset (also known as a **flavor**).\n\nThe user can then select that preset from the web interface to customize the current addon's UI.\n\nAll files in the **go** folder support **data tags** only.\n\nThe contents of the **style.css** file is automatically appended to the core theme's style file.\nAutomatic re-indexing of the CSS comment headers takes place.\n\nThe contents of the **functions.js** file is automatically appended to the core theme's function file, as a worker function:\n\n\u003e {project.prefix}_instance.addWorker(\"__ADDON__\", function(addonName, _this) {\n\u003e \n\u003e }\n\nThe contents of the **customizer.css** file is parsed and used to populate the **cssRules** property of the **Addon** class.\n\nIf a **customizer.css** file is not declared for the current flavor, the default one will be used instead.\n\nEach rule has the following structure:\n\n\u003e /\\* key.subkey \\*/\n\u003e \n\u003e cssSelector {\n\u003e \n\u003e         cssProperty: cssValue;\n\u003e \n\u003e }\n\nThe CSS comment block is very important. Its contents will be converted into an associative array structure.\n\nThe CSS rules associated with each comment block extend up until the next comment block or until the EOF.\n\nIn the above example, the **cssRules** property in **Addon** becomes\n\n\u003e array('key' =\u003e array('subkey' =\u003e 'cssSelector {...}'))\n\nThe contents of the **functions.js** file is automatically appended to the **js/functions.js** file,\nright before the **{project.prefix}_instance.init();** statement, encased in a \n**{project.prefix}_instance.addWorker()** method call.\n\nThe contents of the **\\_functions.js** and **\\_style.css** are **appended**, whereas **functions.js** and\n**style.css** **replace** the corresponding files from the **default** flavor.\n\n## The go.php file\n\n### Naming conventions\n\nThe **go.php** file must contain a **class** that extends **Addon**.\n\nThe class name should begin with **Addon_** and be followed by a **camel-cased**,\n**alpha-numeric**, **capitalized** variant of the addon's folder name.\n\n\u003e Example: for the addon **core-custom-colors**, the class name should be \n\u003e **Addon_CoreCustomColors**.\n\n### Functionality\n\n#### Methods\n\n1. You can execute addon-specific tasks at certain points during the deployment of\nyour WordPress theme by using **before** and **after** **hooks**.\n\n    The method naming convention is as follows:\n\n    * before / after\n    * task name (from **/lib/Tasks**) without the leading number\n\n    \u003e Example: \n    \u003e \n    \u003e * **afterNewProject()**\n    \u003e * **beforeRelease()**\n\n2. You can set this addon's user-configurable options and other WordPress-related\ndetails by defining or extending the **Addon** class's methods:\n\n    \u003e List of extendable methods:\n    \u003e\n    \u003e * **getOptions()**\n    \u003e * **getPlugins()**\n    \u003e * **getTags()**\n    \u003e * **initCustomizer()** - see **Data tags / {call}**\n    \u003e * **initDrawables()** - see **Data tags / {call}**\n    \u003e * **assert($testName)** - see **Action tags**\n\n3. You can use any method defined in your addon class by referencing it with the \n**{call}** tag.\n\n    \u003e Example:\n    \u003e \n    \u003e Method **getTimeOfDay()**'s result will replace the **{call.addonName.getTimeOfDay}**\n    \u003e tag in this addon's files.\n\n#### Properties\n\n1. **$addonData**\n\n    Model_Project_Config_Item[]. Array of this addon's configuration items, as \ndefined in the **getOptions()** method.\n\n2. **$addonIcon**\n\n    String. **Twitter_Bootstrap_GlyphIcon::GLYPH_*** icon to use when listing this addon.\n\n3. **$safeMethods**\n\n    String[]. The results of these methods will not be escaped.\n\n\n## Tags\n\nYou can use any one of the following tags to customize your addon files.\n\nCurrently, tags are supported only for the following file extensions:\n\n  * **php** \\*\n  * **phtml** \\*\n  * **html**\n  * **xhtml**\n  * **js** \\*\n  * **css**\n  * **cfg**\n  * **txt**\n\n\\* These files also feature automatic **escaping** in order to prevent code \ninjection by any of the designers working on the WordPress themes.\n\nYou can call any method from the current framework agnostically by refering to it\nas **\"framework\"** in any action tag or data tag that expects an **addonName** argument.\n\n\u003e Example: \n\u003e \n\u003e * `{call.framework.methodName}`\n\u003e * `{add **if**=\"framework.x\"}`\n\u003e * `{if.framework.testName}`\n\u003e \n\u003e is the same as\n\u003e \n\u003e * `{call.onepage.methodName}`\n\u003e * `{add **if**=\"onepage.x\"}`\n\u003e * `{if.onepage.testName}`\n\u003e \n\u003e if the current framework is \"onepage\"\n\n### Action tags\n\nAction tags **DO NOT** allow **nesting**!\n\nThey are to be treated as TODO list items. Actions are executed in the order they\nare defined.\n\nAction tags are executed **after** the data tags.\n\nAll action tags share the following property:\n\n  * **if** - (Optional) execute the action tag only if the assertion test passes\n\n    \u003e {add **if**=\"addonName.testName\"}\n    \u003e \n    \u003e         Text to insert\n    \u003e \n    \u003e {/add}\n\nThe **addonName** is the name of the addon that has defined the **assert($testName)** method.\n\nExample:\n\n        public function assert($testName) {\n\n            switch($testName) {\n\n                case 'x':\n                    // Perform any type of validation here\n                    // ...\n                    return true; \n\n            }\n\n        }\n\nThe **$testName** is the name of the test you wish to pass before executing this tag.\n\nThe test passes only if the **assert($testName)** method returns boolean **true** (or equivalent)!\n\n#### {add}\n\nAdd a block of text in specific locations over an existing file using RegEx.\n\n1. Before a block of text\n\n    \u003e {add **before**=\"regex\"}\n    \u003e \n    \u003e         Text to add before a specified location\n    \u003e \n    \u003e {/add}\n\n2. After a block of text\n\n    \u003e {add **after**=\"regex\"}\n    \u003e \n    \u003e         Text to add after a specified location\n    \u003e \n    \u003e {/add}\n\n3. Replace a block of text\n\n    \u003e {add **replace**=\"regex\"}\n    \u003e \n    \u003e         Text replacement\n    \u003e \n    \u003e {/add}\n\n#### {remove}\n\nRemove a block of text in a specific location from an existing file using RegEx.\n\n1. Remove a block of text\n\n    \u003e {remove}regex{/remove}\n\n### Data tags\n\nData tags **ALLOW nesting**. This is especially useful when using the **{foreach}** \nor **{if}** / **{else}** tags is combination with other data tags.\n\nData tags are replaced with string representations.\n\nWhether or not these strings are escaped depends on the file type and data tag.\n\nYou can force disable escaping by capitalizing the data tag.\n\n\u003e Example:\n\u003e \n\u003e * `{Call.addonName.methodName}`\n\nAs opposed to action tags, data tags can also be used for **file names**.\n\n\u003e Example:\n\u003e \n\u003e Local file name: **{config.ns}_icon.png**\n\u003e \n\u003e Final file name: **st_icon.png**\n\n#### {options}\nThe options tag holds all of the current project's options, including the core \noptions and each individual addon's options for **cross-addon** configuration access.\n\nAutomatic escaping takes place for the following file extensions:\n\n  - **.js**: `json_encode`\n  - **.php**, **.phtml**: `var_export`\n\n\u003e Structure:\n\u003e \n\u003e * `{options.[core addon option]}`\n\u003e * `{options.projectAddons.[addon name].[addon option]}`\n\u003e * `{options._staging}`: 'y' or 'n'\n\u003e * `{options._snapshotId}`: numeric, current snapshot ID\n\n\u003e Example: \n\u003e \n\u003e * `{options.projectVersion}`\n\u003e * `{options.projectAddons.core-custom-colors.color1}`\n\n#### {addon}\n\nThe addon tag holds all of the current addon's options for ease of access.\n\nThe following are equivalent if the current addon is **core-custom-colors**:\n\n - `{options.projectAddons.core-custom-colors.color1}`\n - `{addon.color1}`\n\nAutomatic escaping takes place for the following file extensions:\n\n  - **.js**: `json_encode`\n  - **.php**, **.phtml**: `var_export`\n\n\u003e Example: \n\u003e \n\u003e * `{addon.projectName}`\n\u003e * `{addon.projectIcon}`\n\n#### {if}\n\nInsert a block of text on the spot if the validation succeeds.\n\n\u003e Example:\n\u003e \n\u003e {if.addonName.testName}\n\u003e \n\u003e         // testing??\n\u003e \n\u003e {/if.addonName.testName}\n\nThe **addonName** is the name of the addon that has defined the **assert($testName)** method.\n\nExample:\n\n        public function assert($testName) {\n\n            switch($testName) {\n\n                case 'x':\n                    // Perform any type of validation here\n                    // ...\n                    return true; \n\n            }\n\n        }\n\nThe **$testName** is the name of the test you wish to pass before executing this tag.\n\nThe test passes only if the **assert($testName)** method returns boolean **true** (or equivalent)!\n\nIf no **testName** is provided, the assertion is validated if the addon is enabled.\n\n#### {else}\n\nInsert a block of text on the spot if the validation fails.\n\n\u003e Example:\n\u003e \n\u003e {else.addonName.testName}\n\u003e \n\u003e         // testing??\n\u003e \n\u003e {/else.addonName.testName}\n\nThe **addonName** is the name of the addon that has defined the **assert($testName)** method.\n\nExample:\n\n        public function assert($testName) {\n\n            switch($testName) {\n\n                case 'x':\n                    // Perform any type of validation here\n                    // ...\n                    return false; \n\n            }\n\n        }\n\nThe **$testName** is the name of the test you wish to fail before executing this tag.\n\nThe test fails only if the **assert($testName)** method returns a value other than boolean **true** (or equivalent)!\n\nIf no **testName** is provided, the assertion is validated if the addon is disabled.\n\n#### {foreach}\n\nUse a block of text as a template, then iterate over an array.\n\nThe array keys and values will get automatically replaced.\n\nUse **{@key}** for the escaped keys and **{@value}** for the escaped values.\n\nUse **{@Key}** for the unescaped keys and **{@Value}** for the unescaped values.\n\n\u003e Example:\n\u003e \n\u003e {foreach.addonName.methodName}\n\u003e \n\u003e         // Testing {@key}\n\u003e \n\u003e         // Testing {@value}\n\u003e \n\u003e {/foreach.addonName.methodName}\n\nYou can also define custom key and value variables in order to handle nested\nforeach statements using the **as=\"key.value\"** attribute.\n\n\u003e Example:\n\u003e \n\u003e {foreach.addonName.methodName}\n\u003e \n\u003e         // Testing {@key}\n\u003e \n\u003e         // Testing {@value}\n\u003e \n\u003e         {foreach.addonName.methodNameBeta as=\"keyBeta.valueBeta\"}\n\u003e \n\u003e             // Testing {@keyBeta}\n\u003e\n\u003e             // Testing {@valueBeta}\n\u003e \n\u003e         {/foreach.addonName.methodNameBeta}\n\u003e \n\u003e {/foreach.addonName.methodName}\n\nThe **addonName** is the name of the addon that has defined the **methodName()** method.\n\nThe result of the **methodName()** must be an associative array!\n\nYou can also pass extra arguments to the method.\n\n\u003e Example:\n\u003e \n\u003e {foreach.addonName.methodName.arg1.arg2}\n\u003e \n\u003e         // Testing {@key}\n\u003e \n\u003e         // Testing {@value}\n\u003e \n\u003e {/foreach.addonName.methodName.arg1.arg2}\n\nThe **{@value}** tags support traversing for associative arrays, objects properties \nand objects methods - without additional arguments.\n\n\u003e Example:\n\u003e \n\u003e {@value.key}\n\u003e {@value.objectProperty}\n\u003e {@value.objectMethod}\n\u003e {@value.key.objectProperty.objectMethod}\n\nTraversing overflow is ignored; the last valid tree branch is used instead of null.\n\n\u003e Example:\n\u003e \n\u003e Suppose we have this array as input: array(\"foo\" =\u003e array(\"bar\" =\u003e \"baz\"))\n\u003e\n\u003e {@key} = \"foo\"\n\u003e {@value} = array(\"bar\" =\u003e \"baz\")\n\u003e {@value.bar} = \"baz\"\n\u003e {@value.bar.extra} = \"baz\"\n\n#### {call}\n\nThe call tag holds the result of calls to custom methods defined in addon's **go.php** files.\n\nAutomatic escaping takes place for the following file extensions:\n\n  - **.js**: `json_encode`\n  - **.php**, **.phtml**: `var_export`\n\nAutomatic escaping can be disabled for each method individually by listing it in \nthe **$safeMethods** public static property:\n\n        public static $safeMethods = array('doNotEscapeThisMethodsResult');\n\n\u003e Example: \n\u003e \n\u003e * `{call.core-custom-colors.codePrepareCss}`\n\u003e * `{call.core-custom-colors.codeRegisterColors}`\n\nIf you have defined the **initCustomizer()** method in your addon, you can use the \n**customizer** tag to reference **WordPress_Customizer_Element_Item** objects' methods.\n\n\u003e Example:\n\u003e \n\u003e * `{call.onepage.customizer._register}`\n\u003e * `{call.onepage.customizer._stylize}`\n\u003e * `{call.onepage.customizer.layout-toggle.exportVarInit}`\n\u003e * `{call.onepage.customizer.layout-toggle.exportVarName}`\n\u003e * `{call.onepage.customizer.layout-toggle.getTransport}`\n\nYou should do all image processing inside the **initDrawables()** method.\n\nAvailable image processing tools:\n\n* **$this-\u003e_image**\n* **$this-\u003e_imageMagick**\n* **$this-\u003e_imagick**\n\n\u003e Example of getting the path to a designer-set file:\n\u003e \n\u003e `$this-\u003eaddonData[self::KEY_IMAGE]-\u003egetPath();`\n\n\n\u003e Save the drawables to the project path:\n\u003e \n\u003e `Tasks_1NewProject::getPath();`\n\n#### {utils}\n\nThe utils tag holds the result of calls to custom methods defined in the \n**Addons_Utils** class.\n\nAutomatic escaping takes place for the following file extensions:\n\n  - **.js**: `json_encode`\n  - **.php**, **.phtml**: `var_export`\n\nAutomatic escaping can be disabled for each method individually by listing it in \nthe **$safeMethods** public static property:\n\n        public static $safeMethods = array('doNotEscapeThisMethodsResult');\n\n\u003e Safe methods: \n\u003e\n\u003e * `{utils.common.copyright}`\n\u003e * `{utils.common.quote}`\n\u003e * `{utils.common.tagsList}`\n\u003e * `{utils.common.themeUrl}`\n\u003e  \n\u003e Escaped methods:\n\u003e \n\u003e * `{utils.color.rgba.[current addon's color option]}`\n\u003e * `{utils.color.wp.[current addon's color option]}`\n\n#### {project}\n\nThe project tag contains project structure-specific data.\n\nThe keys represent the public static properties of **Tasks_1NewProject**.\n\nAutomatic escaping **DOES NOT** take place. All values are used as such \nregardless of file extension.\n\n\u003e Possible values: \n\u003e \n\u003e * `{project.sourceDir}`\n\u003e * `{project.destDir}`\n\u003e * `{project.prefix}`\n\u003e * `{project.destAuthorName}`\n\u003e * `{project.destProjectName}`\n\u003e * `{project.versionVerbose}`\n\n#### {framework}\n\nThe framework tag contains framework-specific data.\n\nThis information is defined in the corresponding **info.php** file for this \nframework.\n\nAutomatic escaping **DOES NOT** take place. All values are used as such \nregardless of file extension.\n\n\u003e Possible values: \n\u003e \n\u003e * `{framework.framework_target}`\n\u003e * `{framework.framework_id}`\n\n#### {config}\n\nThe config tag contains the **config.ini** values.\n\nAutomatic escaping **DOES NOT** take place. All values are used as such \nregardless of file extension.\n\n\u003e Possible values: \n\u003e \n\u003e * `{config.authorName}`\n\u003e * `{config.authorUrl}`\n\u003e * `{config.authorEmail}`\n\u003e * `{config.appMode}`\n\u003e * `{config.logLevel}`\n\u003e * `{config.getUse}`\n\u003e * ...\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkjivko%2Fthemewarlock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkjivko%2Fthemewarlock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkjivko%2Fthemewarlock/lists"}