This is the Phoogoo Wordpress theme development kit. This is not a framework, no child-themes, no bloatware. Developers can take this theme and modify it directly.
The goal of this kit is to provide common functionality required in most wordpress themes today in a lean and semantically clean format. Below is a quick outline of the functionality a developer can quickly tap into during theme construction.
This kit is also a constant work in progress and forking is encouraged.
( email michael.niles@phoogoo.com for GIT repo access. )
Setup
There are a few preliminary steps before a developer should start modifying this theme.
- Change theme directory name, update screenshot, favicons & iOS badges
- Move _htaccess.txt to root and rename to .htaccess
- Edit & move _humans.txt to root and rename to humans.txt
- Move _robots.txt to root and rename to robots.txt (unless using a plugin such as Yoast SEO)
- Edit lib/less/theme.less: change the variable @theme from demo to theme (or whatever dir that houses your theme specific LESS CSS)
- Review $phoo_config in functions.php
- Delete lib/less/theme.less.cache if it exists before developement
LESS CSS
This theme utilizes the CSS preprocessor LESS. To learn more about LESS, please review the documentation at lesscss.org.
No client-side preprocessors are nessecary, all work is done by the theme via lessphp and cached on the server. There are a few aspects to lessphp that are unique (such as setting variables with php), documentation can be found at leafo.net/lessphp.
Do NOT edit lib/css/theme.css instead edit lib/less/theme.less & lib/less/inc/{theme}/* where {theme} is your theme's less directory (it's "theme" by default).
Poke around lib/less/inc/demo/* to see how the demo theme is styled.
Mobile First
The stylesheets are organized in a mobile-first arrangement. Meaning that media queries are called from bottom-up and that styles are inherited from each set before it. This is so that mobile devices don't download assets they won't end up using, as they do with the traditional top-down approach.
For easy organization you'll find in lib/less/inc/{theme}/responsive/ 4 files; phone.less, tablet.less, desktop.less & print.less.
Conventions
File organization and naming conventions are a work in progress. As they stand now, you'll find every type of asset organized in it's respective directory in lib/.
There is an automated variable that you can use in your LESS that references the path to your theme's root. An example of use:
.class {
background-image: url(@{url}/lib/img/picture.jpg)
}
LESS
- lib/less/ houses the core theme.less file.
all .less includes should be called from the theme.less file.
lib/less/inc/ houses various LESS includes.
lib/less/inc/core/* should not be edited unless you plan on committing a change to the kit's GIT repository.
lib/less/inc/vendor/* houses any vendor-specific css (such as styles that accompany 3rd-party scripts).
lib/less/inc/demo/* houses the styles for the default demo theme.
lib/less/inc/theme/* houses the barebone styles for your custom theme.
lib/less/inc/theme/init.less should contain all your global LESS variables. Useful for making quick changes & adjustments.
lib/less/inc/theme/layout.less should contain all your global structural styling.
lib/less/inc/theme/type.less should contain all your typographic styling.
lib/less/inc/theme/ui.less should contain all your user-interface styling including colors.
CSS
- lib/css/ houses the core theme.css file that the lessphp preprocessor generates. This file should NOT be edited.
Fonts
- lib/fonts/ should house your custom webfonts and icon fonts. These fonts should be requested via @font-face in lib/less/inc/{theme}/type.less
Images
- lib/img/ contains the theme's favicon & iOS badges. This is were you'd place your theme's imagery.
Javascript
- lib/js/ houses your main.js which is your primary custom javascript file, & plugins.js which should contain all the 3rd-party javascript your theme calls for. lib/js/vendor/* houses any vendor-specific css (primarily a local copy of jQuery, and modernizer).
PHP
- lib/php/ contains a few PHP classes for additional functionality
lib/php/core/* should not be edited unless you plan on committing a change to the kit's GIT repository.
lib/php/admin/theme-settings.php is where you can add site-wide options for the client (found in appearance -> site options in WP's admin menu).
lib/php/meta/* houses a simple PHP class for adding custom meta boxes. Do NOT edit. Use the commented structure under Metaboxes in functions.php
SVG
- lib/svg/ houses any SVG objects or filters.
IE
- lib/ie/ contains all IE only assets, including styles, scripts, images and polyfills.
Wrap up list
Aside from the usual items (making sure search engines aren't blocked, etc.) there are a few things specific to this theme that should be tended to before pushing live.
- Set inDevelopement in functions.php to false, and set the appropriate value for cacheBustVersion
- Remove /lib/less/inc/demo
- Remove any fonts & icon fonts not being used in /lib/fonts
- Trim lib/js/vendor/modernizr-.js so that we aren't checking the browser for every capability.
- Minify each 3rd-party javascript in lib/js/plugins.js. A helpful tool can be found at htmlcompressor.com
- Optimize images in lib/img/. A helpful tool can be found at smushit.com
Shrinkwrap
This is a simple organizational convention that can make your life easier. Infact your looking at it right now, this is the structure the whole theme is built upon.
<div id="full-container">
<div class="shrinkwrap">
...
</div>
</div>
Example
Other Notes
The shrinkwrap class inherits it's width & left and right padding from the @site-width & @site-outer-margins variables set in lib/less/inc/{theme}/init.less, however it's built to be flexable and will shrink as the window requires it to.
Grids
Using the .grid() LESS mixin we can quickly and semantically construct unique flexable grid layouts
.grid( @total_columns: 1, @column_span: 1, @gutter_override: @gutter-width );
.replace-grid( @old_total_columns: 1, @new_total_columns: 1, @column_span: 1, @gutter_override: @gutter-width );
Examples
Continuous + Responsive grid
HTML
<ul class="gallery">
<li></li>
...
<li></li>
</ul>
LESS
/* mobile-first */.gallery li {
.grid(2);
}
/* everything else */@media only screen and (min-width: 480px) {
.gallery li {
.replace-grid(2, 4);
}
}
Colspan + nested + responsive grid
Main Content
- 1
- 2
- 3
Aside Content
HTML
<div class="main">
<p>Main Content</p>
<ul class="nested-grid">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
<div class="aside">
<p>Aside Content</p>
</div>
LESS
/* mobile-first */.main,
.aside,
.nested-grid li {
.grid(1);
}
/* everything else */@media only screen and (min-width: 480px) {
.main {
.replace-grid(1, 3, 2);
}
.aside {
.replace-grid(1, 3);
}
.nested-grid li {
.replace-grid(1, 3);
}
}
Other Notes
The .grid() mixin uses ":last-of-type" css selectors, so make sure your grid is wrapped in a container.
Don't worry about IE, it's served a polyfill.
Icons
Using the .icon() mixin, we can easily add icons from iconfonts to our elements. Icon fonts are 100% customizable with CSS, and scale crystal clear to any pixel density.
.icon( @icon: attr('data-icon'), @icon-font: 'icons' );
Examples
Inline icon before element: Pure CSS
HTML
<span class="twitter">
Follow us on Twitter
</span>
LESS
.twitter {
&:before {
.icon('\F099', 'icons');
}
}
Inline icon after element: Data-attribute method
HTML
<span class="facebook" data-icon="">
Friend us on Facebook
</span>
LESS
.facebook {
&:after {
.icon();
}
}
Linked Icon with text hidden
HTML
<a class="like" href="#liked">
<span>Like Us!</span>
</a>
LESS
.like {
&:after {
.icon('\F164');
}
span {
.visuallyHidden();
}
}
Other Notes
It's best practice to round up all of your project's icons, export them individually as svg's, and create a custom icon-font over at http://icomoon.io/app/
Here's a set of icons included for testing: Fontawesome Index
*** Don't include icons your project won't be using as it will increase load-time.
If you find you need to convert unicode characters between formats (html entities, css escapes, etc.) this is a very helpful tool http://rishida.net/tools/conversion/
Modals
We can quickly bind a modal to any element by using the data-modal attribute.
<div data-modal="..."></div>
Examples
Image Modal
HTML
<img src="http://placekitten.com/200/200" data-modal="<img src='http://placekitten.com/400/400' />" />
Video Modal
HTML
<img src="http://placekitten.com/200/200" data-modal="<?php echo video(array('hash'=>'0Bmhjf0rKe8')); ?>" />
Gallery Modal
HTML
<img src="http://placekitten.com/200/200" data-modal="<img src='http://placekitten.com/400/400' />" data-gallery="1" />
<img src="http://placekitten.com/200/200" data-modal="<img src='http://placekitten.com/400/400' />" data-gallery="1" />
Other Notes
When using the gallery modal, the index of the clicked gallery item must be relative to it's other gallery neighbors. if you wrap the item in a parent container, the index will always be returned as one.
To avoid this, make sure you place the actual data-modal and data-gallery attributes on the parent. See the example below.
<ul>
<li data-modal="<img src='http://placekitten.com/400/400' />" data-gallery="1">
<img src="http://placekitten.com/200/200" />
</li>
</ul>
Breadcrumbs
Built in, there's an extremely customizable breadcrumb generator. Just call the phoo_crumbs() PHP function.
<?php phoo_crumbs($title = '', $end = false, $separator = '»'); ?>
Examples
Custom seperator & prefix
HTML
<div class="crumbs">
<?php phoo_crumbs('Crumbs:', true, '/'); ?>
</div>
LESS
.crumbs {
&, a, .seperator, .title {
color: blue;
}
}
No prefix & Omit current page title
HTML
<div class="crumbs">
<?php phoo_crumbs(); ?>
</div>
LESS
.crumbs {
&, a {
color: blue;
}
}
Sharing
We've got simple, stylable sharing links built in for google+, facebook, & twitter. Use the phoo_share() PHP function.
<?php phoo_share(); ?>
Examples
Plain text links
HTML
<div class="share">
<?php phoo_share(); ?>
</div>
LESS
.share {
ul {
margin: 0;
padding: 0;
}
li {
display: inline;
margin: 0;
padding: 0 1em 0 0;
}
}
Icon links + hidden text
HTML
<div class="share">
<?php phoo_share(); ?>
</div>
LESS
.share {
/*duplicate css from above*/
.fb a:before {
.icon('\F082');
}
.ggl a:before {
.icon('\F0D4');
}
.twtr a:before {
.icon('\F081');
}
span {
.visuallyHidden();
}
}
Form Elements
Simple pre-styled form elements that can easily and quickly be skinned into any project.
Buttons
HTML
<a class="button" href="#button">My Link</a>
<button>My Button</button>
<input type="submit" value="My Submit" />
Other Notes
.button, button, & input['type=submit'] all have the .btn() mixin applied by default in /lib/less/inc/{theme}/ui.less.
Text Inputs with Placeholders + invalid entries
HTML
<label class="half">Text</label>
<label class="half">Email</label>
<input class="half" type="text" placeholder="placeholder text..." />
<input class="half" type="email" placeholder="address@domain.com" />
<label class="half">Tel</label>
<label class="half">Password</label>
<input class="half" type="tel" pattern="[0-9]{3} [0-9]{3} [0-9]{4}" placeholder="--- --- ----" />
<input class="half" type="password" placeholder="enter your password" />
<label>Date</label>
<input type="date" placeholder="mm/dd/yyyy" />
<label>Time</label>
<input type="time" placeholder="--:--:--" />
<label>Textarea</label>
<textarea placeholder="this is required..." required></textarea>
Other Notes
All input types & textarea (excluding submit, checkbox, & radio) have the .input() mixin applied by default in /lib/less/inc/{theme}/ui.less.
Checkboxes & Radios
HTML
<input type="checkbox" id="demo_checkbox" />
<label for="demo_checkbox">Custom Checkbox</label>
<input type="radio" name="demo_radio" id="demo_radio_01" />
<label for="demo_radio_01">Custom Radio 01</label>
<input type="radio" name="demo_radio" id="demo_radio_02" />
<label for="demo_radio_02">Custom Radio 02</label>
Other Notes
Checkboxes & Radios both have the .toggle-input() mixin applied by default in /lib/less/inc/{theme}/ui.less.
Custom Checkboxes & Radios
LESS
input[type=checkbox] + label,
input[type=radio] + label {
display: block;
&:before {
border: none;
background-color: transparent;
font-family: icons;
}
}
input[type=checkbox] {
+ label:before {
content: '\F09C';
}
&:checked + label:before {
content: '\F023';
}
}
input[type=radio] {
+ label:before {
content: '\F026';
}
&:checked + label:before {
content: '\F028';
}
}
Other Notes
Checkboxes & Radios both have the .toggle-input() mixin applied by default in /lib/less/inc/{theme}/ui.less.
Thumbnails
Quick and easy thumbnail fetch with PHP using the get_thumb() function.
<?php get_thumb($size = 'thumbnail', $fallback_image_ID = null, $echo = true); ?>
Examples
Grabbing an existing 150x150 thumbnail from featured image
HTML
<div class="thumb">
<?php get_thumb(); ?>
</div>
No Feature Image exists, fall back to default + Medium size
HTML
<div class="thumb">
<?php get_thumb('medium', 12); ?>
</div>
No Feature Image exists, no fallback specified.
HTML
<div class="thumb">
<?php get_thumb(); ?>
</div>
Other Notes
When no feature image exists & no fallback is specified, the image from /lib/img/default.jpg is fetched.
Change it if you feel let down.
Galleries
Fetching a gallery from a post's media using phoo_gallery() function.
<?php phoo_gallery($postID = $post->ID, $size = 'thumbnail'); ?>
Example
Display gallery if post has media.
HTML
<?php phoo_gallery(); ?>
LESS
.gallery-grid {
li {
...
}
a {
...
&:after {
...
}
}
img {
...
}
}
Other Notes
Responsive out of the box. No styling required. phoo_gallery() will not render anything if the post has no media attached; it will also ignore the featured image.
Excerpts
Quickly fetch and customize a post's excerpt with the phoo_excerpt() PHP function.
<?php phoo_excerpt($length = 20, $text = null, $letters = false, $echo = true); ?>
Examples
Default usage. Cuts length at 20 words.
HTML
<?php phoo_excerpt(); ?>...
Cut length at 20 characters.
HTML
<?php phoo_excerpt(20, null, true); ?>...
Excerpt'ify from another source + cut length at 10 characters.
HTML
<?php phoo_excerpt(10, get_the_title(), true); ?>...
Mixins
A Quick reference of the other available mixins.
Placeholder
Defines placeholder color for inputs.
.placeholder(@color);
Greyscale
Forces an image to greyscale. Cross-browser support with IE filters, SVG filters, & CSS3.
.greyscale();
Remove Greyscale
Resets all filters to remove greyscale from image.
.remove-greyscale();
Prevent Highlight
Prevents element from being highlighted. Good for UI elements.
.prevent-highlight();
Image Replacement
Wipes element of text to be replaced by an image in a SEO friendly way. Inspired by zeldman: http://goo.gl/gdVJI
.ir();
Completely Hidden
Hide from both screenreaders and browsers: h5bp.com/u
.hidden();
Visually Hidden
Hide only visually, but have it available for screenreaders: h5bp.com/v
.visually-hidden();
Clearfix
Contain floats: h5bp.com/q
.clearfix();
Other Mixins
This theme also includes all mixins from elements.less
WP Helpers
A Quick reference of the custom wordpress helpers.
Is Post Type
Matches current post against postType. Better to use is_singular( $post-type ) if you're able.
<?php is_post_type($type, $postID = $post->ID); ?>
Is Blog
Returns true if current post is blog-related. Use is_home() to check if it's the blogroll page.
<?php is_blog(); ?>
Is Descendant
Returns true if current page is descendant of specified page. $parent parameter can be slug or ID.
<?php is_descendant($parent); ?>
Quick Meta
Echo meta, get meta, & check if meta exists.
<?php
meta($meta);
get_meta($meta);
meta_exists($meta);
?>
Get Posts Page URL/Title
Gets page URL or Title that's responsible for housing posts when manually set. $data parameter can be 'url' or 'title'.
<?php echo get_posts_page($data); ?>
Youtube/Vimeo fetch
Can get video or image assets from youtube or vimeo from url or video hash. $array parameter has the following options:
'hash' => video url or hash
'type' => only required if hash was given instead of url. options: 'youtube', 'vimeo'. Defaults to 'youtube'
'action' => options 'get_thumb', 'get_image', 'get_hash', 'get_type', 'get_video'. Defaults to 'get_video'
'width' => integer: video width in px
'height' => integer: video height in px
<?php echo video($array); ?>