When your theme is complete and demo page is working, there’s one more thing left to do before the upload. That is to set up a zip package containing theme contents with proper text domain, compiled styles, generated demo content, promo materials, documentation, languages etc.
Packages are automatically built by Phing tasks. All you need to do is configure them in build.xml file. Then, ask a project manager to build a package.
Please follow the boilerplate structure: Theme structure
In particular, make sure you do have the following directories:
wp-content/ ├-themes/ ├-projectname/ ├-build/ # There should be build.xml and build.properties files already there ├-docs/ # Put pdf documentation here (or create a .gitkeep file if needed) ├-theme/ │ │--vendor/ # Commerial plugins zip files (if required by the theme) │ │--languages/ # Leave empty for autogenerated .pot file (create a .gitkeep file if needed) │ │--demo-content/ # Put all demo content manifest and screenshot. The content itself should be autogenerated. │ │ │--example-multipager/ # Local demo content directory, demo files will be generated here │ │ │ │--manifest.php # Demo content name, image, preview link │ │ │ │--screenshot.png # Screenshot │ │ │--example-remote-content/ # Remote demo content directory, downloaded outside of the package │ │ │ │--remote.php # Demo content name, image, preview link (same as manifest.php) │ │ │ │--screenshot.png # Screenshot │ │ │--example-onepager/ │ │ │--...
Basic structure can be downloaded here: Theme boilerplate
In build/build.properties
file set up paths according to your project name and structure. Below, you can find an example
from boilerplate theme with comments:
<!-- Base variables -->
# base directory, path relative to 'build' directory
base.dir = ./..
# project name = project directory = final text domain (no special chars are allowed)
base.projectName = boilerplatetheme
# project plugin slug = plugin directory
base.pluginName = theme-plugin
# project demo plugin slug = demo plugin directory
base.demoPluginName = theme-demo-plugin
# path to theme files
base.html = ${base.dir}/theme
# path to plugin files
base.pluginSrc = ${base.dir}/../../plugins/${base.pluginName}
# destination path to plugin zip
base.pluginDst = ${base.html}/vendor/${base.pluginName}
# path to demo plugin files
base.demoPluginSrc = ${base.dir}/../../plugins/${base.demoPluginName}
# theme demo website (for wp-cli tasks)
base.url = http://boilerplate.themeplayers.net
# theme flavors slugs (for wp-cli tasks)
base.flavors = flavor1, flavor2, flavor3
<!-- SCSS Compiler related -->
# path to compiled main css
base.css.path = assets/css/style.css
# path to main scss
base.scss.path = assets/sass/style.scss
# final css format
build.scss.formatter = compressed
<!-- The path to the publish directory. -->
# publisher's name (no need to change)
build.publishName = themeforest
# directory to hold all packages (no need to change)
build.dir = ${base.dir}/${build.publishName}
# temp directory for packing (no need to change)
build.tmp = ${build.dir}/tmp
# theme package name (no need to change)
build.zipNameFile = ${base.projectName}.zip
# theme package destination path (no need to change)
build.zipName = ${build.tmp}/${build.zipNameFile}
# theme package with promo materials destination path (no need to change)
build.zipNameFull = ${build.dir}/${base.projectName}_all.zip
# packing directory (no need to change)
build.html = ${build.tmp}/${base.projectName}
# theme flavors which will be available as remote demo content (for wp-cli tasks)
build.remotes = flavor1, flavor2
# remote demo content destination directory (for wp-cli tasks)
build.remotesDestination = ${build.dir}/demo-content
<!-- Documentation -->
# path to docs html directory on demo (no need to change)
base.doc = ${base.dir}/../../../documentation
# path to docs pdf inside package (no need to change)
build.doc = ${build.tmp}/Documentation
# slug of the docs file (without an extension)
build.docSlug = boilerplate
# release of the docs file (eg. latest, master)
build.docRelease = latest
# documentation pdf download link
build.docUrlPdf = https://media.readthedocs.org/pdf/${build.docSlug}/${build.docRelease}/${build.docSlug}.pdf
# documentation html download link
build.docUrlHtml = https://media.readthedocs.org/htmlzip/${build.docSlug}/${build.docRelease}/${build.docSlug}.zip
Once properties properly set, build.xml tasks need only little changes. Here are some sections higlighted, and below you can find a whole file example
These are main two task sets. One for creating a package, and another one for updating demo website.
Here, you can add or remove tasks defined below in build.xml
, however the default set up should be enough
<target name="envato"
depends="base.cleanup, base.update, build.delete, build.plugin, build.demoPlugin, build.createDir, build.vctemplates, build.generateDemoContent, build.deleteThumbnails, build.moveRemotes, copy.all, build.removeDemo, build.changeTextDomain, build.pot, build.doc, build.pack, build.cleanup">
<echo message="Envato product version completed."/>
</target>
<target name="demo"
depends="base.update, build.plugin, build.demoPlugin, build.vctemplates">
<echo message="Envato demo completed."/>
</target>
build.scss
task calls ct_fw_ext_sass_compiler_cli_compile_save
function located in demo plugin. Make sure you have
configured SCSS compiler in your project. Or if you don’t use it, remove the task from task sets above.
<target name="build.scss">
<echo>Compiling SCSS to CSS...</echo>
<exec
command="wp eval 'ct_fw_ext_sass_compiler_cli_compile_save();'"
/>
</target>
build.generateDemoContent
task calls ct_fw_ext_backups_do_cli_backup
function located in demo plugin.
The –url parameter needs to point to a particular site (if multisite install) to generate content from, so you will
need to modify the base.flavors variable in build.properties. Read more about WP-CLI: WP-CLI global parameters
Also make sure Demo Plugin settings (demo content directory in particular) are properly set on demo website.
<target name="build.generateDemoContent">
<echo>Generating demo content...</echo>
<exec
command="wp eval --user=1 --url=${base.url} 'fw_ext_ct_demo_content_do_cli_backup();'"
outputProperty="execOutput"
/>
<echo msg="Generated output: ${execOutput}"/>
<foreach list="${base.flavors}" target="build.flavorDemoContent" param="flavorSlug" />
</target>
<target name="build.flavorDemoContent">
<echo msg="Generating demo content for flavor: ${flavorSlug}" />
<exec
command="wp eval --user=1 --url=${base.url}/${flavorSlug} 'fw_ext_ct_demo_content_do_cli_backup();'"
outputProperty="execOutput"
/>
<echo msg="Generated output: ${execOutput}"/>
</target>
<?xml version="1.0"?>
<project name="boilerplate" default="envato">
<import file="lib/build.common.xml"/>
<property file="build.properties"/>
<property name="build.jsPath" value="${build.html}/${base.js.path}"/>
<property name="build.cssPath" value="${build.html}/${base.css.path}"/>
<taskdef name="lineend" classname="lib.converter.ctLineEndingConverter"/>
<taskdef name="jsobfuscate" classname="lib.obfuscator.JsObfuscatorTask"/>
<taskdef name="frameadd" classname="lib.frame.themewoodmen.ctThemeforestThemewoodmenFrame"/>
<taskdef name="switcher" classname="lib.switcher.ctColorSwitcherTask"/>
<target name="envato"
depends="base.cleanup, base.update, build.delete, build.plugin, build.demoPlugin, build.createDir, build.vctemplates, build.generateDemoContent, build.deleteThumbnails, build.moveRemotes, copy.all, build.removeDemo, build.changeTextDomain, build.pot, build.doc, build.pack, build.cleanup">
<echo message="Envato product version completed."/>
</target>
<target name="demo"
depends="base.update, build.plugin, build.demoPlugin, build.vctemplates">
<echo message="Envato demo completed."/>
</target>
<target name="build.plugin">
<echo>git reset --hard</echo>
<exec command="git reset --hard" dir="${base.pluginSrc}"/>
<echo>git pull</echo>
<exec command="git pull" dir="${base.pluginSrc}"/>
<echo>composer update</echo>
<exec command="composer update" dir="${base.pluginSrc}"/>
<delete file="${base.html}/vendor/${base.pluginName}.zip"/>
<delete file="${base.pluginDst}/${base.pluginName}.zip"/>
<delete dir="${base.pluginDst}"/>
<copy todir="${base.pluginDst}/${base.pluginName}">
<fileset dir="${base.pluginSrc}">
<exclude name="**/*.svn/"/>
<exclude name="**/*.git/"/>
<exclude name="**/*.git*"/>
<exclude name="**/*.idea/"/>
<exclude name="**/*.htaccess"/>
<exclude name="**/composer.*"/>
</fileset>
</copy>
<zip destfile="${base.pluginDst}/${base.pluginName}.zip" description="dump zip to tmp">
<fileset dir="${base.pluginDst}"/>
</zip>
<delete dir="${base.pluginDst}/${base.pluginName}"/>
</target>
<target name="build.demoPlugin">
<echo>git reset --hard</echo>
<exec command="git reset --hard" dir="${base.demoPluginSrc}"/>
<echo>git pull</echo>
<exec command="git pull" dir="${base.demoPluginSrc}"/>
</target>
<target name="build.update">
<echo>git pull ${base.dir}</echo>
<exec command="git reset --hard" dir="${base.dir}" checkreturn="true"/>
<exec command="git pull" dir="${base.dir}"/>
</target>
<target name="build.removeDemo">
<reflexive description="Strip demo content if required">
<fileset dir="${build.html}" includes="**/*.php"/>
<filterchain description="cleans demo code">
<replaceregexp>
<regexp pattern="//\s*demo\s*[\s\S]+?//\s*end demo" replace=""/>
</replaceregexp>
</filterchain>
</reflexive>
</target>
<target name="build.changeTextDomain">
<reflexive description="Change text domain to project specific">
<fileset dir="${build.html}" includes="**/*.php"/>
<filterchain description="switches text domain">
<replaceregexp>
<regexp pattern="ct_theme" replace="${base.projectName}"/>
</replaceregexp>
</filterchain>
</reflexive>
</target>
<target name="build.eol">
<lineend path="${build.html}/${base.css.path}/style.css"/>
</target>
<target name="build.scss">
<echo>Compiling SCSS to CSS...</echo>
<exec
command="wp eval 'fw_ext_ct_demo_content_cli_compile_save();'"
outputProperty="execOutput"
/>
<echo msg="Generated output: ${execOutput}"/>
<foreach list="${base.flavors}" target="build.flavorScss" param="flavorSlug" />
</target>
<target name="build.flavorScss">
<echo msg="Compiling SCSS for flavor: ${flavorSlug}" />
<exec
command="wp eval --user=1 --url=${base.url}/${flavorSlug} 'fw_ext_ct_demo_content_cli_compile_save();'"
outputProperty="execOutput"
/>
<echo msg="Generated output: ${execOutput}"/>
</target>
<target name="build.generateDemoContent">
<echo>Generating demo content...</echo>
<exec
command="wp eval --user=1 --url=${base.url} 'fw_ext_ct_demo_content_do_cli_backup();'"
outputProperty="execOutput"
/>
<echo msg="Generated output: ${execOutput}"/>
<foreach list="${base.flavors}" target="build.flavorDemoContent" param="flavorSlug" />
</target>
<target name="build.flavorDemoContent">
<echo msg="Generating demo content for flavor: ${flavorSlug}" />
<exec
command="wp eval --user=1 --url=${base.url}/${flavorSlug} 'fw_ext_ct_demo_content_do_cli_backup();'"
outputProperty="execOutput"
/>
<echo msg="Generated output: ${execOutput}"/>
</target>
<target name="build.moveRemotes">
<echo msg="Moving remotes: ${build.remotes} to destination: ${build.remotesDestination}" />
<foreach list="${build.remotes}" target="build.moveSingleRemote" param="flavorSlug" />
</target>
<target name="build.moveSingleRemote">
<zip destfile="${base.html}/demo-content/${flavorSlug}/${flavorSlug}.zip" description="pack flavor content">
<fileset dir="${base.html}/demo-content/${flavorSlug}"/>
</zip>
<copy todir="${build.remotesDestination}/${flavorSlug}">
<fileset dir="${base.html}/demo-content/${flavorSlug}">
<include name="*.zip" />
<include name="*.php" />
<include name="*.png" />
</fileset>
</copy>
<delete includeemptydirs="true" description="remove remote demo files from theme but leave manifest and screenshot">
<fileset dir="${base.html}/demo-content/${flavorSlug}">
<exclude name="remote.php" />
<exclude name="manifest.php" />
<exclude name="screenshot.*" />
</fileset>
</delete>
</target>
<target name="js.obfuscate">
<jsobfuscate targetdir="${build.html}/${base.js.path}">
<fileset dir="${build.html}/${base.js.path}">
<include name="ct*.js"/>
</fileset>
</jsobfuscate>
</target>
<target name="base.cleanup">
<echo>Deleting vendor zip files...</echo>
<delete>
<fileset dir="${base.html}/vendor">
<include name="*.zip"/> <!-- delete old style vendor files-->
</fileset>
</delete>
<echo>Deleting wrong dir for demo content...</echo>
<delete dir="${base.html}/demo-content/test-dir" />
</target>
<!-- Delete the Publish directory to start from scratch -->
<target name="build.delete">
<echo>build.delete</echo>
<delete file="${build.zipNameFull}"/>
<delete file="${build.dir}/${build.zipNameFile}"/>
<delete dir="${build.tmp}"/>
</target>
<target name="build.cleanup">
<delete dir="${build.tmp}"/>
</target>
<!-- Create the Build Directory -->
<target name="build.createDir">
<mkdir dir="${build.tmp}"/>
</target>
<target name="copy.all">
<!--Main HTML-->
<copy todir="${build.html}">
<fileset dir="${base.html}">
<exclude name="npm/"/>
<exclude name="**/*.svn/"/>
<exclude name="**/*.git/"/>
<exclude name="**/*.git*"/>
<exclude name="**/*.idea/"/>
<exclude name="**/*.htaccess"/>
<exclude name="**/composer.*"/>
</fileset>
</copy>
</target>
<target name="build.pack">
<copy todir="${build.tmp}/packing/${base.projectName}">
<fileset dir="${build.html}"/>
</copy>
<zip destfile="${build.zipName}" description="dump zip to tmp">
<fileset dir="${build.tmp}/packing/"/>
</zip>
<delete dir="${build.tmp}/${base.projectName}" description="remove theme"/>
<delete dir="${build.tmp}/packing" description="remove temp zip dir"/>
<zip destfile="${build.zipNameFull}" description="packs everything (with theme zip)">
<fileset dir="${build.tmp}"/>
</zip>
<copy todir="${build.dir}">
<fileset dir="${build.tmp}">
<include name="${build.zipNameFile}"/>
</fileset>
</copy>
</target>
<target name="build.pot" description="generate po i18n file">
<delete includeemptydirs="false">
<fileset dir="${build.html}/languages">
</fileset>
</delete>
<echo message="php lib/pot/makepot.php wp-theme ${build.html} ${build.html}/languages/${base.projectName}.pot"/>
<exec command="php lib/pot/makepot.php wp-theme ${build.html} ${build.html}/languages/${base.projectName}.pot"
description="generate po file. LANG dir must exist"/>
</target>
<target name="build.vctemplates" description="re generate vc templates for every page">
<echo>Generating VC templates...</echo>
<exec
command="wp eval --user=1 --url=${base.url} 'fw_ext_ct_demo_content_update_vc_templates();'"
/>
<foreach list="${base.flavors}" target="build.flavorVctemplates" param="flavorSlug" />
</target>
<target name="build.flavorVctemplates">
<echo msg="Generating VC templates for flavor: ${flavorSlug}" />
<exec
command="wp eval --user=1 --url=${base.url}/${flavorSlug} 'fw_ext_ct_demo_content_update_vc_templates();'"
/>
</target>
<target name="build.deleteThumbnails" description="delete all custom image sizes in demo content">
<exec
command="find ${base.html}/demo-content -type f -regex '.+-[0-9]+x[0-9]+\.jpg' -o -regex '.+-[0-9]+x[0-9]+\.jpeg' -o -regex '.+-[0-9]+x[0-9]+\.png' -o -regex '.+-[0-9]+x[0-9]+\.gif' | wc -l"
outputProperty="filesToDelete"
/>
<echo msg="Deleting ${filesToDelete} thumbnails..."/>
<exec
command="find ${base.html}/demo-content -type f -regex '.+-[0-9]+x[0-9]+\.jpg' -delete"
/>
<exec
command="find ${base.html}/demo-content -type f -regex '.+-[0-9]+x[0-9]+\.jpeg' -delete"
/>
<exec
command="find ${base.html}/demo-content -type f -regex '.+-[0-9]+x[0-9]+\.png' -delete"
/>
<exec
command="find ${base.html}/demo-content -type f -regex '.+-[0-9]+x[0-9]+\.gif' -delete"
/>
</target>
<target name="build.doc">
<!-- pdf docs for the package -->
<mkdir dir="${build.doc}"/>
<httpget url="${build.docUrlPdf}" dir="${build.doc}" filename="Documentation.pdf"/>
<!-- html docs for the demo -->
<mkdir dir="${base.doc}"/>
<httpget url="${build.docUrlHtml}" dir="${base.doc}" filename="${build.docSlug}-${build.docRelease}.zip"
description="download docs"/>
<unzip todir="${base.doc}" file="${base.doc}/${build.docSlug}-${build.docRelease}.zip"
description="unzip docs"/>
<copy todir="${base.doc}" overwrite="true">
<fileset dir="${base.doc}/${build.docSlug}-${build.docRelease}">
<include name="**/*.*"/>
</fileset>
</copy>
<delete dir="${base.doc}/${build.docSlug}-${build.docRelease}" />
<delete file="${base.doc}/${build.docSlug}-${build.docRelease}.zip" description="deleting doc zip"/>
</target>
</project>
To locally test the package build, download phing tool, and run phing
command in build directory. Some task won’t work here, eg. wp cli based tasks, but the zip file should be built inside themeforest directory. When succeeded, commit and push changes in build.xml. Ask a project manager to update demo website and generate the package.
Note
In order for changes in build.xml to take place you may need to run build twice (build.xml is pulled from git after tasks run init)
If you don’t have it already, create a fresh wordpress install just for testing packages. It can be a single site installation in a subdirectory of your current wordpress.
Download wordpress from wordpress.org/download
Unpack contents to a new subdirectory of your phinky main wordpress directory, eg. phinky.createit/www/ctXX/wp/wptest
Run wordpress install. See screenshot below. Important: select unique table prefix, eg. wptest_
Log in to your new install url: http://ctXX.phinky.createit/wptest/
If everything checks, let know the project manager the package is ready to be uploaded for a review.