Jaime Martínez | @jmslbam | #wpmeetup010 | 10 feb 2014
Start here
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
FireFox and Web Developer + FireBug
Chrome and Web Developer + Chrome tools
Internet Explorer
+ developer toolbar
or
modern.ie || ievms
Online hosting
Otherwise
Local with Homebrew and php-osx #
Recommended ++
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 );
}
display_errors = On;
error_reporting = E_ALL | E_STRICT;
Also install Xdebug
wp-content/themes/*
Themes consist of a collection of HTML, CSS, PHP and probably JavaScript files
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
*/
don't put everything in this file... organize it!
Too enqueue scripts and styles (see last slides)
// Most important call in header.php
wp_head();
// Most important call in footer.php
wp_footer();
The Template file used to render the Archive Index page for a Custom Post Type
archive-{post_type}.php
– If the post type is product
, WordPress will look for archive-product.php
.archive.php
index.php
Only for pages, needs plugin for CPT's
<?php
/*
Template Name: Contact
*/
?>
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 use page-recent-news.php
page-{id}.php
– If the page ID is 6, WordPress will look to use page-6.php
page.php
index.php
Please don't use 2 & 3
get_template_part
get_template_part
get_template_part
get_template_part
get_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>
<?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>
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>
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 } ?>
<?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>
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;
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' );
}
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 ); ?>" />
Child themes are themes that piggy-back on another (full) theme.
It only overrides the bare necessary
Updates!
One theme to rule them all...
Payed theme builders don't take care backwards compatibility
woocommerce/templates/cart/cart.php
to
your-theme/woocommerce/cart/cart.php
Or use hooks to add / move content
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' );
}
//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();
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 );
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' );
Prevent XSS attacks, escape your data!
or stuff like
absint( $int )
sanitize_title( $title )
$wpdb->prepare(...)
wp_safe_redirect($location, $status = 302)