Theme development
Jaime Martínez | @jmslbam | #wpmeetup010 | 10 feb 2014
Hola
Jaime Martinez
btw, thank for the time & the drinks ;)
And you are?
Designers?
Account and projectmanager?
Site owners?
Shop owners?
Overall thought
DRY #
Don't repeat yourselfDRY results in flexible and maintainable software
Let me seduce you to the
proper theming side
So new to WordPress and themes?
Start here
kthxbye
What do you need?
Some knowledge of HTML & PHP comes in handyand some developertools
Handbook *
Intro, just read this
http://codex.wordpress.org/WordPress_Semantics#Terminology_Related_to_Design
and then the handbook :)
http://make.wordpress.org/docs/theme-developer-handbook/
*Read back at home or the office
Tools and skills *
Editor
Browsers
FireFox and Web Developer + FireBug
Chrome and Web Developer + Chrome tools
Internet Explorer
+ developer toolbar
or
modern.ie || ievms
The setup *
Online hosting
Otherwise
Local with Homebrew and php-osx #
Recommended ++
Learn to debug
Turn on debug info! #
wp-config.php
define( 'WP_DEBUG', true );
if ( WP_DEBUG ) {
define( 'SCRIPT_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', true );
@ini_set( 'display_errors', 1 );
}
Turn on debug info!
php.inidisplay_errors = On;
error_reporting = E_ALL | E_STRICT;
Also install Xdebug
Thanks Barry!
Development plugins
So where's the party?
User proper themes
_sRoots
Genesis Framework #
Bones
Hybrid
Thematic
Theme anatomy
wp-content/themes/*
Themes consist of a collection of HTML, CSS, PHP and probably JavaScript files
- style.css
- functions.php
- index.php
- ...
style.css
Must have!
/*
Theme Name: Roots
Theme URI: http://roots.io/
Description: Roots is a WordPress starter theme based on HTML5 Boilerplate & Bootstrap.
Version: 6.5.2
Author: Ben Word
Author URI: http://benword.com/
License: MIT License
License URI: http://opensource.org/licenses/MIT
*/
functions.php
don't put everything in this file... organize it!
functions.php
Theme anatomy #
index.php calls
- get_header();
-
The Loop
- get_sidebar();
- get_footer();
Theme anatomy
Theme anatomy
Too enqueue scripts and styles (see last slides)
// Most important call in header.php
wp_head();
// Most important call in footer.php
wp_footer();
Template hierarchy
Say WHUT? #
Template hierarchy
Custom Post Types #
The Template file used to render the Archive Index page for a Custom Post Type
-
archive-{post_type}.php
– If the post type isproduct
, WordPress will look forarchive-product.php
. -
archive.php
-
index.php
Custom template
Only for pages, needs plugin for CPT's
<?php
/*
Template Name: Contact
*/
?>
Template hierarchy Page #
The Template file used to render a static page (page
post-type)
-
Custom template file
– The Page Template assigned to the Page. See get_page_templates(). -
page-{slug}.php
– If the page slug is recent-news, WordPress will look to usepage-recent-news.php
-
page-{id}.php
– If the page ID is 6, WordPress will look to usepage-6.php
-
page.php
-
index.php
Please don't use 2 & 3
Get a template part - #
DRY
get_template_part
get_template_part
get_template_part
get_template_part
get_template_part
get_template_part
Get a template part
get_template_part
<?php
/*
Template Name: Front page
*/
?>
<div class="main">
<?php get_template_part('templates/post', 'highlighted'); // The same ?>
<?php get_template_part('templates/post', 'latest'); ?>
</div>
<div class="sidebar">
<?php get_template_part('templates/event', 'highlighted'); ?>
<?php
// Remember that on the front_page the global query contains the latest x posts else use get_template_part('templates/post', 'latest');
get_template_part('templates/event', 'latest');
?>
</div>
get_template_part
get_template_part
<?php
/*
Template Name: News
*/
?>
<div class="main">
<?php get_template_part('templates/post', 'highlighted'); // The same ?>
</div>
<div class="sidebar">
<?php get_template_part('templates/post', 'latest'); ?>
<p class="list-view-all-link">
<a class="read-more" href="<?php echo $archive_page; ?>"><?php echo __("More news", "sharedstories"); ?></a>
</p>
<?php endif; ?>
</div>
get_template_part
get_template_part
templates/post-highlighted.php
<article <?php post_class('highlighted'); ?>>
<header>
<?php get_template_part('templates/post', 'meta'); ?>
<h2 class="entry-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
</header>
<?php
if ( has_post_thumbnail() ) :
the_post_thumbnail('medium'); // wrapper link added in custom.php for all post_thumbnail
endif;
?>
<div class="entry-summary">
<?php echo ll_excerpt_by_id( get_the_ID(), POST_EXCERPT_LENGTH , roots_excerpt_more( true ) ); ?>
</div>
</article>
get_template_part
templates/post-meta.php
<?php if( is_front_page() ) { ?>
<?php get_template_part('templates/entry-meta', 'time'); ?>
<?php } else {
$post_taxonomies = get_object_taxonomies( $post ); ?>
<p class="meta">
<?php get_template_part('templates/entry-meta', 'time'); ?>
<?php echo get_the_term_list( get_the_ID(), $post_taxonomies, ' - <span class="lc">', '</span>, <span class="lc">', '</span>' ); ?>
- <span class="byline author vcard"><a href="<?php echo get_author_posts_url(get_the_author_meta('ID')); ?>" rel="author" class="fn"><?php echo get_the_author(); ?></a></span>
</p>
<?php } ?>
get_template_part
<?php $d = "d M";?>
<span class="date">
<time class="updated" datetime="<?php echo get_the_time('c'); ?>"><?php echo get_the_date( $d ); ?></time>
</span>
Render a template part ++
Like every proper template engine this lets you pass $args to the template file #
/templates/contact-persons.php
$people = '';
foreach ($loc_people as $key => $person) {
$people .= ll_get_template_part('templates/contact-person', array( 'person' => (object)$person['ss_contact_person'], 'return' => true ), false ) ;
}
echo $people;
Even widgets can have templates
Templates in widgets
Templates in widgets #
Simply include the templates from plugins/your-plugin/widget.php
public function form( $instance ) {
wp_enqueue_media();
$defaults = array( 'image-id' => false, 'image-preview' => '', 'url' => false );
$instance = wp_parse_args( $instance, $defaults );
$image_preview = esc_url_raw( $instance['image-preview'] );
$image_id = absint( $instance['image-id'] );
$image_thumbnail = $this->get_image_preview( $image_id );
$url = esc_url_raw( $instance['url'] );
// Display the admin form
include( plugin_dir_path(__FILE__) . 'views/admin.php' );
}
Templates in widgets
plugins/your-plugin/views/admint.php
<!-- This file is used to markup the administration form of the widget. -->
<p class="abn-sidebar-widget-image"><?php echo $image_thumbnail; ?></p> <p> <a class="ll-sidebar-widget-image-button button button-secondary" data-uploader_title="Select banner" >Select image</a> </p> <p> <label for="<?php echo $this->get_field_name('url'); ?>">Link</label> <input class="ll-sidebar-widget-url widefat" type="text" name="<?php echo $this->get_field_name('url'); ?>" value="<?php echo esc_attr($url); ?>" /> </p> <input class="ll-sidebar-widget-image-preview" type="hidden" name="<?php echo $this->get_field_name('image-preview'); ?>" value="<?php echo esc_attr( $image_preview ); ?>" /> <input class="ll-sidebar-widget-image-id" type="hidden" name="<?php echo $this->get_field_name('image-id'); ?>" value="<?php echo esc_attr( $image_id ); ?>" />
Overwriting stuff
Child theme #
Child themes are themes that piggy-back on another (full) theme.
It only overrides the bare necessary
- functions.php loads before and in addition to it's parent them
- No child theme limbo
Why child themes?
Updates!
One theme to rule them all...
Why not child themes?
Payed theme builders don't take care backwards compatibility
Overwriting WooCommerce
named /woocommerce keeping the same file structure
woocommerce/templates/cart/cart.php
to
your-theme/woocommerce/cart/cart.php
Or use hooks to add / move content
Overwriting WooCommerce
Overwriting Woocommerce
in your-child-theme/functions.php
// First mimic WooCommerce style loading from theme-actions.php
if ( ! is_admin() ) { add_action( 'wp_enqueue_scripts', 'woo_load_frontend_css', 20 ); }
function woo_load_frontend_css () {
// Mimic WooCommerce style loading - theme-actions.php
wp_register_style( 'woo-theme-stylesheet', get_template_directory_uri() . '/style.css' );
wp_register_style( 'woo-layout', get_template_directory_uri() . '/css/layout.css' );
wp_enqueue_style( 'woo-theme-stylesheet' );
wp_enqueue_style( 'woo-layout' );
// Mimic Woocommerce style loading - theme-woocommerce.php
wp_register_style( 'woocommerce', esc_url( get_template_directory_uri() . '/css/woocommerce.css' ) );
wp_enqueue_style( 'woocommerce' );
// Manualy load Fabulous Women style
wp_enqueue_style('theme-stylesheet', get_stylesheet_directory_uri().'/assets/less/style.less');
//wp_register_style( 'theme-stylesheet', get_stylesheet_uri() );
wp_enqueue_style( 'theme-stylesheet' );
}
Again DRY
Reuse The Events Calendar #
//Let's use all code from tri.be and no custom!
$args = array(
'posts_per_page' => 3,
);
$query = TribeEventsQuery::getEvents( $args, true );
if ( $query->tribe_is_event && $query->posts ) : //setup_postdata( $post );
$query->the_post();
echo '<article class="hentry tribe-event">';
tribe_get_template_part( 'list/single', 'event' ); // This way all views will be the same ;)
echo "</article>";
endif;
// Clean up
$event = $query = $highlighted_event = false;
wp_reset_postdata();
Extra goodies
Conditional Tags #
Checks where you are on the site
// function.php ;)
function ll_conditional_custom_category_limit( $query ) {
if ( is_admin() || ! $query->is_main_query() )
return;
if ( is_archive('specific-term') ) {
$query->set( 'posts_per_page', 1 );
return;
}
}
add_action( 'pre_get_posts', 'll_conditional_custom_category_limit', 1 );
Enqueue scripts and styles #
Why?
Caching plugins
Minify plugins
Unload stylesheets and scripts from plugins
/**
* Enqueue scripts and styles.
*/
function _s_scripts() {
wp_enqueue_style( '_s-style', get_stylesheet_uri() );
wp_enqueue_script( '_s-navigation', get_template_directory_uri() . '/js/navigation.js', array(), '20120206', true );
if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
wp_enqueue_script( 'comment-reply' );
}
}
add_action( 'wp_enqueue_scripts', '_s_scripts' );
Security #
Prevent XSS attacks, escape your data!
- esc_url
- esc_html
- esc_attr
- etc…
or stuff like
absint( $int )
sanitize_title( $title )
$wpdb->prepare(...)
wp_safe_redirect($location, $status = 302)
Tips and tricks *
Use the WordPress API's #Coding Standards
Analyse other peoples work
Read some nice websites like http://www.poststat.us
Follow the WordPress Devel Twitter account
Follow developers like Nacin or ?
Tools and skills II *
GIT
CMD
oh-my-zsh & off course WP-CLI ^^
rly kthxbye
Theme development
By Jaime Martinez
Theme development
- 13,969