├── .DS_Store ├── .babelrc ├── .gitignore ├── .npmignore ├── .timber ├── README.md ├── package.json ├── src ├── build.js ├── createQuery.js ├── createSubclass.js ├── createTemplates.js ├── index.js └── removeTemplates.js └── test └── test.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nclud/wp-timber-cli/32edb79db0c551c2dcf647d189b3d2b7b52cfe0b/.DS_Store -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | src 4 | .timber 5 | -------------------------------------------------------------------------------- /.timber: -------------------------------------------------------------------------------- 1 | { 2 | "page": { 3 | "blog": { 4 | "queries":{ 5 | "news": { 6 | "post_per_page": 10, 7 | "orderby": "title" 8 | }, 9 | "custom-posts": { 10 | "post_per_page": 20, 11 | "orderby": "date" 12 | } 13 | } 14 | }, 15 | "about-us": {} 16 | }, 17 | "archive": { 18 | "events": {} 19 | }, 20 | "single": { 21 | "event": {}, 22 | "news": {} 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ##Requirements 3 | You must be using [Timber](https://github.com/jarednova/timber) for WordPress. 4 | 5 | ##Installation 6 | run `npm install --save wp-timber-cli` inside your root WordPress theme directory. 7 | 8 | ##Usage 9 | Timber CLI will create a WordPress PHP template and corresponding twig template and automatically create some default Timber stuff. 10 | 11 | ###Create Templates 12 | From the command line, run `wp-timber -c ` where type is the type of template (page, single, archive) and name is, you guessed it, the name of the template. 13 | 14 | **Example Output** 15 | 16 | `wp-timber -c page about-us` 17 | 18 | Creates `page-about-us.php` in your theme's root directory, and `/views/pages/page-about-us.twig`. If you don't have a `views` directory it will be created for you. 19 | 20 | Inside the created .php file is a very basic Timber template that renders the corresponding twig template that was also created. 21 | 22 | _page-about-us.php_ 23 | ```php 24 | 32 | ``` 33 | 34 | ###Create Query 35 | You can create a basic WordPress query for an existing page template, or when create a new template using this CLI. 36 | 37 | **Existing Template** 38 | 39 | `wp-timber -q page-about.php custom-post-type` 40 | 41 | **When Create a New Template** 42 | 43 | `wp-timber -c page about -q custom-post-type` 44 | 45 | 46 | **Output** 47 | ```php 48 | "custom-post-type" 52 | ); 53 | 54 | $context = Timber::get_context(); 55 | $post = new TimberPost(); 56 | $context["post"] = $post; 57 | $context["custom_post_types"] = Timber::get_posts($custom_post_types_args); 58 | Timber::render("/views/pages/page-about.twig", $context); 59 | 60 | ?> 61 | ``` 62 | 63 | 64 | ###Remove Templates 65 | 66 | `wp-timber -r page about-us` 67 | 68 | This will find a .php template called `page-about-us.php` in the root theme directory and delete it, as well as the corresponding twig template in `/views/pages/`. 69 | 70 | ###Create Subclasses 71 | 72 | Create a subclass of a built-in Timber class (TimberPost, TimberTerm etc.) in the lib directory by running `wp-timber -s `, where class refers to the class to extend and name is the name assigned to the new subclass. Site, term, post, menu, menuitem, and user are all accepted as arguments for the base class. 73 | 74 | **Output** 75 | 76 | `wp-timber -s post TestPost` 77 | 78 | Creates TestPost.php in the `/lib` directory, with the following boilerplate: 79 | ```php 80 | 87 | ``` 88 | 89 | This will find a .php template called `page-about-us.php` in the root theme directory and delete it, as well as the corresponding twig template in `/views/pages/`. 90 | 91 | ###Build from a Config file 92 | With Timber CLI you can generate a series of templates with queries from a configuration file. Create a `.timber` file that contains JSON to generate as many templates with queries as you want. 93 | 94 | Here's an example config file: 95 | ```JSON 96 | { 97 | "page": { 98 | "blog": { 99 | "queries":{ 100 | "news": { 101 | "post_per_page": 10, 102 | "orderby": "title" 103 | }, 104 | "custom-posts": { 105 | "post_per_page": 20, 106 | "orderby": "date" 107 | } 108 | } 109 | }, 110 | "about-us": {} 111 | }, 112 | "archive": { 113 | "events": {}, 114 | }, 115 | "single": { 116 | "event": {} 117 | } 118 | } 119 | ``` 120 | 121 | Running `wp-timber build` will generate the following PHP/twig templates: 122 | * `page-blog.php` with two queries: one for 'news' post type and one for 'custom-posts' **and** `views/pages/page-blog.twig` file 123 | * `page-about-us.php` **and** `views/pages/page-about-us.twig` 124 | * `archive-events.php` **and** `views/archives/archive-events.twig` 125 | * `single-event.php` **and** `views/singles/single-event.twig` 126 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wp-timber-cli", 3 | "version": "0.4.1", 4 | "description": "CLI for wordpress and Timber-WP with Twig", 5 | "files": [ 6 | "lib" 7 | ], 8 | "main": "./lib/index.js", 9 | "bin": { 10 | "wp-timber": "./lib/index.js" 11 | }, 12 | "scripts": { 13 | "test": "mocha ./test/test.js", 14 | "build": "rimraf lib && babel src -d lib" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/nclud/wp-timber-cli" 19 | }, 20 | "keywords": [ 21 | "wordpress", 22 | "twig", 23 | "timber" 24 | ], 25 | "author": "nlcud (http://nclud.com)", 26 | "contributors": [ 27 | "Ramsay Lanier (http://ramsaylanier.com)", 28 | "Zakk Fleischmann (http://zakkman.github.io)" 29 | ], 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/nclud/wp-timber-cli/issues" 33 | }, 34 | "homepage": "https://github.com/nclud/wp-timber-cli#readme", 35 | "dependencies": { 36 | "cli": "^0.11.1", 37 | "mkdirp": "^0.5.1", 38 | "rimraf": "^2.5.1" 39 | }, 40 | "devDependencies": { 41 | "babel-cli": "^6.5.1", 42 | "babel-preset-es2015": "^6.5.0", 43 | "babel-preset-stage-0": "^6.5.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/build.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import cli from 'cli'; 4 | import fs from 'fs'; 5 | import mkdirp from 'mkdirp'; 6 | 7 | import createTemplates from './createTemplates.js' 8 | import createQuery from './createQuery.js'; 9 | import createSubclass from './createSubclass.js'; 10 | 11 | const buildTemplatesFromConfig = function(){ 12 | fs.readFile('./.timber', 'utf8', function(err, res){ 13 | if (err){ 14 | console.log(err) 15 | } else { 16 | console.log('Building...'); 17 | parseFile(res) 18 | } 19 | }) 20 | 21 | function parseFile(file){ 22 | const Types=JSON.parse(file); 23 | 24 | Object.keys(Types).map( type => { 25 | const BuildType = Types[type]; 26 | Object.keys(BuildType).map( name => { 27 | const args = [type, name] 28 | createTemplates(args); 29 | 30 | const Queries = BuildType[name].queries; 31 | if (Queries){ 32 | Object.keys(Queries).map( (query, index) => { 33 | setTimeout(function(){ 34 | const queryArgs = [type, name, query, Queries[query]]; 35 | createQuery(queryArgs, true); 36 | }, 10 * (index + 1)); 37 | }); 38 | } 39 | }) 40 | }) 41 | } 42 | } 43 | 44 | export default buildTemplatesFromConfig; 45 | -------------------------------------------------------------------------------- /src/createQuery.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | 3 | const createQuery = function(args, create){ 4 | let type, name, postType, queryOptions, file; 5 | 6 | if (create){ 7 | type = args[0]; 8 | name = args[1]; 9 | postType = args[2]; 10 | queryOptions = args[3]; 11 | file = './' + type + '-' + name + '.php'; 12 | } else { 13 | file = args[0]; 14 | postType = args[1]; 15 | } 16 | 17 | const postTypeUnderscore = postType.replace(/-/g, '_'); 18 | 19 | fs.readFile(file, 'utf8', function(err, data){ 20 | if (err){ 21 | console.log(err) 22 | } else { 23 | checkTemplateForExistingQuery(data); 24 | } 25 | }) 26 | 27 | function checkTemplateForExistingQuery(data){ 28 | 29 | const existingQuery = '$' + postTypeUnderscore + '_args'; 30 | 31 | if (data.indexOf(existingQuery) == -1){ 32 | writeQuery(data) 33 | } else { 34 | console.log('That query already exists') 35 | } 36 | } 37 | 38 | function writeQueryOptions(options){ 39 | let optionsString = ''; 40 | Object.keys(options).map( option => { 41 | const value = options[option]; 42 | optionsString += ' "' + option + '"\t\t\t=> "' + value + '",\n '; 43 | }) 44 | 45 | return optionsString; 46 | } 47 | 48 | function writeQuery(data){ 49 | const queryOptionsText = queryOptions ? writeQueryOptions(queryOptions) : ''; 50 | const queryText = '$' + postTypeUnderscore + '_args = array( \n '+ 51 | ' "post_type"\t\t\t=> "' + postType + '",\n ' + 52 | queryOptionsText + 53 | ');'; 54 | const query = data.replace(/(<\?php)/, " { 5 | const type = args[0]; 6 | const name = args[1]; 7 | 8 | if (selectClass(type)) { 9 | mkdirp.sync( './lib'); 10 | fs.writeFileSync('./lib/' + name + '.php', buildPHPTemplate(type, name)); 11 | console.log('Subclass Created!'); 12 | } else { 13 | console.log('Please use a valid base class (post, term, menu, menuitem, user)'); 14 | } 15 | 16 | } 17 | 18 | function buildPHPTemplate(type, name){ 19 | var baseClass = selectClass(type); 20 | 21 | return '' 27 | } 28 | 29 | function selectClass(type){ 30 | var classes = { 31 | site : 'TimberSite', 32 | post : 'TimberPost', 33 | term : 'TimberTerm', 34 | menu : 'TimberMenu', 35 | menuitem : 'TimberMenuItem', 36 | user : 'TimberUser' 37 | } 38 | if (classes[type]) { 39 | return classes[type]; 40 | } else { 41 | return false; 42 | } 43 | } 44 | 45 | export default createSubclass; -------------------------------------------------------------------------------- /src/createTemplates.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import mkdirp from 'mkdirp'; 3 | 4 | const createTemplates = args => { 5 | const type = args[0]; 6 | const name = args[1]; 7 | 8 | fs.writeFileSync(type + '-' + name + '.php', buildPHPTemplate(type, name)); 9 | mkdirp.sync( './views/' + type + 's'); 10 | fs.writeFileSync('./views/' + type + 's/' + type + '-' + name + '.twig'); 11 | 12 | console.log('Template Created!'); 13 | 14 | } 15 | 16 | function buildPHPTemplate(type, name){ 17 | return '' 25 | } 26 | 27 | export default createTemplates; 28 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import cli from 'cli'; 4 | import fs from 'fs'; 5 | import mkdirp from 'mkdirp'; 6 | 7 | 8 | import createTemplates from './createTemplates.js' 9 | import deleteTemplates from './removeTemplates.js'; 10 | import createQuery from './createQuery.js'; 11 | import createSubclass from './createSubclass.js'; 12 | import buildTemplatesFromConfig from './build.js'; 13 | 14 | 15 | cli.parse({ 16 | create: ['c', 'Create A Template'], 17 | remove: ['r', 'Remove A Template'], 18 | query: ['q', 'Add Query to Template'], 19 | subclass: ['s', 'Add An Object Subclass'], 20 | help: ['h', 'HALP'] 21 | }); 22 | 23 | 24 | cli.main(function(args, options){ 25 | 26 | console.log('args: ', args); 27 | console.log('options: ', options); 28 | 29 | 30 | const { create, remove, query, help, init, subclass } = options; 31 | 32 | if (args[0] == 'build'){ 33 | buildTemplatesFromConfig() 34 | } else { 35 | if (create){ 36 | createTemplates(args); 37 | } 38 | 39 | if (remove){ 40 | deleteTemplates(args); 41 | } 42 | 43 | if (query){ 44 | createQuery(args, create); 45 | } 46 | 47 | if (help){ 48 | help(); 49 | } 50 | 51 | if (init){ 52 | init(); 53 | } 54 | 55 | if (subclass) { 56 | createSubclass(args); 57 | } 58 | } 59 | 60 | }); 61 | 62 | function help(){ 63 | console.log('HALP'); 64 | return false; 65 | } 66 | -------------------------------------------------------------------------------- /src/removeTemplates.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | 3 | const removeTemplates = function(args){ 4 | const type = args[0]; 5 | const name = args[1]; 6 | 7 | fs.unlink('./' + type + '-' + name + '.php', function(err){ 8 | if (err){ 9 | console.log(err); 10 | } else { 11 | console.log('PHP Template Removed') 12 | } 13 | }); 14 | fs.unlink('./views/' + type + 's/' + type + '-' + name + '.twig', function(err){ 15 | if (err){ 16 | console.log(err); 17 | } else { 18 | console.log('Twig Template Removed') 19 | } 20 | }); 21 | } 22 | 23 | export default removeTemplates 24 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var fs = require('fs'); 3 | var rimraf = require('rimraf'); 4 | var createTemplates = require('../lib/createTemplates.js'); 5 | var deleteTemplates = require('../lib/removeTemplates.js'); 6 | var createSubclass = require('../lib/createSubclass.js'); 7 | 8 | function cleanUp(){ 9 | rimraf.sync('./views'); 10 | } 11 | 12 | describe('createTemplates', function() { 13 | it ('should create a PHP and Twig template', function(done){ 14 | 15 | console.log(createTemplates); 16 | 17 | var args = ['page', 'test']; 18 | var type = args[0]; 19 | var name = args[1]; 20 | 21 | createTemplates.default(args); 22 | 23 | if (fs.existsSync('./' + type + '-' + name + '.php')){ 24 | console.log('php template exists'); 25 | if (fs.existsSync('./views/' + type + 's/' + type + '-' + name + '.twig')){ 26 | console.log('twig template exists'); 27 | cleanUp(); 28 | return done() 29 | } else { 30 | throw new Error('Twig template not created') 31 | } 32 | } else { 33 | cleanUp(); 34 | throw new Error('PHP template not created') 35 | } 36 | }); 37 | }); 38 | 39 | describe('createSubclass', function() { 40 | it ('should create a subclass of TimberPost', function(done){ 41 | 42 | var args = ['post', 'TestPost']; 43 | var type = args[0]; 44 | var name = args[1]; 45 | 46 | createSubclass.default(args); 47 | 48 | if (fs.existsSync('./lib/' + name + '.php')){ 49 | console.log('subclass exists'); 50 | cleanUp(); 51 | return done(); 52 | } else { 53 | cleanUp(); 54 | throw new Error('Subclass not created') 55 | } 56 | }); 57 | }); 58 | --------------------------------------------------------------------------------