Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cleaner Themes: A Persil.co.uk Case Study

Cleaner Themes: A Persil.co.uk Case Study

Persil may say “Dirt is Good”, but when it comes to WordPress themes you want to make sure they're as clean as possible, especially when you're building a global network of websites for one of the world's leading washing detergent brands. This case study will take a close look inside the theme and front end code powering the Persil.co.uk website and it's international counterparts.

Using WordPress Multisite, some select plugins, parent and child theming, as well as custom plugins, Sass, and Compass we were able to tackle problems such as: internationalisation, complex page content, and lots of Ajax interactivity. All the while making sure the sites would be easily updatable and extensible by the local content teams, good for SEO, and easily customised for each market.

Fc7368fd45560e1e7401bc80684f5867?s=128

Adam Onishi

April 29, 2014
Tweet

Transcript

  1. @onishiweb Cleaner Themes Persil Case Study

  2. @onishiweb

  3. @onishiweb

  4. @onishiweb 2 to give away

  5. @onishiweb

  6. @onishiweb Code Examples

  7. @onishiweb Beginner / Expert

  8. @onishiweb The project

  9. @onishiweb The project: ‣ WordPress backend ‣ 35+ Markets Worldwide

    ‣ Multi-language support ‣ Customisable per market - features, styling, etc ‣ Manageable by local teams ‣ Integrate with external campaigns
  10. @onishiweb The solution... ‣ Work with a team of developers

    ‣ Modify styles/functionality on a per-site basis ‣ Managed through a simple codebase ‣ Easy to keep up to date and easy to deploy ‣ Extendible when necessary
  11. @onishiweb Tools

  12. ‣ Multisite ‣ Parent/Child Themes ‣ Git ‣ Frontend Tools

    - Sass/Compass/Grunt ‣ Plugins @onishiweb Tools
  13. @onishiweb Multisite

  14. @onishiweb Centrally managed system

  15. @onishiweb Easily create new sites

  16. @onishiweb Got a bit messed up...

  17. @onishiweb Parent/Child Themes

  18. @onishiweb 1 core parent theme

  19. @onishiweb Child themes https://codex.wordpress.org/Child_Themes

  20. ‣ Functions file ‣ Pluggable functions ‣ Post type &

    taxonomy slugs ‣ Mail settings @onishiweb Child theme config
  21. if( ! function_exists('dig_mail_from_address') ) : function dig_mail_from_address( $old ) {

    return 'admin@persil.co.uk'; } endif; add_filter('wp_mail_from', 'dig_mail_from_address'); @onishiweb
  22. function dig_mail_from_address( $old ) { return 'admin@persil.co.uk'; } @onishiweb

  23. @onishiweb Always child theme!

  24. @onishiweb Git

  25. @onishiweb USE IT! http://git-scm.com/book/en/Getting-Started http://gitimmersion.com/ http://alistapart.com/article/get-started-with-git

  26. @onishiweb A successful Git branching model http://nvie.com/posts/a-successful-git-branching-model/

  27. @onishiweb Frontend Tools

  28. @onishiweb Sass/Compass

  29. @onishiweb Sass & Compass benefits ‣ Easier to work in

    collaboration ‣ More modular way of writing styles ‣ Makes working with child themes a breeze ‣ Good for performance ‣ Easily modify base styles
  30. @onishiweb

  31. @onishiweb

  32. @onishiweb Grunt

  33. ‣ JSHint ‣ Concatenation ‣ Minification ‣ Image optimisation ‣

    Compass compliation @onishiweb Grunt tasks
  34. @onishiweb Icon Fonts

  35. @onishiweb http://fontastic.me/

  36. @onishiweb Plugins

  37. @onishiweb Advanced Custom Fields http://www.advancedcustomfields.com/

  38. ‣ Repeater Field ‣ Options Pages ‣ Flexible Content Field

    @onishiweb ACF Add-ons
  39. @onishiweb WordPress Multilingual http://wpml.org/ http://translate-toolkit.readthedocs.org/en/latest/commands/csv2po.html

  40. @onishiweb WordPress SEO (Yoast) https://wordpress.org/plugins/wordpress-seo/

  41. @onishiweb WordPress Social Login http://wordpress.org/plugins/wordpress-social-login/

  42. @onishiweb Content

  43. @onishiweb Custom Post Types

  44. @onishiweb 5 main 3 supporting

  45. @onishiweb Custom Taxonomies

  46. @onishiweb

  47. @onishiweb Configured per market

  48. $count = 1; foreach( $tax_labels as $slug => $labels )

    { $args = array( 'hierarchical' => true, 'labels' => $labels, 'show_ui' => true, 'show_admin_column' => true, 'query_var' => true, 'rewrite' => array( 'slug' => $slug ), ); register_taxonomy( 'dig_product_filter_' . $count, 'dig_product', $args ); $count++; } @onishiweb
  49. @onishiweb Custom Fields

  50. @onishiweb ACF...

  51. @onishiweb Modular content made easy

  52. @onishiweb

  53. @onishiweb $75!

  54. @onishiweb $75 AUD!

  55. @onishiweb The Theme

  56. @onishiweb Theme organisation

  57. @onishiweb Folders are your friend!

  58. /css /javascript /inc /inc/admin /inc/template-tags /templates /template-parts @onishiweb

  59. @onishiweb The template hierarchy extends into subdirectories http://nacin.com/2012/03/29/page-templates-in-subdirectories-new-in-wordpress-3-4/

  60. // For /pages/page-contact.php <?php get_page_template(); ?> // Will return ‘pages/page-contact.php’

    @onishiweb
  61. @onishiweb Templating

  62. @onishiweb Template parts

  63. <?php // Explicit get_template_part('template-parts/content', 'page'); // Dynamic get_template_part('template-parts/loop', dig_current_post_type()); ?>

    @onishiweb
  64. @onishiweb Separating logic from templates

  65. @onishiweb

  66. @onishiweb Custom template tags

  67. if( ! function_exists( 'dig_get_post_type_title' ) ) : function dig_get_post_type_title() {

    if( is_tag() ) { $query = get_queried_object(); return __('Topic: ', 'dirtisgood') . $query->name; } $type_name = dig_current_post_type(); if( '' !== $type_name ) { $post_type = get_post_type_object( $type_name ); return $post_type->labels->name; } } endif; @onishiweb
  68. @onishiweb Custom templates

  69. @onishiweb Best for i18n - no more page-xxxx.php

  70. @onishiweb Ajax

  71. @onishiweb admin-ajax.php http://www.smashingmagazine.com/2011/10/18/how-to-use-ajax-in-wordpress/

  72. // Set up Nonce in the arguments args.nonce = coreData.ajaxData.postUserNonce;

    // Run ajax call $.ajax({ type: 'POST', dataType: 'json', url: coreData.ajaxData.ajaxurl, data: args, success: callback }); @onishiweb
  73. <script type='text/javascript'> /* <![CDATA[ */ var coreData = {"ajaxData":{"ajaxurl":"http:\/\/ www.persil.co.uk\/wp-admin\/admin-

    ajax.php","postUserNonce":"d11736ec4f"}}; /* ]]> */ </script> @onishiweb
  74. wp_enqueue_script( 'core', $javascript_file, 'jquery', '1.1.1', true ); $ajaxData = array(

    'ajaxurl' => admin_url('admin-ajax.php' ), 'postUserNonce' => wp_create_nonce( 'ajax-users-nonce' ), ); wp_localize_script( 'core', 'coreData', $ajaxData ); @onishiweb
  75. add_action('wp_ajax_sort_filter_articles', 'dig_ajax_process_archive'); add_action('wp_ajax_nopriv_sort_filter_articles', 'dig_ajax_process_archive'); @onishiweb

  76. // Set up and send the response $response = json_encode(array(

    'results' => true, 'pages' => $pages, 'data' => $data, )); die( $response ); @onishiweb
  77. @onishiweb I18n and L10n

  78. $labels = array( 'name' => __('Laundry Products', 'dirtisgood'), 'singular_name' =>

    __('Product', 'dirtisgood'), [...] ); <h2><?php _e('Sign in with', 'dirtisgood'); ?></h2> <p class="page-error"> <?php printf( __( 'Sorry, no %s were found.', 'dirtisgood' ), strtolower( dig_get_post_type_title() ) ); ?> </p> @onishiweb
  79. $strings = array( 'close' => __('close', 'dirtisgood'), 'all' => __('All',

    'dirtisgood'), 'both' => __('Both', 'dirtisgood'), [...] ); wp_localize_script( 'core', 'coreData', $localisations ); @onishiweb
  80. @onishiweb Custom plugins

  81. @onishiweb Reusable functionality

  82. @onishiweb Easy to switch on/off

  83. @onishiweb Menu

  84. @onishiweb

  85. @onishiweb Uses custom menus

  86. @onishiweb

  87. @onishiweb

  88. @onishiweb Making use of JavaScript

  89. @onishiweb Universal Navigation

  90. @onishiweb Work in Progress!

  91. @onishiweb Thanks! adamonishi.com twitter.com/onishiweb github.com/onishiweb