Merge sage-9 into master

This commit is contained in:
QWp6t
2016-08-29 19:18:51 -07:00
77 changed files with 1775 additions and 1232 deletions

View File

@@ -1,3 +0,0 @@
{
"directory": "bower_components"
}

View File

@@ -9,3 +9,9 @@ end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.php]
indent_size = 4
[templates/**.php]
indent_size = 2

17
.eslintrc Normal file
View File

@@ -0,0 +1,17 @@
{
"root": true,
"extends": "eslint:recommended",
"globals": {
"wp": true
},
"env": {
"browser": true,
"jquery": true,
"node": true,
"amd": true
},
"parser": "babel-eslint",
"rules": {
"no-console": 0
}
}

3
.gitattributes vendored Normal file
View File

@@ -0,0 +1,3 @@
/.github export-ignore
/.gitattributes export-ignore
/.travis.yml export-ignore

95
.jscsrc
View File

@@ -1,95 +0,0 @@
{
"requireCurlyBraces": [
"if",
"else",
"for",
"while",
"do",
"try",
"catch"
],
"requireOperatorBeforeLineBreak": true,
"requireCamelCaseOrUpperCaseIdentifiers": true,
"maximumLineLength": {
"value": 80,
"allowComments": true,
"allowRegex": true
},
"validateIndentation": 2,
"validateQuoteMarks": "'",
"disallowMultipleLineStrings": true,
"disallowMixedSpacesAndTabs": true,
"disallowTrailingWhitespace": true,
"disallowSpaceAfterPrefixUnaryOperators": true,
"disallowMultipleVarDecl": true,
"disallowKeywordsOnNewLine": [
"else"
],
"requireSpaceAfterKeywords": [
"if",
"else",
"for",
"while",
"do",
"switch",
"return",
"try",
"catch"
],
"requireSpaceBeforeBinaryOperators": [
"=",
"+=",
"-=",
"*=",
"/=",
"%=",
"<<=",
">>=",
">>>=",
"&=",
"|=",
"^=",
"+=",
"+",
"-",
"*",
"/",
"%",
"<<",
">>",
">>>",
"&",
"|",
"^",
"&&",
"||",
"===",
"==",
">=",
"<=",
"<",
">",
"!=",
"!=="
],
"requireSpaceAfterBinaryOperators": true,
"requireSpacesInConditionalExpression": true,
"requireSpaceBeforeBlockStatements": true,
"requireSpacesInForStatement": true,
"requireLineFeedAtFileEnd": true,
"requireSpacesInFunctionExpression": {
"beforeOpeningCurlyBrace": true
},
"disallowSpacesInAnonymousFunctionExpression": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInsideObjectBrackets": "all",
"disallowSpacesInsideArrayBrackets": "all",
"disallowSpacesInsideParentheses": true,
"jsDoc": {
"checkParamNames": true,
"requireParamTypes": true
},
"disallowMultipleLineBreaks": true,
"disallowNewlineBeforeBlockStatements": true
}

View File

@@ -1,15 +0,0 @@
{
"bitwise": true,
"browser": true,
"curly": true,
"eqeqeq": true,
"eqnull": true,
"esnext": true,
"immed": true,
"jquery": true,
"latedef": true,
"newcap": true,
"noarg": true,
"node": true,
"strict": false
}

View File

@@ -1,31 +1,47 @@
sudo: false
language: php
php:
- nightly
- 7.0
- 5.6
- 5.5
- 5.4
- hhvm
- nightly
env:
- TRAVIS_NODE_VERSION="4.2" CXX="g++-4.8"
- TRAVIS_NODE_VERSION="5.3" CXX="g++-4.8"
matrix:
fast_finish: true
allow_failures:
- php: nightly
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
cache:
apt: true
directories:
- bower_components
- $HOME/.composer/cache
- node_modules
- vendor
before_install:
- composer self-update
install:
- npm install -g npm@latest
- npm install -g bower gulp jscs
- npm install
- composer self-update && composer --version
- export PATH="$HOME/.composer/vendor/bin:$PATH"
- composer global require squizlabs/php_codesniffer
- source ~/.nvm/nvm.sh && nvm install $TRAVIS_NODE_VERSION
- travis_retry npm install -g npm@latest
- travis_retry npm install -g eslint
- node -v && npm -v
- npm rebuild
- travis_retry npm install
- npm prune
- composer install -o --prefer-dist --no-interaction
script:
- npm run build
- npm run jshint
- npm run jscs
- phpcs --standard=ruleset.xml --extensions=php -n -s .
- composer test

137
README.md
View File

@@ -2,121 +2,118 @@
[![Build Status](https://travis-ci.org/roots/sage.svg)](https://travis-ci.org/roots/sage)
[![devDependency Status](https://david-dm.org/roots/sage/dev-status.svg)](https://david-dm.org/roots/sage#info=devDependencies)
Sage is a WordPress starter theme based on HTML5 Boilerplate, gulp, Bower, and Bootstrap Sass, that will help you make better themes.
Sage is a WordPress starter theme with a modern development workflow.
* Source: [https://github.com/roots/sage](https://github.com/roots/sage)
* Homepage: [https://roots.io/sage/](https://roots.io/sage/)
* Documentation: [https://roots.io/sage/docs/](https://roots.io/sage/docs/)
* Twitter: [@rootswp](https://twitter.com/rootswp)
* Newsletter: [Subscribe](http://roots.io/subscribe/)
* Forum: [https://discourse.roots.io/](https://discourse.roots.io/)
## Requirements
| Prerequisite | How to check | How to install
| --------------- | ------------ | ------------- |
| PHP >= 5.4.x | `php -v` | [php.net](http://php.net/manual/en/install.php) |
| Node.js 0.12.x | `node -v` | [nodejs.org](http://nodejs.org/) |
| gulp >= 3.8.10 | `gulp -v` | `npm install -g gulp` |
| Bower >= 1.3.12 | `bower -v` | `npm install -g bower` |
For more installation notes, refer to the [Install gulp and Bower](#install-gulp-and-bower) section in this document.
Write stylesheets with Sass, automatically check your JavaScript for errors, optimize images, enable synchronized browser testing, and more.
## Features
* [gulp](http://gulpjs.com/) build script that compiles both Sass and Less, checks for JavaScript errors, optimizes images, and concatenates and minifies files
* [Webpack](https://webpack.github.io/) is used as a build tool for compiling stylesheets, checking for JavaScript errors, optimizing images, and concatenating and minifying files
* [BrowserSync](http://www.browsersync.io/) for keeping multiple browsers and devices synchronized while testing, along with injecting updated CSS and JS into your browser while you're developing
* [Bower](http://bower.io/) for front-end package management
* [asset-builder](https://github.com/austinpray/asset-builder) for the JSON file based asset pipeline
* [Bootstrap](http://getbootstrap.com/)
* [Theme wrapper](https://roots.io/sage/docs/theme-wrapper/)
* Template inheritance with the [theme wrapper](https://roots.io/sage/docs/theme-wrapper/)
* ARIA roles and microformats
* Posts use the [hNews](http://microformats.org/wiki/hnews) microformat
* [Multilingual ready](https://roots.io/wpml/) and over 30 available [community translations](https://github.com/roots/sage-translations)
Install the [Soil](https://github.com/roots/soil) plugin to enable additional features:
Install the [Soil](https://roots.io/plugins/soil/) plugin to enable additional recommended features:
* Cleaner output of `wp_head` and enqueued assets
* Load jQuery from the jQuery CDN
* Cleaner WordPress markup
* Cleaner HTML output of navigation menus
* Root relative URLs
* Nice search (`/search/query/`)
* Google CDN jQuery snippet from [HTML5 Boilerplate](http://html5boilerplate.com/)
* Nice search
* Google Analytics snippet from [HTML5 Boilerplate](http://html5boilerplate.com/)
* Move all JS to the footer
* Disable trackbacks and pingbacks
See a complete working example in the [roots-example-project.com repo](https://github.com/roots/roots-example-project.com).
## Requirements
Make sure all dependencies have been installed before moving on:
* [PHP](http://php.net/manual/en/install.php) >= 5.5.x
* [Composer](https://getcomposer.org/download/)
* [Node.js](http://nodejs.org/) >= 0.12.x
## Theme installation
Bottom line is you want to get the files in this repo into your local development environment. There are many ways to do this, two of which we will cover here.
From the command line, run the following commands from the root of your WordPress site (where `composer.json` exists). These instructions assume you're using a [Bedrock](https://roots.io/bedrock/)-based WordPress setup. If you're using Vagrant, make sure to run these commands from the Vagrant box (`vagrant ssh`). Create a new theme based on Sage by using Composer's [`create-project`](https://getcomposer.org/doc/03-cli.md#create-project):
### via Command-line
If you're already [using Composer to manage WordPress](https://roots.io/using-composer-with-wordpress/), then you might consider using composer's `create-project` command to download Sage.
The example below assumes you're using Bedrock. If you're not, simply change the target path accordingly.
```sh
composer create-project roots/sage web/app/themes/your-theme-name-here
```shell
# @ example.com/site
$ composer create-project roots/sage web/app/themes/your-theme-name dev-sage-9
```
Then activate the theme via [wp-cli](http://wp-cli.org/commands/theme/activate/).
Then activate the theme via [wp-cli](http://wp-cli.org/commands/theme/activate/):
```sh
wp theme activate your-theme-name-here
```shell
# @ example.com/site
$ wp theme activate your-theme-name
```
### via WordPress Admin Panel
## Theme structure
1. [Download the latest release](https://github.com/roots/sage/releases/latest) of Sage.
2. In your WordPress admin panel, navigate to Appearance->Themes
3. Click Add New
4. Click Upload Theme
5. Upload the zip file that you downloaded.
```shell
themes/theme-name/ # → Root of your Sage based theme
├── assets # → Front-end assets
│   ├── config.json # → Settings for compiled assets
│   ├── fonts/ # → Theme fonts
│   ├── images/ # → Theme images
│   ├── scripts/ # → Theme JS
│   └── styles/ # → Theme stylesheets
├── composer.json # → Autoloading for `src/` files
├── composer.lock # → Composer lock file (never manually edit)
├── dist/ # → Built theme assets (never manually edit)
├── functions.php # → Never manually edit
├── index.php # → Never manually edit
├── node_modules/ # → Node.js packages (never manually edit)
├── package.json # → Node.js dependencies and scripts
├── screenshot.png # → Theme screenshot for WP admin
├── src/ # → Theme PHP
├── style.css # → Theme meta information
├── templates/ # → Theme templates
│   ├── layouts/ # → Base templates
│   └── partials/ # → Partial templates
├── vendor/ # → Composer packages (never manually edit)
├── watch.js # → Webpack/BrowserSync watch config
└── webpack.config.js # → Webpack config
```
## Theme setup
Edit `lib/setup.php` to enable or disable theme features, setup navigation menus, post thumbnail sizes, post formats, and sidebars.
Edit `src/lib/setup.php` to enable or disable theme features, setup navigation menus, post thumbnail sizes, post formats, and sidebars.
## Theme development
Sage uses [gulp](http://gulpjs.com/) as its build system and [Bower](http://bower.io/) to manage front-end packages.
Sage uses [Webpack](https://webpack.github.io/) as a build tool and [npm](https://www.npmjs.com/) to manage front-end packages.
### Install gulp and Bower
### Install dependencies
Building the theme requires [node.js](http://nodejs.org/download/). We recommend you update to the latest version of npm: `npm install -g npm@latest`.
From the command line on your host machine (not on your Vagrant development box), navigate to the theme directory then run `npm install`:
From the command line:
1. Install [gulp](http://gulpjs.com) and [Bower](http://bower.io/) globally with `npm install -g gulp bower`
2. Navigate to the theme directory, then run `npm install`
3. Run `bower install`
```shell
# @ example.com/site/web/app/themes/your-theme-name
$ npm install
```
You now have all the necessary dependencies to run the build process.
### Available gulp commands
### Available build commands
* `gulp` — Compile and optimize the files in your assets directory
* `gulp watch` — Compile assets when file changes are made
* `gulp --production` — Compile assets for production (no source maps).
* `npm run build` — Compile and optimize the files in your assets directory
* `npm run watch` — Compile assets when file changes are made, start BrowerSync session
* `npm run build:production` — Compile assets for production
### Using BrowserSync
To use BrowserSync during `gulp watch` you need to update `devUrl` at the bottom of `assets/manifest.json` to reflect your local development hostname.
To use BrowserSync during `npm watch` you need to update `devUrl` at the bottom of `assets/config.json` to reflect your local development hostname.
For example, if your local development URL is `http://project-name.dev` you would update the file to read:
For example, if your local development URL is `https://project-name.dev` you would update the file to read:
```json
...
"config": {
"devUrl": "http://project-name.dev"
}
...
```
If your local development URL looks like `http://localhost:8888/project-name/` you would update the file to read:
```json
...
"config": {
"devUrl": "http://localhost:8888/project-name/"
}
"devUrl": "https://project-name.dev",
...
```

14
assets/config.json Normal file
View File

@@ -0,0 +1,14 @@
{
"entry": {
"main": [
"./scripts/util/public-path.js",
"./scripts/main.js",
"./styles/main.scss"
],
"customizer": [
"./scripts/customizer.js"
]
},
"publicPath": "/app/themes/sage",
"devUrl": "http://example.dev"
}

View File

@@ -1,27 +0,0 @@
{
"dependencies": {
"main.js": {
"files": [
"scripts/main.js"
],
"main": true
},
"main.css": {
"files": [
"styles/main.scss"
],
"main": true
},
"customizer.js": {
"files": [
"scripts/customizer.js"
]
},
"jquery.js": {
"bower": ["jquery"]
}
},
"config": {
"devUrl": "http://example.dev"
}
}

View File

@@ -1,8 +1,5 @@
(function($) {
// Site title
wp.customize('blogname', function(value) {
value.bind(function(to) {
$('.brand').text(to);
});
});
})(jQuery);
import $ from 'jquery';
wp.customize('blogname', (value) => {
value.bind((to) => $('.brand').text(to))
});

View File

@@ -1,77 +1,23 @@
/* ========================================================================
* DOM-based Routing
* Based on http://goo.gl/EUTi53 by Paul Irish
*
* Only fires on body classes that match. If a body class contains a dash,
* replace the dash with an underscore when adding it to the object below.
*
* .noConflict()
* The routing is enclosed within an anonymous function so that you can
* always reference jQuery with $, even when in .noConflict() mode.
* ======================================================================== */
// import external dependencies
import 'jquery'
import 'bootstrap/dist/js/bootstrap'
(function($) {
// import local dependencies
import Router from './util/router';
import common from './routes/Common';
import home from './routes/Home';
import about_us from './routes/About';
// Use this variable to set up the common and page specific functions. If you
// rename this variable, you will also need to rename the namespace below.
var Sage = {
// All pages
'common': {
init: function() {
// JavaScript to be fired on all pages
},
finalize: function() {
// JavaScript to be fired on all pages, after page specific JS is fired
}
},
// Home page
'home': {
init: function() {
// JavaScript to be fired on the home page
},
finalize: function() {
// JavaScript to be fired on the home page, after the init JS
}
},
// About us page, note the change from about-us to about_us.
'about_us': {
init: function() {
// JavaScript to be fired on the about us page
}
}
};
// Use this variable to set up the common and page specific functions. If you
// rename this variable, you will also need to rename the namespace below.
const routes = {
// All pages
common,
// Home page
home,
// About us page, note the change from about-us to about_us.
about_us
};
// The routing fires all common scripts, followed by the page specific scripts.
// Add additional events for more control over timing e.g. a finalize event
var UTIL = {
fire: function(func, funcname, args) {
var fire;
var namespace = Sage;
funcname = (funcname === undefined) ? 'init' : funcname;
fire = func !== '';
fire = fire && namespace[func];
fire = fire && typeof namespace[func][funcname] === 'function';
if (fire) {
namespace[func][funcname](args);
}
},
loadEvents: function() {
// Fire common init JS
UTIL.fire('common');
// Fire page-specific init JS, and then finalize JS
$.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
UTIL.fire(classnm);
UTIL.fire(classnm, 'finalize');
});
// Fire common finalize JS
UTIL.fire('common', 'finalize');
}
};
// Load Events
$(document).ready(UTIL.loadEvents);
})(jQuery); // Fully reference jQuery after this point.
// Load Events
$(document).ready(() => new Router(routes).loadEvents());

View File

@@ -0,0 +1,5 @@
export default {
init() {
// JavaScript to be fired on the about us page
}
};

View File

@@ -0,0 +1,8 @@
export default {
init() {
// JavaScript to be fired on all pages
},
finalize() {
// JavaScript to be fired on all pages, after page specific JS is fired
}
};

View File

@@ -0,0 +1,8 @@
export default {
init() {
// JavaScript to be fired on the home page
},
finalize() {
// JavaScript to be fired on the home page, after the init JS
}
};

View File

@@ -0,0 +1,8 @@
/* globals WEBPACK_PUBLIC_PATH */
// Dynamically set absolute public path from current protocol and host
if (WEBPACK_PUBLIC_PATH !== false) {
/* eslint-disable no-undef */
__webpack_public_path__ = location.protocol + '//' + location.host + WEBPACK_PUBLIC_PATH;
/*eslint-enable no-undef*/
}

View File

@@ -0,0 +1,36 @@
/* ========================================================================
* DOM-based Routing
* Based on http://goo.gl/EUTi53 by Paul Irish
*
* Only fires on body classes that match. If a body class contains a dash,
* replace the dash with an underscore when adding it to the object below.
* ======================================================================== */
// The routing fires all common scripts, followed by the page specific scripts.
// Add additional events for more control over timing e.g. a finalize event
export default class Router {
constructor(routes) {
this.routes = routes;
}
fire(route, fn = 'init', args) {
const fire = route !== '' && this.routes[route] && typeof this.routes[route][fn] === 'function';
if (fire) {
this.routes[route][fn](args);
}
}
loadEvents() {
// Fire common init JS
this.fire('common');
// Fire page-specific init JS, and then finalize JS
document.body.className.replace(/-/g, '_').split(/\s+/).forEach((className) => {
this.fire(className);
this.fire(className, 'finalize');
});
// Fire common finalize JS
this.fire('common', 'finalize');
}
}

View File

@@ -1,9 +1,10 @@
// Glyphicons font path
$icon-font-path: "../fonts/";
// Grid settings
$enable-flex: true;
$main-sm-columns: 12;
$sidebar-sm-columns: 4;
// Colors
$brand-primary: #27ae60;
// Font Awesome | see: http://fontawesome.io/get-started/
$fa-font-path: '~font-awesome/fonts';

View File

@@ -1,5 +1,5 @@
.comment-list {
@include list-unstyled;
@extend .list-unstyled;
}
.comment-list ol {
list-style: none;
@@ -15,5 +15,5 @@
}
.comment-form input[type="submit"] {
@extend .btn;
@extend .btn-primary;
@extend .btn-secondary;
}

View File

@@ -11,5 +11,5 @@
}
.search-form .search-submit {
@extend .btn;
@extend .btn-default;
@extend .btn-secondary;
}

View File

@@ -1,10 +1,16 @@
// Grid system
.main {
@include make-sm-column($main-sm-columns);
.sidebar-primary & {
@include make-sm-column($main-sm-columns - $sidebar-sm-columns);
@extend %grid-column;
@include media-breakpoint-up(sm) {
@include make-col($main-sm-columns);
.sidebar-primary & {
@include make-col($main-sm-columns - $sidebar-sm-columns);
}
}
}
.sidebar {
@include make-sm-column($sidebar-sm-columns);
@extend %grid-column;
@include media-breakpoint-up(sm) {
@include make-col($sidebar-sm-columns);
}
}

View File

@@ -10,32 +10,33 @@
}
.aligncenter {
display: block;
margin: ($line-height-computed / 2) auto;
margin: ($spacer / 2) auto;
height: auto;
}
.alignleft,
.alignright {
margin-bottom: ($line-height-computed / 2);
margin-bottom: ($spacer / 2);
height: auto;
}
@media (min-width: $screen-sm-min) {
@include media-breakpoint-up(sm) {
// Only float if not on an extra small device
.alignleft {
float: left;
margin-right: ($line-height-computed / 2);
margin-right: ($spacer / 2);
}
.alignright {
float: right;
margin-left: ($line-height-computed / 2);
margin-left: ($spacer / 2);
}
}
// Captions
.wp-caption {
@extend .thumbnail;
@extend .figure-img;
@extend .img-fluid;
}
.wp-caption-text {
padding: $thumbnail-caption-padding;
@extend .figure-caption;
}
// Text meant only for screen readers

View File

@@ -0,0 +1,6 @@
.banner .nav li {
@extend .nav-item;
}
.banner .nav a {
@extend .nav-link;
}

View File

@@ -1,9 +1,8 @@
@import "common/variables";
// Automatically injected Bower dependencies via wiredep (never manually edit this block)
// bower:scss
@import "../../bower_components/bootstrap-sass/assets/stylesheets/_bootstrap.scss";
// endbower
// Import npm dependencies
@import "~bootstrap/scss/bootstrap";
@import "~font-awesome/scss/font-awesome";
@import "common/global";
@import "components/buttons";

View File

@@ -1,36 +0,0 @@
{
"name": "sage",
"homepage": "https://roots.io/sage/",
"authors": [
"Ben Word <ben@benword.com>"
],
"license": "MIT",
"private": true,
"dependencies": {
"bootstrap-sass": "3.3.6"
},
"overrides": {
"bootstrap-sass": {
"main": [
"./assets/stylesheets/_bootstrap.scss",
"./assets/javascripts/bootstrap/transition.js",
"./assets/javascripts/bootstrap/alert.js",
"./assets/javascripts/bootstrap/button.js",
"./assets/javascripts/bootstrap/carousel.js",
"./assets/javascripts/bootstrap/collapse.js",
"./assets/javascripts/bootstrap/dropdown.js",
"./assets/javascripts/bootstrap/modal.js",
"./assets/javascripts/bootstrap/tooltip.js",
"./assets/javascripts/bootstrap/popover.js",
"./assets/javascripts/bootstrap/scrollspy.js",
"./assets/javascripts/bootstrap/tab.js",
"./assets/javascripts/bootstrap/affix.js",
"./assets/fonts/bootstrap/glyphicons-halflings-regular.eot",
"./assets/fonts/bootstrap/glyphicons-halflings-regular.svg",
"./assets/fonts/bootstrap/glyphicons-halflings-regular.ttf",
"./assets/fonts/bootstrap/glyphicons-halflings-regular.woff",
"./assets/fonts/bootstrap/glyphicons-halflings-regular.woff2"
]
}
}
}

View File

@@ -23,8 +23,23 @@
"issues": "https://github.com/roots/sage/issues",
"forum": "https://discourse.roots.io/"
},
"autoload": {
"psr-4": {
"Roots\\Sage\\": "src/lib/Sage/"
}
},
"require": {
"php": ">=5.4.0",
"php": ">=5.5.0",
"composer/installers": "~1.0"
},
"require-dev": {
"squizlabs/php_codesniffer": "^2.5.1",
"phpmd/phpmd": "^2.4.2"
},
"scripts": {
"test": [
"vendor/bin/phpcs",
"vendor/bin/phpmd src text cleancode,codesize,controversial,design,naming,unusedcode"
]
}
}
}

463
composer.lock generated Normal file
View File

@@ -0,0 +1,463 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "5f4d419852a5551e2b54ef851cab83b4",
"content-hash": "1ee82adf8a4565a48214e5686e6b3293",
"packages": [
{
"name": "composer/installers",
"version": "v1.0.23",
"source": {
"type": "git",
"url": "https://github.com/composer/installers.git",
"reference": "6213d900e92647831f7a406d5c530ea1f3d4360e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/installers/zipball/6213d900e92647831f7a406d5c530ea1f3d4360e",
"reference": "6213d900e92647831f7a406d5c530ea1f3d4360e",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0"
},
"replace": {
"roundcube/plugin-installer": "*",
"shama/baton": "*"
},
"require-dev": {
"composer/composer": "1.0.*@dev",
"phpunit/phpunit": "4.1.*"
},
"type": "composer-plugin",
"extra": {
"class": "Composer\\Installers\\Plugin",
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-0": {
"Composer\\Installers\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kyle Robinson Young",
"email": "kyle@dontkry.com",
"homepage": "https://github.com/shama"
}
],
"description": "A multi-framework Composer library installer",
"homepage": "http://composer.github.com/installers/",
"keywords": [
"Craft",
"Dolibarr",
"Hurad",
"MODX Evo",
"OXID",
"SMF",
"Thelia",
"WolfCMS",
"agl",
"aimeos",
"annotatecms",
"bitrix",
"cakephp",
"chef",
"codeigniter",
"concrete5",
"croogo",
"dokuwiki",
"drupal",
"elgg",
"fuelphp",
"grav",
"installer",
"joomla",
"kohana",
"laravel",
"lithium",
"magento",
"mako",
"mediawiki",
"modulework",
"moodle",
"phpbb",
"piwik",
"ppi",
"puppet",
"roundcube",
"shopware",
"silverstripe",
"symfony",
"typo3",
"wordpress",
"zend",
"zikula"
],
"time": "2016-01-27 12:54:22"
}
],
"packages-dev": [
{
"name": "pdepend/pdepend",
"version": "2.2.4",
"source": {
"type": "git",
"url": "https://github.com/pdepend/pdepend.git",
"reference": "b086687f3a01dc6bb92d633aef071d2c5dd0db06"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/b086687f3a01dc6bb92d633aef071d2c5dd0db06",
"reference": "b086687f3a01dc6bb92d633aef071d2c5dd0db06",
"shasum": ""
},
"require": {
"php": ">=5.3.7",
"symfony/config": "^2.3.0|^3",
"symfony/dependency-injection": "^2.3.0|^3",
"symfony/filesystem": "^2.3.0|^3"
},
"require-dev": {
"phpunit/phpunit": "^4.4.0,<4.8",
"squizlabs/php_codesniffer": "^2.0.0"
},
"bin": [
"src/bin/pdepend"
],
"type": "library",
"autoload": {
"psr-4": {
"PDepend\\": "src/main/php/PDepend"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Official version of pdepend to be handled with Composer",
"time": "2016-03-10 15:15:04"
},
{
"name": "phpmd/phpmd",
"version": "2.4.2",
"source": {
"type": "git",
"url": "https://github.com/phpmd/phpmd.git",
"reference": "fccbdb6b222f6d7a6d35af1c396ba5435cec76a9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpmd/phpmd/zipball/fccbdb6b222f6d7a6d35af1c396ba5435cec76a9",
"reference": "fccbdb6b222f6d7a6d35af1c396ba5435cec76a9",
"shasum": ""
},
"require": {
"pdepend/pdepend": "~2.0",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"squizlabs/php_codesniffer": "^2.0"
},
"bin": [
"src/bin/phpmd"
],
"type": "project",
"autoload": {
"psr-0": {
"PHPMD\\": "src/main/php"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Manuel Pichler",
"email": "github@manuel-pichler.de",
"homepage": "https://github.com/manuelpichler",
"role": "Project Founder"
},
{
"name": "Other contributors",
"homepage": "https://github.com/phpmd/phpmd/graphs/contributors",
"role": "Contributors"
},
{
"name": "Marc Würth",
"email": "ravage@bluewin.ch",
"homepage": "https://github.com/ravage84",
"role": "Project Maintainer"
}
],
"description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.",
"homepage": "http://phpmd.org/",
"keywords": [
"mess detection",
"mess detector",
"pdepend",
"phpmd",
"pmd"
],
"time": "2016-03-10 17:17:44"
},
{
"name": "squizlabs/php_codesniffer",
"version": "2.5.1",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "6731851d6aaf1d0d6c58feff1065227b7fda3ba8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6731851d6aaf1d0d6c58feff1065227b7fda3ba8",
"reference": "6731851d6aaf1d0d6c58feff1065227b7fda3ba8",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"ext-xmlwriter": "*",
"php": ">=5.1.2"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"bin": [
"scripts/phpcs",
"scripts/phpcbf"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"classmap": [
"CodeSniffer.php",
"CodeSniffer/CLI.php",
"CodeSniffer/Exception.php",
"CodeSniffer/File.php",
"CodeSniffer/Fixer.php",
"CodeSniffer/Report.php",
"CodeSniffer/Reporting.php",
"CodeSniffer/Sniff.php",
"CodeSniffer/Tokens.php",
"CodeSniffer/Reports/",
"CodeSniffer/Tokenizers/",
"CodeSniffer/DocGenerators/",
"CodeSniffer/Standards/AbstractPatternSniff.php",
"CodeSniffer/Standards/AbstractScopeSniff.php",
"CodeSniffer/Standards/AbstractVariableSniff.php",
"CodeSniffer/Standards/IncorrectPatternException.php",
"CodeSniffer/Standards/Generic/Sniffs/",
"CodeSniffer/Standards/MySource/Sniffs/",
"CodeSniffer/Standards/PEAR/Sniffs/",
"CodeSniffer/Standards/PSR1/Sniffs/",
"CodeSniffer/Standards/PSR2/Sniffs/",
"CodeSniffer/Standards/Squiz/Sniffs/",
"CodeSniffer/Standards/Zend/Sniffs/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Greg Sherwood",
"role": "lead"
}
],
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
"homepage": "http://www.squizlabs.com/php-codesniffer",
"keywords": [
"phpcs",
"standards"
],
"time": "2016-01-19 23:39:10"
},
{
"name": "symfony/config",
"version": "v3.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "980ee40c28f00acff8906c11b778aab5f0db74c2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/980ee40c28f00acff8906c11b778aab5f0db74c2",
"reference": "980ee40c28f00acff8906c11b778aab5f0db74c2",
"shasum": ""
},
"require": {
"php": ">=5.5.9",
"symfony/filesystem": "~2.8|~3.0"
},
"suggest": {
"symfony/yaml": "To use the yaml reference dumper"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Config\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
"time": "2016-03-04 07:55:57"
},
{
"name": "symfony/dependency-injection",
"version": "v3.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
"reference": "6a9058101b591edced21ca3c83c80a3978f5c6b0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/6a9058101b591edced21ca3c83c80a3978f5c6b0",
"reference": "6a9058101b591edced21ca3c83c80a3978f5c6b0",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"require-dev": {
"symfony/config": "~2.8|~3.0",
"symfony/expression-language": "~2.8|~3.0",
"symfony/yaml": "~2.8|~3.0"
},
"suggest": {
"symfony/config": "",
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
"symfony/yaml": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\DependencyInjection\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com",
"time": "2016-03-30 10:41:14"
},
{
"name": "symfony/filesystem",
"version": "v3.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "f82499a459dcade2ea56df94cc58b19c8bde3d20"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/f82499a459dcade2ea56df94cc58b19c8bde3d20",
"reference": "f82499a459dcade2ea56df94cc58b19c8bde3d20",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"time": "2016-03-27 10:24:39"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=5.5.0"
},
"platform-dev": []
}

View File

@@ -1,4 +1,42 @@
<?php
/**
* Do not edit anything in this file unless you know what you're doing
*/
/**
* Require Composer autoloader if installed on it's own
*/
if (file_exists($composer = __DIR__ . '/vendor/autoload.php')) {
require_once $composer;
}
/**
* Here's what's happening with these hooks:
* 1. WordPress detects theme in themes/sage
* 2. When we activate, we tell WordPress that the theme is actually in themes/sage/templates
* 3. When we call get_template_directory() or get_template_directory_uri(), we point it back to themes/sage
*
* We do this so that the Template Hierarchy will look in themes/sage/templates for core WordPress themes
* But functions.php, style.css, and index.php are all still located in themes/sage
*
* themes/sage/index.php also contains some self-correcting code, just in case the template option gets reset
*/
add_filter('stylesheet', function ($stylesheet) {
return dirname($stylesheet);
});
add_action('after_switch_theme', function () {
$stylesheet = get_option('stylesheet');
if (basename($stylesheet) !== 'templates') {
update_option('stylesheet', $stylesheet . '/templates');
}
});
add_action('customize_render_section', function ($section) {
if ($section->type === 'themes') {
$section->title = wp_get_theme(basename(__DIR__))->display('Name');
}
}, 10, 2);
/**
* Sage includes
*
@@ -6,23 +44,15 @@
* Add or remove files to the array as needed. Supports child theme overrides.
*
* Please note that missing files will produce a fatal error.
*
* @link https://github.com/roots/sage/pull/1042
*/
$sage_includes = [
'lib/assets.php', // Scripts and stylesheets
'lib/extras.php', // Custom functions
'lib/setup.php', // Theme setup
'lib/titles.php', // Page titles
'lib/wrapper.php', // Theme wrapper class
'lib/customizer.php' // Theme customizer
'src/helpers.php', // Helper functions
'src/setup.php', // Theme setup
'src/filters.php', // Filters
'src/admin.php' // Admin
];
foreach ($sage_includes as $file) {
if (!$filepath = locate_template($file)) {
trigger_error(sprintf(__('Error locating %s for inclusion', 'sage'), $file), E_USER_ERROR);
}
require_once $filepath;
}
unset($file, $filepath);
array_walk($sage_includes, function ($file) {
if (!locate_template($file, true, true)) {
trigger_error(sprintf(__('Error locating %s for inclusion', 'sage'), $file), E_USER_ERROR);
}
});

View File

@@ -1,288 +0,0 @@
// ## Globals
var argv = require('minimist')(process.argv.slice(2));
var autoprefixer = require('gulp-autoprefixer');
var browserSync = require('browser-sync').create();
var changed = require('gulp-changed');
var concat = require('gulp-concat');
var flatten = require('gulp-flatten');
var gulp = require('gulp');
var gulpif = require('gulp-if');
var imagemin = require('gulp-imagemin');
var jshint = require('gulp-jshint');
var lazypipe = require('lazypipe');
var less = require('gulp-less');
var merge = require('merge-stream');
var cssNano = require('gulp-cssnano');
var plumber = require('gulp-plumber');
var rev = require('gulp-rev');
var runSequence = require('run-sequence');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var uglify = require('gulp-uglify');
// See https://github.com/austinpray/asset-builder
var manifest = require('asset-builder')('./assets/manifest.json');
// `path` - Paths to base asset directories. With trailing slashes.
// - `path.source` - Path to the source files. Default: `assets/`
// - `path.dist` - Path to the build directory. Default: `dist/`
var path = manifest.paths;
// `config` - Store arbitrary configuration values here.
var config = manifest.config || {};
// `globs` - These ultimately end up in their respective `gulp.src`.
// - `globs.js` - Array of asset-builder JS dependency objects. Example:
// ```
// {type: 'js', name: 'main.js', globs: []}
// ```
// - `globs.css` - Array of asset-builder CSS dependency objects. Example:
// ```
// {type: 'css', name: 'main.css', globs: []}
// ```
// - `globs.fonts` - Array of font path globs.
// - `globs.images` - Array of image path globs.
// - `globs.bower` - Array of all the main Bower files.
var globs = manifest.globs;
// `project` - paths to first-party assets.
// - `project.js` - Array of first-party JS assets.
// - `project.css` - Array of first-party CSS assets.
var project = manifest.getProjectGlobs();
// CLI options
var enabled = {
// Enable static asset revisioning when `--production`
rev: argv.production,
// Disable source maps when `--production`
maps: !argv.production,
// Fail styles task on error when `--production`
failStyleTask: argv.production,
// Fail due to JSHint warnings only when `--production`
failJSHint: argv.production,
// Strip debug statments from javascript when `--production`
stripJSDebug: argv.production
};
// Path to the compiled assets manifest in the dist directory
var revManifest = path.dist + 'assets.json';
// ## Reusable Pipelines
// See https://github.com/OverZealous/lazypipe
// ### CSS processing pipeline
// Example
// ```
// gulp.src(cssFiles)
// .pipe(cssTasks('main.css')
// .pipe(gulp.dest(path.dist + 'styles'))
// ```
var cssTasks = function(filename) {
return lazypipe()
.pipe(function() {
return gulpif(!enabled.failStyleTask, plumber());
})
.pipe(function() {
return gulpif(enabled.maps, sourcemaps.init());
})
.pipe(function() {
return gulpif('*.less', less());
})
.pipe(function() {
return gulpif('*.scss', sass({
outputStyle: 'nested', // libsass doesn't support expanded yet
precision: 10,
includePaths: ['.'],
errLogToConsole: !enabled.failStyleTask
}));
})
.pipe(concat, filename)
.pipe(autoprefixer, {
browsers: [
'last 2 versions',
'android 4',
'opera 12'
]
})
.pipe(cssNano, {
safe: true
})
.pipe(function() {
return gulpif(enabled.rev, rev());
})
.pipe(function() {
return gulpif(enabled.maps, sourcemaps.write('.', {
sourceRoot: 'assets/styles/'
}));
})();
};
// ### JS processing pipeline
// Example
// ```
// gulp.src(jsFiles)
// .pipe(jsTasks('main.js')
// .pipe(gulp.dest(path.dist + 'scripts'))
// ```
var jsTasks = function(filename) {
return lazypipe()
.pipe(function() {
return gulpif(enabled.maps, sourcemaps.init());
})
.pipe(concat, filename)
.pipe(uglify, {
compress: {
'drop_debugger': enabled.stripJSDebug
}
})
.pipe(function() {
return gulpif(enabled.rev, rev());
})
.pipe(function() {
return gulpif(enabled.maps, sourcemaps.write('.', {
sourceRoot: 'assets/scripts/'
}));
})();
};
// ### Write to rev manifest
// If there are any revved files then write them to the rev manifest.
// See https://github.com/sindresorhus/gulp-rev
var writeToManifest = function(directory) {
return lazypipe()
.pipe(gulp.dest, path.dist + directory)
.pipe(browserSync.stream, {match: '**/*.{js,css}'})
.pipe(rev.manifest, revManifest, {
base: path.dist,
merge: true
})
.pipe(gulp.dest, path.dist)();
};
// ## Gulp tasks
// Run `gulp -T` for a task summary
// ### Styles
// `gulp styles` - Compiles, combines, and optimizes Bower CSS and project CSS.
// By default this task will only log a warning if a precompiler error is
// raised. If the `--production` flag is set: this task will fail outright.
gulp.task('styles', ['wiredep'], function() {
var merged = merge();
manifest.forEachDependency('css', function(dep) {
var cssTasksInstance = cssTasks(dep.name);
if (!enabled.failStyleTask) {
cssTasksInstance.on('error', function(err) {
console.error(err.message);
this.emit('end');
});
}
merged.add(gulp.src(dep.globs, {base: 'styles'})
.pipe(cssTasksInstance));
});
return merged
.pipe(writeToManifest('styles'));
});
// ### Scripts
// `gulp scripts` - Runs JSHint then compiles, combines, and optimizes Bower JS
// and project JS.
gulp.task('scripts', ['jshint'], function() {
var merged = merge();
manifest.forEachDependency('js', function(dep) {
merged.add(
gulp.src(dep.globs, {base: 'scripts'})
.pipe(jsTasks(dep.name))
);
});
return merged
.pipe(writeToManifest('scripts'));
});
// ### Fonts
// `gulp fonts` - Grabs all the fonts and outputs them in a flattened directory
// structure. See: https://github.com/armed/gulp-flatten
gulp.task('fonts', function() {
return gulp.src(globs.fonts)
.pipe(flatten())
.pipe(gulp.dest(path.dist + 'fonts'))
.pipe(browserSync.stream());
});
// ### Images
// `gulp images` - Run lossless compression on all the images.
gulp.task('images', function() {
return gulp.src(globs.images)
.pipe(imagemin({
progressive: true,
interlaced: true,
svgoPlugins: [{removeUnknownsAndDefaults: false}, {cleanupIDs: false}]
}))
.pipe(gulp.dest(path.dist + 'images'))
.pipe(browserSync.stream());
});
// ### JSHint
// `gulp jshint` - Lints configuration JSON and project JS.
gulp.task('jshint', function() {
return gulp.src([
'bower.json', 'gulpfile.js'
].concat(project.js))
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'))
.pipe(gulpif(enabled.failJSHint, jshint.reporter('fail')));
});
// ### Clean
// `gulp clean` - Deletes the build folder entirely.
gulp.task('clean', require('del').bind(null, [path.dist]));
// ### Watch
// `gulp watch` - Use BrowserSync to proxy your dev server and synchronize code
// changes across devices. Specify the hostname of your dev server at
// `manifest.config.devUrl`. When a modification is made to an asset, run the
// build step for that asset and inject the changes into the page.
// See: http://www.browsersync.io
gulp.task('watch', function() {
browserSync.init({
files: ['{lib,templates}/**/*.php', '*.php'],
proxy: config.devUrl,
snippetOptions: {
whitelist: ['/wp-admin/admin-ajax.php'],
blacklist: ['/wp-admin/**']
}
});
gulp.watch([path.source + 'styles/**/*'], ['styles']);
gulp.watch([path.source + 'scripts/**/*'], ['jshint', 'scripts']);
gulp.watch([path.source + 'fonts/**/*'], ['fonts']);
gulp.watch([path.source + 'images/**/*'], ['images']);
gulp.watch(['bower.json', 'assets/manifest.json'], ['build']);
});
// ### Build
// `gulp build` - Run all the build tasks but don't clean up beforehand.
// Generally you should be running `gulp` instead of `gulp build`.
gulp.task('build', function(callback) {
runSequence('styles',
'scripts',
['fonts', 'images'],
callback);
});
// ### Wiredep
// `gulp wiredep` - Automatically inject Less and Sass Bower dependencies. See
// https://github.com/taptapship/wiredep
gulp.task('wiredep', function() {
var wiredep = require('wiredep').stream;
return gulp.src(project.css)
.pipe(wiredep())
.pipe(changed(path.source + 'styles', {
hasChanged: changed.compareSha1Digest
}))
.pipe(gulp.dest(path.source + 'styles'));
});
// ### Gulp
// `gulp` - Run a complete build. To compile for production run `gulp --production`.
gulp.task('default', ['clean'], function() {
gulp.start('build');
});

View File

@@ -1,14 +1,6 @@
<?php get_template_part('templates/page', 'header'); ?>
<?php
<?php if (!have_posts()) : ?>
<div class="alert alert-warning">
<?php _e('Sorry, no results were found.', 'sage'); ?>
</div>
<?php get_search_form(); ?>
<?php endif; ?>
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('templates/content', get_post_type() != 'post' ? get_post_type() : get_post_format()); ?>
<?php endwhile; ?>
<?php the_posts_navigation(); ?>
if (defined('ABSPATH')) {
update_option('template', get_option('template') . '/templates');
}
die("Kind Regards,\nRoots");

View File

@@ -1,103 +0,0 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: 404.php:4
msgid "Sorry, but the page you were trying to view does not exist."
msgstr ""
#: base.php:14
msgid ""
"You are using an <strong>outdated</strong> browser. Please <a href=\"http://"
"browsehappy.com/\">upgrade your browser</a> to improve your experience."
msgstr ""
#: functions.php:22
msgid "Error locating %s for inclusion"
msgstr ""
#: index.php:5 search.php:5
msgid "Sorry, no results were found."
msgstr ""
#: lib/extras.php:31
msgid "Continued"
msgstr ""
#: lib/setup.php:30
msgid "Primary Navigation"
msgstr ""
#: lib/setup.php:57
msgid "Primary"
msgstr ""
#: lib/setup.php:66
msgid "Footer"
msgstr ""
#: lib/titles.php:13
msgid "Latest Posts"
msgstr ""
#: lib/titles.php:18
msgid "Search Results for %s"
msgstr ""
#: lib/titles.php:20
msgid "Not Found"
msgstr ""
#: templates/comments.php:9
msgctxt "comments title"
msgid "One response to &ldquo;%2$s&rdquo;"
msgid_plural "%1$s responses to &ldquo;%2$s&rdquo;"
msgstr[0] ""
msgstr[1] ""
#: templates/comments.php:19
msgid "&larr; Older comments"
msgstr ""
#: templates/comments.php:22
msgid "Newer comments &rarr;"
msgstr ""
#: templates/comments.php:31
msgid "Comments are closed."
msgstr ""
#: templates/content-page.php:2 templates/content-single.php:11
msgid "Pages:"
msgstr ""
#: templates/entry-meta.php:2
msgid "By"
msgstr ""
#. Theme Name of the plugin/theme
msgid "Sage Starter Theme"
msgstr ""
#. Theme URI of the plugin/theme
msgid "https://roots.io/sage/"
msgstr ""
#. Description of the plugin/theme
msgid ""
"Sage is a WordPress starter theme. <a href=\"https://github.com/roots/sage"
"\">Contribute on GitHub</a>"
msgstr ""
#. Author of the plugin/theme
msgid "Roots"
msgstr ""
#. Author URI of the plugin/theme
msgid "https://roots.io/"
msgstr ""
#. Template Name of the plugin/theme
msgid "Custom Template"
msgstr ""

View File

@@ -1,58 +0,0 @@
<?php
namespace Roots\Sage\Assets;
/**
* Get paths for assets
*/
class JsonManifest {
private $manifest;
public function __construct($manifest_path) {
if (file_exists($manifest_path)) {
$this->manifest = json_decode(file_get_contents($manifest_path), true);
} else {
$this->manifest = [];
}
}
public function get() {
return $this->manifest;
}
public function getPath($key = '', $default = null) {
$collection = $this->manifest;
if (is_null($key)) {
return $collection;
}
if (isset($collection[$key])) {
return $collection[$key];
}
foreach (explode('.', $key) as $segment) {
if (!isset($collection[$segment])) {
return $default;
} else {
$collection = $collection[$segment];
}
}
return $collection;
}
}
function asset_path($filename) {
$dist_path = get_template_directory_uri() . '/dist/';
$directory = dirname($filename) . '/';
$file = basename($filename);
static $manifest;
if (empty($manifest)) {
$manifest_path = get_template_directory() . '/dist/' . 'assets.json';
$manifest = new JsonManifest($manifest_path);
}
if (array_key_exists($file, $manifest->get())) {
return $dist_path . $directory . $manifest->get()[$file];
} else {
return $dist_path . $directory . $file;
}
}

View File

@@ -1,21 +0,0 @@
<?php
namespace Roots\Sage\Customizer;
use Roots\Sage\Assets;
/**
* Add postMessage support
*/
function customize_register($wp_customize) {
$wp_customize->get_setting('blogname')->transport = 'postMessage';
}
add_action('customize_register', __NAMESPACE__ . '\\customize_register');
/**
* Customizer JS
*/
function customize_preview_js() {
wp_enqueue_script('sage/customizer', Assets\asset_path('scripts/customizer.js'), ['customize-preview'], null, true);
}
add_action('customize_preview_init', __NAMESPACE__ . '\\customize_preview_js');

View File

@@ -1,33 +0,0 @@
<?php
namespace Roots\Sage\Extras;
use Roots\Sage\Setup;
/**
* Add <body> classes
*/
function body_class($classes) {
// Add page slug if it doesn't exist
if (is_single() || is_page() && !is_front_page()) {
if (!in_array(basename(get_permalink()), $classes)) {
$classes[] = basename(get_permalink());
}
}
// Add class if sidebar is active
if (Setup\display_sidebar()) {
$classes[] = 'sidebar-primary';
}
return $classes;
}
add_filter('body_class', __NAMESPACE__ . '\\body_class');
/**
* Clean up the_excerpt()
*/
function excerpt_more() {
return ' &hellip; <a href="' . get_permalink() . '">' . __('Continued', 'sage') . '</a>';
}
add_filter('excerpt_more', __NAMESPACE__ . '\\excerpt_more');

View File

@@ -1,106 +0,0 @@
<?php
namespace Roots\Sage\Setup;
use Roots\Sage\Assets;
/**
* Theme setup
*/
function setup() {
// Enable features from Soil when plugin is activated
// https://roots.io/plugins/soil/
add_theme_support('soil-clean-up');
add_theme_support('soil-nav-walker');
add_theme_support('soil-nice-search');
add_theme_support('soil-jquery-cdn');
add_theme_support('soil-relative-urls');
// Make theme available for translation
// Community translations can be found at https://github.com/roots/sage-translations
load_theme_textdomain('sage', get_template_directory() . '/lang');
// Enable plugins to manage the document title
// http://codex.wordpress.org/Function_Reference/add_theme_support#Title_Tag
add_theme_support('title-tag');
// Register wp_nav_menu() menus
// http://codex.wordpress.org/Function_Reference/register_nav_menus
register_nav_menus([
'primary_navigation' => __('Primary Navigation', 'sage')
]);
// Enable post thumbnails
// http://codex.wordpress.org/Post_Thumbnails
// http://codex.wordpress.org/Function_Reference/set_post_thumbnail_size
// http://codex.wordpress.org/Function_Reference/add_image_size
add_theme_support('post-thumbnails');
// Enable post formats
// http://codex.wordpress.org/Post_Formats
add_theme_support('post-formats', ['aside', 'gallery', 'link', 'image', 'quote', 'video', 'audio']);
// Enable HTML5 markup support
// http://codex.wordpress.org/Function_Reference/add_theme_support#HTML5
add_theme_support('html5', ['caption', 'comment-form', 'comment-list', 'gallery', 'search-form']);
// Use main stylesheet for visual editor
// To add custom styles edit /assets/styles/layouts/_tinymce.scss
add_editor_style(Assets\asset_path('styles/main.css'));
}
add_action('after_setup_theme', __NAMESPACE__ . '\\setup');
/**
* Register sidebars
*/
function widgets_init() {
register_sidebar([
'name' => __('Primary', 'sage'),
'id' => 'sidebar-primary',
'before_widget' => '<section class="widget %1$s %2$s">',
'after_widget' => '</section>',
'before_title' => '<h3>',
'after_title' => '</h3>'
]);
register_sidebar([
'name' => __('Footer', 'sage'),
'id' => 'sidebar-footer',
'before_widget' => '<section class="widget %1$s %2$s">',
'after_widget' => '</section>',
'before_title' => '<h3>',
'after_title' => '</h3>'
]);
}
add_action('widgets_init', __NAMESPACE__ . '\\widgets_init');
/**
* Determine which pages should NOT display the sidebar
*/
function display_sidebar() {
static $display;
isset($display) || $display = !in_array(true, [
// The sidebar will NOT be displayed if ANY of the following return true.
// @link https://codex.wordpress.org/Conditional_Tags
is_404(),
is_front_page(),
is_page_template('template-custom.php'),
]);
return apply_filters('sage/display_sidebar', $display);
}
/**
* Theme assets
*/
function assets() {
wp_enqueue_style('sage/css', Assets\asset_path('styles/main.css'), false, null);
if (is_single() && comments_open() && get_option('thread_comments')) {
wp_enqueue_script('comment-reply');
}
wp_enqueue_script('sage/js', Assets\asset_path('scripts/main.js'), ['jquery'], null, true);
}
add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\assets', 100);

View File

@@ -1,24 +0,0 @@
<?php
namespace Roots\Sage\Titles;
/**
* Page titles
*/
function title() {
if (is_home()) {
if (get_option('page_for_posts', true)) {
return get_the_title(get_option('page_for_posts', true));
} else {
return __('Latest Posts', 'sage');
}
} elseif (is_archive()) {
return get_the_archive_title();
} elseif (is_search()) {
return sprintf(__('Search Results for %s', 'sage'), get_search_query());
} elseif (is_404()) {
return __('Not Found', 'sage');
} else {
return get_the_title();
}
}

View File

@@ -1,64 +0,0 @@
<?php
namespace Roots\Sage\Wrapper;
/**
* Theme wrapper
*
* @link https://roots.io/sage/docs/theme-wrapper/
* @link http://scribu.net/wordpress/theme-wrappers.html
*/
function template_path() {
return SageWrapping::$main_template;
}
function sidebar_path() {
return new SageWrapping('templates/sidebar.php');
}
class SageWrapping {
// Stores the full path to the main template file
public static $main_template;
// Basename of template file
public $slug;
// Array of templates
public $templates;
// Stores the base name of the template file; e.g. 'page' for 'page.php' etc.
public static $base;
public function __construct($template = 'base.php') {
$this->slug = basename($template, '.php');
$this->templates = [$template];
if (self::$base) {
$str = substr($template, 0, -4);
array_unshift($this->templates, sprintf($str . '-%s.php', self::$base));
}
}
public function __toString() {
$this->templates = apply_filters('sage/wrap_' . $this->slug, $this->templates);
return locate_template($this->templates);
}
public static function wrap($main) {
// Check for other filters returning null
if (!is_string($main)) {
return $main;
}
self::$main_template = $main;
self::$base = basename(self::$main_template, '.php');
if (self::$base === 'index') {
self::$base = false;
}
return new SageWrapping();
}
}
add_filter('template_include', [__NAMESPACE__ . '\\SageWrapping', 'wrap'], 109);

View File

@@ -1,7 +1,9 @@
{
"name": "sage",
"version": "8.4.2",
"author": "Ben Word <ben@benword.com>",
"version": "9.0.0",
"author": "Roots <team@roots.io>",
"homepage": "https://roots.io/sage/",
"private": true,
"repository": {
@@ -18,41 +20,55 @@
}
],
"scripts": {
"build": "bower install && gulp",
"jshint": "gulp jshint",
"jscs": "jscs gulpfile.js assets/scripts/*.js"
"build:production": "webpack -p --progress --release",
"build": "webpack -d --progress",
"watch": "node watch.js --watch",
"lint": "eslint -c .eslintrc assets/scripts watch.js webpack.config.js"
},
"engines": {
"node": ">= 0.12.0",
"npm": ">=2.1.5"
"node": ">=4"
},
"devDependencies": {
"asset-builder": "^1.1.0",
"browser-sync": "^2.8.2",
"del": "^1.2.1",
"gulp": "^3.9.0",
"gulp-autoprefixer": "^2.3.1",
"gulp-changed": "^1.3.0",
"gulp-concat": "^2.6.0",
"gulp-cssnano": "^2.1.0",
"gulp-flatten": "0.1.1",
"gulp-if": "^2.0.1",
"gulp-imagemin": "^2.3.0",
"gulp-jshint": "^1.11.2",
"gulp-less": "^3.0.3",
"gulp-plumber": "^1.0.1",
"gulp-rename": "^1.2.2",
"gulp-rev": "^6.0.0",
"gulp-sass": "^2.0.1",
"gulp-sourcemaps": "^1.5.2",
"gulp-uglify": "^1.2.0",
"imagemin-pngcrush": "^4.1.0",
"jshint-stylish": "^2.0.1",
"lazypipe": "^1.0.1",
"merge-stream": "^1.0.0",
"minimist": "^1.1.3",
"run-sequence": "^1.1.2",
"traverse": "^0.6.6",
"wiredep": "^2.2.2"
"assets-webpack-plugin": "^3.4.0",
"autoprefixer": "^6.1.0",
"babel-cli": "^6.6.5",
"babel-core": "^6.7.4",
"babel-eslint": "^6.0.0",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.13.2",
"babel-register": "^6.5.2",
"babel-runtime": "^6.5.0",
"body-parser": "^1.14.1",
"browser-sync": "^2.11.2",
"clean-webpack-plugin": "^0.1.8",
"css-loader": "^0.23.1",
"cssnano": "^3.5.2",
"eslint": "^3.2.2",
"eslint-loader": "^1.3.0",
"eslint-plugin-react": "^6.0.0",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.9.0",
"image-webpack-loader": "^2.0.0",
"imagemin-pngcrush": "^5.0.0",
"imports-loader": "^0.6.5",
"minimist": "^1.2.0",
"monkey-hot-loader": "0.0.3",
"node-sass": "^3.4.2",
"optimize-css-assets-webpack-plugin": "^1.3.0",
"postcss": "^5.0.18",
"postcss-loader": "^0.9.1",
"qs": "^6.1.0",
"resolve-url-loader": "^1.4.3",
"sass-loader": "^4.0.0",
"style-loader": "^0.13.0",
"url-loader": "^0.5.7",
"webpack": "^1.12.14",
"webpack-dev-middleware": "^1.6",
"webpack-hot-middleware": "^2.10.0"
},
"dependencies": {
"bootstrap": "github:twbs/bootstrap#v4-dev",
"font-awesome": "^4.6.3",
"jquery": "^1.12.4"
}
}

View File

@@ -1,4 +0,0 @@
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('templates/page', 'header'); ?>
<?php get_template_part('templates/content', 'page'); ?>
<?php endwhile; ?>

71
phpcs.xml Normal file
View File

@@ -0,0 +1,71 @@
<?xml version="1.0"?>
<ruleset name="Roots">
<description>Roots Coding Standards</description>
<!-- Scan these files -->
<file>functions.php</file>
<file>index.php</file>
<file>src</file>
<file>templates</file>
<!-- Show colors in console -->
<arg value="-colors"/>
<!-- Show sniff codes in all reports -->
<arg value="s"/>
<!-- Use PSR-2 as a base -->
<rule ref="PSR2"/>
<!-- Exclusions below are for templates/ folder -->
<!-- Allow php files without any PHP in them -->
<rule ref="Internal.NoCodeFound">
<exclude-pattern>templates</exclude-pattern>
</rule>
<!-- Allow braces on same line for named functions -->
<rule ref="Squiz.Functions.MultiLineFunctionDeclaration.BraceOnSameLine">
<exclude-pattern>templates</exclude-pattern>
</rule>
<!-- Allow closing braces to be on the same line -->
<rule ref="Squiz.WhiteSpace.ScopeClosingBrace">
<exclude-pattern>templates</exclude-pattern>
</rule>
<!-- Disable newline after opening brace -->
<rule ref="Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace">
<exclude-pattern>templates</exclude-pattern>
</rule>
<!-- Allow multiple PHP statements in the same line -->
<rule ref="Generic.Formatting.DisallowMultipleStatements.SameLine">
<exclude-pattern>templates</exclude-pattern>
</rule>
<!-- Disable PSR-2 indentation rules that are buggy with 2 spaces -->
<rule ref="PSR2.ControlStructures.SwitchDeclaration.BreakIndent">
<exclude-pattern>templates</exclude-pattern>
</rule>
<!-- Don't require a blank line after the last `use` -->
<rule ref="PSR2.Namespaces.UseDeclaration.SpaceAfterLastUse">
<exclude-pattern>templates</exclude-pattern>
</rule>
<!-- Allow long lines -->
<rule ref="Generic.Files.LineLength.TooLong">
<exclude-pattern>templates</exclude-pattern>
</rule>
<!-- Ignore indentation rules -->
<rule ref="Generic.WhiteSpace.ScopeIndent">
<exclude-pattern>templates</exclude-pattern>
</rule>
<!-- Allow PHP closing tags -->
<rule ref="PSR2.Files.ClosingTag.NotAllowed">
<exclude-pattern>templates</exclude-pattern>
</rule>
</ruleset>

View File

@@ -1,48 +0,0 @@
<?xml version="1.0"?>
<ruleset name="Roots">
<description>Roots Coding Standards</description>
<!-- Use PSR-2 as a base -->
<rule ref="PSR2">
<!-- Allow opening and closing braces for functions and classes to be on the same line -->
<exclude name="Squiz.Functions.MultiLineFunctionDeclaration.BraceOnSameLine"/>
<exclude name="PSR2.Classes.ClassDeclaration.OpenBraceNewLine"/>
<exclude name="Squiz.WhiteSpace.ScopeClosingBrace"/>
<!-- Disable newline after opening brace -->
<exclude name="Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace"/>
<!-- Allow multiple PHP statements in the same line (usually in template files) -->
<exclude name="Generic.Formatting.DisallowMultipleStatements.SameLine"/>
<!-- Disable PSR-2 indentation rules that are buggy with 2 spaces -->
<exclude name="PSR2.ControlStructures.SwitchDeclaration.BreakIndent"/>
<exclude name="PSR2.Methods.FunctionCallSignature.Indent"/>
</rule>
<!-- Don't require a blank line after the last `use` in templates/ directory -->
<rule ref="PSR2.Namespaces.UseDeclaration.SpaceAfterLastUse">
<exclude-pattern>templates/*</exclude-pattern>
</rule>
<!-- Allow PHP closing tags on templates -->
<rule ref="PSR2.Files.ClosingTag.NotAllowed">
<exclude-pattern>templates/*</exclude-pattern>
<exclude-pattern>404.php</exclude-pattern>
<exclude-pattern>index.php</exclude-pattern>
<exclude-pattern>page.php</exclude-pattern>
<exclude-pattern>single.php</exclude-pattern>
<exclude-pattern>template-custom.php</exclude-pattern>
</rule>
<!-- Force 2 spaces indentation -->
<rule ref="Generic.WhiteSpace.ScopeIndent">
<properties>
<property name="indent" value="2"/>
<property name="tabIndent" value="false"/>
</properties>
</rule>
<!-- Verify that operators have valid spacing surrounding them -->
<rule ref="Squiz.WhiteSpace.OperatorSpacing"></rule>
</ruleset>

View File

@@ -1 +0,0 @@
<?php get_template_part('templates/content-single', get_post_type()); ?>

16
src/admin.php Normal file
View File

@@ -0,0 +1,16 @@
<?php namespace App;
/**
* Theme customizer
*/
add_action('customize_register', function (\WP_Customize_Manager $wp_customize) {
// Add postMessage support
$wp_customize->get_setting('blogname')->transport = 'postMessage';
});
/**
* Customizer JS
*/
add_action('customize_preview_init', function () {
wp_enqueue_script('sage/customizer.js', asset_path('scripts/customizer.js'), ['customize-preview'], null, true);
});

53
src/filters.php Normal file
View File

@@ -0,0 +1,53 @@
<?php namespace App;
use Roots\Sage\Template;
use Roots\Sage\Template\Wrapper;
/**
* Determine which pages should NOT display the sidebar
* @link https://codex.wordpress.org/Conditional_Tags
*/
add_filter('sage/display_sidebar', function ($display) {
// The sidebar will NOT be displayed if ANY of the following return true
return $display ? !in_array(true, [
is_404(),
is_front_page(),
is_page_template('templates/template-custom.php'),
]) : $display;
});
/**
* Add <body> classes
*/
add_filter('body_class', function (array $classes) {
// Add page slug if it doesn't exist
if (is_single() || is_page() && !is_front_page()) {
if (!in_array(basename(get_permalink()), $classes)) {
$classes[] = basename(get_permalink());
}
}
// Add class if sidebar is active
if (display_sidebar()) {
$classes[] = 'sidebar-primary';
}
return $classes;
});
/**
* Add "… Continued" to the excerpt
*/
add_filter('excerpt_more', function () {
return ' &hellip; <a href="' . get_permalink() . '">' . __('Continued', 'sage') . '</a>';
});
/**
* Use theme wrapper
*/
add_filter('template_include', function ($main) {
if (!is_string($main) && !(is_object($main) && method_exists($main, '__toString'))) {
return $main;
}
return ((new Template(new Wrapper($main)))->layout());
}, 109);

62
src/helpers.php Normal file
View File

@@ -0,0 +1,62 @@
<?php namespace App;
use Roots\Sage\Asset;
use Roots\Sage\Assets\JsonManifest;
use Roots\Sage\Template;
function template($layout = 'base')
{
return Template::$instances[$layout];
}
function template_part($template, array $context = [], $layout = 'base')
{
extract($context);
include template($layout)->partial($template);
}
/**
* @param $filename
* @return string
*/
function asset_path($filename)
{
static $manifest;
isset($manifest) || $manifest = new JsonManifest(get_template_directory() . '/' . Asset::$dist . '/assets.json');
return (string) new Asset($filename, $manifest);
}
/**
* Determine whether to show the sidebar
* @return bool
*/
function display_sidebar()
{
static $display;
isset($display) || $display = apply_filters('sage/display_sidebar', true);
return $display;
}
/**
* Page titles
* @return string
*/
function title()
{
if (is_home()) {
if ($home = get_option('page_for_posts', true)) {
return get_the_title($home);
}
return __('Latest Posts', 'sage');
}
if (is_archive()) {
return get_the_archive_title();
}
if (is_search()) {
return sprintf(__('Search Results for %s', 'sage'), get_search_query());
}
if (is_404()) {
return __('Not Found', 'sage');
}
return get_the_title();
}

38
src/lib/Sage/Asset.php Normal file
View File

@@ -0,0 +1,38 @@
<?php namespace Roots\Sage;
use Roots\Sage\Assets\ManifestInterface;
/**
* Class Template
* @package Roots\Sage
* @author QWp6t
*/
class Asset
{
public static $dist = '/dist';
/** @var ManifestInterface Currently used manifest */
protected $manifest;
protected $asset;
protected $dir;
public function __construct($file, ManifestInterface $manifest = null)
{
$this->manifest = $manifest;
$this->asset = basename($file);
$this->dir = dirname($file) != '.' ? dirname($file) : '';
}
public function __toString()
{
return $this->getUri();
}
public function getUri()
{
$file = ($this->manifest ? $this->manifest->get($this->asset) : $this->asset);
return get_template_directory_uri() . self::$dist . '/' . $this->dir . '/' . $file;
}
}

View File

@@ -0,0 +1,33 @@
<?php namespace Roots\Sage\Assets;
/**
* Class JsonManifest
* @package Roots\Sage
* @author QWp6t
*/
class JsonManifest implements ManifestInterface
{
/** @var array */
protected $manifest = [];
/**
* JsonManifest constructor
* @param string $manifestPath Local filesystem path to JSON-encoded manifest
*/
public function __construct($manifestPath)
{
$this->manifest = file_exists($manifestPath) ? json_decode(file_get_contents($manifestPath), true) : [];
}
/** @inheritdoc */
public function get($file)
{
return isset($this->manifest[$file]) ? $this->manifest[$file] : $file;
}
/** @inheritdoc */
public function getAll()
{
return $this->manifest;
}
}

View File

@@ -0,0 +1,26 @@
<?php namespace Roots\Sage\Assets;
/**
* Interface ManifestInterface
* @package Roots\Sage
* @author QWp6t
*/
interface ManifestInterface
{
/**
* Get the cache-busted filename
*
* If the manifest does not have an entry for $file, then return $file
*
* @param string $file The original name of the file before cache-busting
* @return string
*/
public function get($file);
/**
* Get the asset manifest
*
* @return array
*/
public function getAll();
}

44
src/lib/Sage/Template.php Normal file
View File

@@ -0,0 +1,44 @@
<?php namespace Roots\Sage;
use Roots\Sage\Template\Partial;
use Roots\Sage\Template\WrapperInterface;
class Template
{
/** @var Template[] */
public static $instances = [];
/** @var WrapperInterface */
protected $wrapper;
public function __construct(WrapperInterface $wrapper)
{
$this->wrapper = $wrapper;
self::$instances[$wrapper->slug()] = $this;
}
/**
* @return string Layout (FQPN of, e.g., `base-page.php`, `base.php`)
*/
public function layout()
{
return $this->wrapper->wrap();
}
/**
* @return string Main template (FQPN of, e.g., `page.php`, `single.php`, `singular.php`)
*/
public function main()
{
return $this->wrapper->unwrap();
}
/**
* @param string $template Delimited template path
* @return string Partial template (FQPN of, e.g., `content.php`, `page-header.php`
*/
public function partial($template)
{
return (new Partial($template, $this->main()))->path();
}
}

View File

@@ -0,0 +1,70 @@
<?php namespace Roots\Sage\Template;
class Partial
{
protected static $cache = [];
public $main;
public $template;
public $delimiter = '-';
public function __construct($template, $main = '')
{
$this->template = $template;
$this->main = $main;
}
public function __toString()
{
return (string) $this->path();
}
/**
* Converts template into array of parts to be passed to locate_template()
*
* Here's an example of what happens:
* (new Template('partials/content-single-audio'))->parts();
* // => ['partials/content-single-audio.php', 'partials/content-single.php', 'partials/content.php']
* @return array Array of parts to pass to locate_template()
*/
public function parts()
{
if ($parts = $this->cache('parts')) {
return $parts;
}
$parts = explode($this->delimiter, str_replace('.php', '', $this->template));
$templates[] = array_shift($parts);
foreach ($parts as $i => $part) {
$templates[] = $templates[$i] . $this->delimiter . $part;
}
if ($this->main) {
$templates = array_merge($templates, array_map(function ($template) {
return $template . $this->delimiter . basename($this->main, '.php');
}, $templates));
}
$templates = array_map(function ($template) {
return $template . '.php';
}, $templates);
return $this->cache('parts', array_reverse($templates));
}
/**
* Passes $this->parts() to locate_template() to retrieve template location
* @return string Location of template
*/
public function path()
{
if (!$path = $this->cache('path')) {
$path = $this->cache('path', locate_template($this->parts()));
}
return apply_filters('sage/partial_' . basename($path, '.php'), $path, $this->parts()) ?: $path;
}
protected function cache($key, $value = null)
{
if ($value !== null) {
self::$cache[$this->template][$key] = $value;
}
return isset(self::$cache[$this->template][$key]) ? self::$cache[$this->template][$key] : null;
}
}

View File

@@ -0,0 +1,62 @@
<?php namespace Roots\Sage\Template;
/**
* Class Wrapper
* @package Roots\Sage
* @author QWp6t
*/
class Wrapper implements WrapperInterface
{
/** @var string Wrapper slug */
protected $slug;
/** @var string Template file that is being wrapped */
protected $template = '';
/** @var string[] Array of template wrappers; e.g., `base-singular.php`, `base-page.php`, `base.php` */
protected $wrapper = [];
/**
* Wrapper constructor
*
* @param string $template Template file, as from Template Hierarchy; e.g., `page.php`, `single.php`, `singular.php`
* @param string $base Wrapper's base template, this is what will wrap around $template
*/
public function __construct($template, $base = 'layouts/base.php')
{
$this->slug = sanitize_title(basename($base, '.php'));
$this->wrapper = [$base];
$this->template = $template;
$str = substr($base, 0, -4);
array_unshift($this->wrapper, sprintf($str . '-%s.php', basename($template, '.php')));
}
/**
* @return string
* @see getTemplate
*/
public function __toString()
{
return $this->unwrap();
}
/** {@inheritdoc} */
public function wrap()
{
$wrappers = apply_filters('sage/wrap_' . $this->slug, $this->wrapper) ?: $this->wrapper;
return locate_template($wrappers);
}
/** {@inheritdoc} */
public function slug()
{
return $this->slug;
}
/** {@inheritdoc} */
public function unwrap()
{
$template = apply_filters('sage/unwrap_' . $this->slug, $this->template) ?: $this->template;
return locate_template($template) ?: $template;
}
}

View File

@@ -0,0 +1,27 @@
<?php namespace Roots\Sage\Template;
/**
* Interface WrapperInterface
* @package Roots\Sage
* @author QWp6t
*/
interface WrapperInterface
{
/**
* Get wrapper template file
*
* @return string Wrapper template (FQPN of, e.g., `base-page.php`, `base.php`)
*/
public function wrap();
/**
* @return string Wrapped template (FQPN of, e.g., `page.php`, `single.php`, `singular.php`)
*/
public function unwrap();
/**
* @return string Slug of the WrapperInterface; e.g., `base`
*/
public function slug();
}

86
src/setup.php Executable file
View File

@@ -0,0 +1,86 @@
<?php namespace App;
use Roots\Sage\Template;
/**
* Theme assets
*/
add_action('wp_enqueue_scripts', function () {
wp_enqueue_style('sage/main.css', asset_path('styles/main.css'), false, null);
wp_enqueue_script('sage/main.js', asset_path('scripts/main.js'), ['jquery'], null, true);
}, 100);
/**
* Theme setup
*/
add_action('after_setup_theme', function () {
/**
* Enable features from Soil when plugin is activated
* @link https://roots.io/plugins/soil/
*/
add_theme_support('soil-clean-up');
add_theme_support('soil-jquery-cdn');
add_theme_support('soil-nav-walker');
add_theme_support('soil-nice-search');
add_theme_support('soil-relative-urls');
/**
* Enable plugins to manage the document title
* @link http://codex.wordpress.org/Function_Reference/add_theme_support#Title_Tag
*/
add_theme_support('title-tag');
/**
* Register navigation menus
* @link http://codex.wordpress.org/Function_Reference/register_nav_menus
*/
register_nav_menus([
'primary_navigation' => __('Primary Navigation', 'sage')
]);
/**
* Enable post thumbnails
* @link http://codex.wordpress.org/Post_Thumbnails
* @link http://codex.wordpress.org/Function_Reference/set_post_thumbnail_size
* @link http://codex.wordpress.org/Function_Reference/add_image_size
*/
add_theme_support('post-thumbnails');
/**
* Enable post formats
* @link http://codex.wordpress.org/Post_Formats
*/
add_theme_support('post-formats', ['aside', 'gallery', 'link', 'image', 'quote', 'video', 'audio']);
/**
* Enable HTML5 markup support
* @link http://codex.wordpress.org/Function_Reference/add_theme_support#HTML5
*/
add_theme_support('html5', ['caption', 'comment-form', 'comment-list', 'gallery', 'search-form']);
/**
* Use main stylesheet for visual editor
* @see assets/styles/layouts/_tinymce.scss
*/
add_editor_style(asset_path('styles/main.css'));
});
/**
* Register sidebars
*/
add_action('widgets_init', function () {
$config = [
'before_widget' => '<section class="widget %1$s %2$s">',
'after_widget' => '</section>',
'before_title' => '<h3>',
'after_title' => '</h3>'
];
register_sidebar([
'name' => __('Primary', 'sage'),
'id' => 'sidebar-primary'
] + $config);
register_sidebar([
'name' => __('Footer', 'sage'),
'id' => 'sidebar-footer'
] + $config);
});

View File

@@ -2,7 +2,7 @@
Theme Name: Sage Starter Theme
Theme URI: https://roots.io/sage/
Description: Sage is a WordPress starter theme. <a href="https://github.com/roots/sage">Contribute on GitHub</a>
Version: 8.4.2
Version: 9.0.0
Author: Roots
Author URI: https://roots.io/
Text Domain: sage

View File

@@ -1,10 +0,0 @@
<?php
/**
* Template Name: Custom Template
*/
?>
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('templates/page', 'header'); ?>
<?php get_template_part('templates/content', 'page'); ?>
<?php endwhile; ?>

View File

@@ -1,4 +1,4 @@
<?php get_template_part('templates/page', 'header'); ?>
<?php get_template_part('partials/page-header'); ?>
<div class="alert alert-warning">
<?php _e('Sorry, but the page you were trying to view does not exist.', 'sage'); ?>

View File

@@ -1,15 +0,0 @@
<?php while (have_posts()) : the_post(); ?>
<article <?php post_class(); ?>>
<header>
<h1 class="entry-title"><?php the_title(); ?></h1>
<?php get_template_part('templates/entry-meta'); ?>
</header>
<div class="entry-content">
<?php the_content(); ?>
</div>
<footer>
<?php wp_link_pages(['before' => '<nav class="page-nav"><p>' . __('Pages:', 'sage'), 'after' => '</p></nav>']); ?>
</footer>
<?php comments_template('/templates/comments.php'); ?>
</article>
<?php endwhile; ?>

14
templates/index.php Normal file
View File

@@ -0,0 +1,14 @@
<?php get_template_part('partials/page-header'); ?>
<?php if (!have_posts()) : ?>
<div class="alert alert-warning">
<?php _e('Sorry, no results were found.', 'sage'); ?>
</div>
<?php get_search_form(); ?>
<?php endif; ?>
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('partials/content', get_post_type() != 'post' ? get_post_type() : get_post_format()); ?>
<?php endwhile; ?>
<?php the_posts_navigation(); ?>

View File

@@ -1,13 +1,6 @@
<?php
use Roots\Sage\Setup;
use Roots\Sage\Wrapper;
?>
<!doctype html>
<html <?php language_attributes(); ?>>
<?php get_template_part('templates/head'); ?>
<?php get_template_part('partials/head'); ?>
<body <?php body_class(); ?>>
<!--[if IE]>
<div class="alert alert-warning">
@@ -16,23 +9,23 @@ use Roots\Sage\Wrapper;
<![endif]-->
<?php
do_action('get_header');
get_template_part('templates/header');
get_template_part('partials/header');
?>
<div class="wrap container" role="document">
<div class="content row">
<main class="main">
<?php include Wrapper\template_path(); ?>
</main><!-- /.main -->
<?php if (Setup\display_sidebar()) : ?>
<?php include App\template()->main(); ?>
</main>
<?php if (App\display_sidebar()) : ?>
<aside class="sidebar">
<?php include Wrapper\sidebar_path(); ?>
</aside><!-- /.sidebar -->
<?php App\template_part('partials/sidebar'); ?>
</aside>
<?php endif; ?>
</div><!-- /.content -->
</div><!-- /.wrap -->
</div>
</div>
<?php
do_action('get_footer');
get_template_part('templates/footer');
get_template_part('partials/footer');
wp_footer();
?>
</body>

View File

@@ -1,5 +0,0 @@
<?php use Roots\Sage\Titles; ?>
<div class="page-header">
<h1><?= Titles\title(); ?></h1>
</div>

4
templates/page.php Normal file
View File

@@ -0,0 +1,4 @@
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('partials/page-header'); ?>
<?php get_template_part('partials/content-page'); ?>
<?php endwhile; ?>

View File

@@ -1,7 +1,7 @@
<article <?php post_class(); ?>>
<header>
<h2 class="entry-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<?php if (get_post_type() === 'post') { get_template_part('templates/entry-meta'); } ?>
<?php if (get_post_type() === 'post') { get_template_part('partials/entry-meta'); } ?>
</header>
<div class="entry-summary">
<?php the_excerpt(); ?>

View File

@@ -0,0 +1,13 @@
<article <?php post_class(); ?>>
<header>
<h1 class="entry-title"><?php the_title(); ?></h1>
<?php get_template_part('partials/entry-meta'); ?>
</header>
<div class="entry-content">
<?php the_content(); ?>
</div>
<footer>
<?php wp_link_pages(['before' => '<nav class="page-nav"><p>' . __('Pages:', 'sage'), 'after' => '</p></nav>']); ?>
</footer>
<?php comments_template('/templates/partials/comments.php'); ?>
</article>

View File

@@ -1,7 +1,7 @@
<article <?php post_class(); ?>>
<header>
<h2 class="entry-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<?php get_template_part('templates/entry-meta'); ?>
<?php get_template_part('partials/entry-meta'); ?>
</header>
<div class="entry-summary">
<?php the_excerpt(); ?>

View File

@@ -1,6 +1,6 @@
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<?php wp_head(); ?>
</head>

View File

@@ -0,0 +1,3 @@
<div class="page-header">
<h1><?= App\title(); ?></h1>
</div>

View File

@@ -1,4 +1,4 @@
<?php get_template_part('templates/page', 'header'); ?>
<?php get_template_part('partials/page-header'); ?>
<?php if (!have_posts()) : ?>
<div class="alert alert-warning">
@@ -8,7 +8,7 @@
<?php endif; ?>
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('templates/content', 'search'); ?>
<?php get_template_part('partials/content-search'); ?>
<?php endwhile; ?>
<?php the_posts_navigation(); ?>

3
templates/single.php Normal file
View File

@@ -0,0 +1,3 @@
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('partials/content-single', get_post_type()); ?>
<?php endwhile; ?>

View File

@@ -0,0 +1,10 @@
<?php
/**
* Template Name: Custom Template
*/
?>
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('partials/page-header'); ?>
<?php get_template_part('partials/content-page'); ?>
<?php endwhile; ?>

33
watch.js Normal file
View File

@@ -0,0 +1,33 @@
// External dependencies
var webpack = require('webpack'),
webpackDevMiddleware = require('webpack-dev-middleware'),
webpackHotMiddleware = require('webpack-hot-middleware'),
browserSync = require('browser-sync');
// Internal dependencies
var webpackConfig = require('./webpack.config'),
config = require('./assets/config');
// Internal variables
var compiler = webpack(webpackConfig);
browserSync.init({
proxy: {
target: config.devUrl,
middleware: [
webpackDevMiddleware(compiler, {
publicPath: webpackConfig.output.publicPath,
stats: {
colors: true
}
}),
webpackHotMiddleware(compiler, {
log: browserSync.notify
})
]
},
files: [
'templates/**/*.php',
'src/**/*.php'
]
});

248
webpack.config.js Normal file
View File

@@ -0,0 +1,248 @@
// External dependencies
var webpack = require('webpack'),
path = require('path'),
argv = require('minimist')(process.argv.slice(2)),
qs = require('qs'),
autoprefixer = require('autoprefixer'),
Clean = require("clean-webpack-plugin"),
AssetsPlugin = require('assets-webpack-plugin'),
ExtractTextPlugin = require('extract-text-webpack-plugin'),
OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'),
cssnano = require('cssnano');
// Internal dependencies
var config = require('./assets/config');
// Internal variables
var scriptsFilename = (argv.release) ? 'scripts/[name]_[hash].js' : 'scripts/[name].js',
stylesFilename = (argv.release) ? 'styles/[name]_[hash].css' : 'styles/[name].css',
sourceMapQueryStr = (argv.release) ? '-sourceMap' : '+sourceMap',
assets = 'assets/',
dist = 'dist/',
jsLoader,
webpackConfig;
jsLoader = {
test: /\.js$/,
exclude: [ /(node_modules|bower_components)(?![/|\\](bootstrap|foundation-sites))/ ],
loaders: [ 'babel?presets[]='+path.resolve('./node_modules/babel-preset-es2015')+'&cacheDirectory' ]
};
if (argv.watch) { // '--watch' to add monkey-hot
jsLoader.loaders.unshift('monkey-hot');
}
/**
* Process AssetsPlugin output and format it
* for Sage: {"[name].[ext]":"[name]_[hash].[ext]"}
* @param {Object} assets passed by processOutput
* @return {String} JSON
*/
var assetsPluginProcessOutput = function (assets) {
var name,
ext,
filename,
results = {};
for (name in assets) {
if (assets.hasOwnProperty(name)) {
for (ext in assets[name]) {
if (assets[name].hasOwnProperty(ext)) {
filename = name + '.' + ext;
results[filename] = path.basename(assets[name][ext]);
}
}
}
}
return JSON.stringify(results);
};
/**
* Loop through webpack entry
* and add the hot middleware
* @param {Object} entry webpack entry
* @return {Object} entry with hot middleware
*/
var addHotMiddleware = function (entry) {
var name,
results = {},
hotMiddlewareScript = 'webpack-hot-middleware/client?' + qs.stringify({
timeout: 20000,
reload: true
});
for (name in entry) {
if (entry.hasOwnProperty(name)) {
if (entry[name] instanceof Array !== true) {
results[name] = [entry[name]];
} else {
results[name] = entry[name].slice(0);
}
results[name].push(hotMiddlewareScript);
}
}
return results;
};
webpackConfig = {
context: path.resolve(assets),
entry: config.entry,
output: {
path: path.join(__dirname, dist),
publicPath: path.join(config.publicPath, dist),
filename: scriptsFilename
},
module: {
preLoaders: [
{
test: /\.js?$/,
include: path.resolve(assets),
loader: 'eslint'
}
],
loaders: [
jsLoader,
{
test: /\.css$/,
include: path.resolve(assets),
loader: ExtractTextPlugin.extract('style', [
'css?' + sourceMapQueryStr,
'postcss'
])
},
{
test: /\.scss$/,
include: path.resolve(assets),
loader: ExtractTextPlugin.extract('style', [
'css?' + sourceMapQueryStr,
'postcss',
'resolve-url?' + sourceMapQueryStr,
'sass?' + sourceMapQueryStr
])
},
{
test: /\.(png|jpg|jpeg|gif|svg)(\?.*)?$/,
include: path.resolve(assets),
loaders: [
'file?' + qs.stringify({
name: '[path][name].[ext]'
}),
'image-webpack?' + JSON.stringify({
bypassOnDebug: true,
progressive: true,
optimizationLevel: 7,
interlaced: true,
pngquant: {
quality: "65-90",
speed: 4
},
svgo: {
removeUnknownsAndDefaults: false,
cleanupIDs: false
}
})
]
},
{
test: /\.(ttf|eot)(\?.*)?$/,
include: path.resolve(assets),
loader: 'file?' + qs.stringify({
name: '[path][name]_[md5:hash:hex:8].[ext]'
})
},
{
test: /\.woff(2)?(\?.*)?$/,
include: path.resolve(assets),
loader: 'url?' + qs.stringify({
limit: 10000,
mimetype: "application/font-woff",
name: "[path][name]_[md5:hash:hex:8].[ext]"
})
},
// Use file-loader for node_modules/ assets
{
test: /\.(ttf|eot|woff(2)?|png|jpg|jpeg|gif|svg)(\?.*)?$/,
include: /node_modules/,
loader: 'file?' + qs.stringify({
name: 'vendor/[name]_[md5:hash:hex:8].[ext]'
})
}
]
},
resolve: {
extensions: [ '', '.js', '.json' ],
modulesDirectories: [
'node_modules',
'bower_components'
]
},
externals: {
jquery: 'jQuery'
},
plugins: [
new Clean([dist]),
new ExtractTextPlugin(stylesFilename, {
allChunks: true,
disable: (argv.watch === true) // '--watch' disable ExtractTextPlugin
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'Tether': 'tether',
'window.Tether': 'tether'
}),
new webpack.DefinePlugin({
WEBPACK_PUBLIC_PATH: (argv.watch === true) ? JSON.stringify(path.join(config.publicPath, dist)) : false
})
],
postcss: [
autoprefixer({
browsers: [
'last 2 versions',
'android 4',
'opera 12'
]
})
],
eslint: {
failOnWarning: false,
failOnError: true
},
stats: {
colors: true
}
};
// '--watch' to push additional plugins to webpackConfig
if (argv.watch) {
webpackConfig.entry = addHotMiddleware(webpackConfig.entry);
webpackConfig.output.pathinfo = true;
webpackConfig.debug = true;
webpackConfig.devtool = '#cheap-module-source-map';
webpackConfig.plugins.push(new webpack.optimize.OccurenceOrderPlugin());
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
webpackConfig.plugins.push(new webpack.NoErrorsPlugin());
}
// '--release' to push additional plugins to webpackConfig
if (argv.release) {
webpackConfig.plugins.push(new AssetsPlugin({
path: path.join(__dirname, dist),
filename: 'assets.json',
fullPath: false,
processOutput: assetsPluginProcessOutput
}));
webpackConfig.plugins.push(new webpack.optimize.UglifyJsPlugin({
compress: {
'drop_debugger': true
}
}));
webpackConfig.plugins.push(new OptimizeCssAssetsPlugin({
cssProcessor: cssnano,
cssProcessorOptions: { discardComments: { removeAll: true } },
canPrint: true
}));
}
module.exports = webpackConfig;