SlideShare a Scribd company logo
1 of 39
The HirshHorn Theme

           How I created it

Snippets of code and techniques I used
Credits

 Client: Hirshhorn Museum and Sculpture Garden
 ,          Smithsonian, Washington, D.C.

 Design: Bruce Mau Design


 Media Agency: Art & Science (formerly Juice).
   Technical director: Spencer Saunders
   WordPress coding: Paul Bearne
This might not be the only or best
way!
 What you will see is how I solved the problems at
 the point in time (Sept 2011) when I did this
 project.

 There is a lot of WordPress code in this talk; I am
 assuming that you can read and understand the
 code!

 I am using code snippets so that I can get them
 on the slides, so not all the comments or code are
 shown!
Notes

 At the end I am going to ask what you found the
 most useful

 Slides @ http://www.slideshare.net/pbearne
Overview Demo
Wire frame Layout

                      menu




Prev page …        Current page   Next page …




                      footer

                      Screen
Viewsource
<body class="single single-collection postid-1349">
<div id="wrapper" class="hfeed">
   <div id="header">
       Standard WP menu header
   </div><!-- #header-->
  <div id="main">
      <div id="container">
         <div id="content">
             <div class="entry-content" id="makeMeScrollable">
               <div id="detail-of..." data-id="7639" title="Detail of..."
                       class="hhh_T_6 jsf_LoadViaAjax post-7639
                                  collection type-collection status-publish hentry" ></div>
            <div id="..." data-id="3734" title="...“
                       class="hhh_T_3 jsf_LoadViaAjax post-3734
                                  collection type-collection status-publish hentry"></div>
                                                        ......
            </div>
         </div>
      </div>
  </div>
</div>
</body>
<div id="home" data-id="1349" title="Home"
       class="hhh_T_7 jsf_Loaded post-1349
                     collection type-collection status-publish
hentry"
       <div id="page10" class="jst_BoxContaner
hhh_template10">
              <div class="hhh_link hhh_box13 hhh_item_1">
                     <a href="http://link to bio">
                             <img src="...." /></a>
              </div>
              <div class="hhh_box2 hhh_item_2">
                     <h4>Headline text</h4>
                     <p>Random text</p>
              </div>
              <div class="hhh_videoInline hhh_box8
hhh_item_3">
                     http://youtu.be/DeYZVBzty0w
              </div>
The scrolling plugin
 http://www.smoothdivscroll.com (forked version)


$(document).ready(function () {
     $("#makeMeScrollable").smoothDivScroll({
     mousewheelScrolling: "allDirections",
     manualContinuousScrolling: true,
     autoScrollingMode: "onStart" });
});

                            Note: not all the settings I used are shown
Changes to smoothdevscroll
swapLastToFirst: function(){
 var self = this, el = this.element, o = this.options;
  el.data("swappedElement", el.data("scrollableArea")
       .children(":last").detach());

el.data("scrollableArea").prepend(el.data("swappedElem
ent"));
  el.data("scrollWrapper")
        .scrollLeft(el.data("scrollWrapper")
        .scrollLeft() + el.ata("swappedElement")
        .outerWidth(true));
el.data("getNextElementWidth", true);
el.data("enabled", true);
self._showHideHotSpots();
Changes to smoothdevscroll
_updateHash : function(){
var self = this, el = this.element, o = this.options, allBoxContaners=[], CurrentScrollLeft, currentDivId = 0

$('#makeMeScrollable
.scrollableArea').children('div').each(function(index,element){
allBoxContaners.push([$(element).attr('id'), Math.round(
$(element).position().left)])
});
CurrentScrollLeft = $(".scrollWrapper").scrollLeft()
if(allBoxContaners.length > 0){
                  while(allBoxContaners[currentDivId][1] < CurrentScrollLeft -
                            ($(window).width()/2)+100 ){
                           currentDivId ++;
             }
             var wall = allBoxContaners[i][0]
             if ($.bbq.getState("collection") != wall){
                           $.bbq.pushState({collection : wall });
                           }
Keeping state and bookmarks

www.hirshhorn.si.edu/collection/home/#collection=home


#collection=doug-aitken-2
&detail=http%3A//www.hirshhorn.si.edu/bio/doug-aitken-interviews/
&title=Doug+Aitken+Interviews
JQUERY BBQ: BACK BUTTON & QUERY
LIBRARY

 HTTP://BENALMAN.COM/PROJECTS/JQUERY-BBQ-PLUGIN


// PUSH THIS URL "STATE" ONTO THE HISTORY HASH.
$.BBQ.PUSHSTATE({ URL: HREF });

$(WINDOW).BIND( "HASHCHANGE", FUNCTION(E) {
      PUT THE ACTION CODE HERE
}

$(WINDOW).TRIGGER( "HASHCHANGE" );
Over riding the menu URLs
jQuery('#menu a').live('click', function(e) {
   var href = this.href;
   // does the clicked URL and current URL have '/collection/' in
the path?
   if (href.indexOf('/collection/') > 0 &&
document.URL.indexOf('/collection/') > 0){
          var clickId = href.toLowerCase().split('/');
           // remove any current state
          jQuery.bbq.removeState("wall", "title", "detail");
          // and set new state
          jQuery.bbq.pushState({ collection: clickId });
          // stop any other on-clicks
          e.stopImmediatePropagation();
          return false;
    }
Example hashchange function
jQuery(window).bind("hashchange", function(e) {
          collectionURL = jQuery.bbq.getState("collection");
          // try to get an title from somewhere.
          title = jQuery.bbq.getState("title") ? jQuery.bbq.getState("title")
                              : jQuery('#' + collectionURL).attr('title');
          document.title = title;
          if (undefined === collectionURL) {
                     collectionURL = jQuery('.jsf_Loaded').attr('id');
          }
jQuery("div#makeMeScrollable").smoothDivScroll("scrollToElement",
"id", collectionURL);
}
Example wall fragment


<div class="hhh_link hhh_box13 hhh_item_1">
         <a href="http://www.hirshhorn.si.edu/collection/dark-
matters/">

              <img src="...." />
         </a>
</div>
Example wall click action
// add the scroll to action to wall links
jQuery('.hhh_link a').on('click', function(e) {
           var clickId = this.href.toLowerCase().split('/');
           var l = clickId.length
           if ( clickId[l-1].length > 1){
                        var         scrollToId = clickId[l-1]
           }else{
                        var         scrollToId = clickId[l-2]
           }
jQuery("div#makeMeScrollable").smoothDivScroll("scrollToElement", "id",scrollToId);
// stop any other onclicks
e.stopImmediatePropagation()
return false;
});

                Note: no hashchange this is done in the move finished callback from
                                                                   smoothDivScroll
Using a menu to store the order




register_nav_menu( „collection‟, 'Select the slider content
menu.');
Collection page PHP
// get the menu object for theme menu location “collection”
$menu_items =
wp_get_nav_menu_items($locations['collection';]);

// loop the menu object again to insert the current page and
update the div before and 4 dev‟s after so that content we
loaded on page load

foreach ( (array) $menu_items as $key => $menu_item ) {
           $title = $menu_item->title;
           $url = $menu_item->url;
           $id = $menu_item->object_id;
           $templateId= 'hhh_T_'.get_post_meta($id, 'hhh_template_Id',
true).' ';
           $slug = basename(get_permalink($id));
// is this post in the menu the current post
if ($post->ID == $id) {
           Next slide……
Collection page PHP
if ($post->ID == $id) {
          //check it not a single post to handle preview
          if(count($array_of_divs)>0){
                               $last_id = $array_of_divs[count($array_of_divs)-
1][0];
          $div_text = '<div id="'.basename(get_permalink($last_id)).'"
                    title="'.$last_id.'" class="'.$templateId.implode("
          ",get_post_class("jsf_ajaxOnLoad",$last_id)).'" ></div>' ;

          array_pop($array_of_divs); // remove the last empty div
          array_push( $array_of_divs , array($last_id , $div_text) );
           // add it back in with extra class "jsf_ajaxOnLoad"
          } // load the content into a div
          $div_text = '<div id="'.basename(get_permalink($id)).'" title="'.$id.'"
class="'.$templateId.'jsf_Loaded '.implode(" ",get_post_class("",$id)).'"
>'.get_the_content().'</div>' ;
          $jsf_ajaxOnLoad = 5;
}else{
Collection page PHP
}else{
       if ($jsf_ajaxOnLoad > 0){ // 4 div after the loaded
content
                $jsf_ajaxOnLoad -- ;
                $extra_class_test =
$templateId."jsf_ajaxOnLoad ";
       }else{
                $extra_class_test =
$templateId."jsf_LoadViaAjax ";
       }
       $div_text = '<div
id="'.basename(get_permalink($id)).'" title="'.$id.'"
class="'.$extra_class_test.implode("
",get_post_class("",$id)).'" ></div>' ;
Collection page PHP
<div class="entry-content" id="makeMeScrollable">
       <?php
       foreach ( (array)$array_of_divs as $jsf_div){
             echo($jsf_div[1]);
             }
       ?>
</div><!-- .entry-content -->
Now to call AJAX in WordPress

URL: /wp-admin/admin-
ajax.php?action=show_content_ajax_call


add_action('wp_ajax_show_content_ajax_call',
array( $this, 'jsf_show_content_ajax'));

add_action('wp_ajax_nopriv_show_content_ajax_c
all', array( $this, 'jsf_show_content_ajax'));
Content fetch AJAX PHP function
function jsf_show_content_ajax($id){
       $postID = $_POST['postID'];
       $content_post = get_post($postID);
       $content = $content_post->post_content;
       $content = apply_filters('the_content', $content);
       $jsonpost = array();
       $jsonpost["id"] = $postID;
       $jsonpost["slug"] = basename(get_permalink($postID)
       $jsonpost["content"] = str_replace(']]>', ']]>', $content);
       header( 'Content-Type: application/json' );
       echo json_encode($jsonpost);;
       exit;
}
Content fetch AJAX function
scrollerRightLimitReached: function() {
    $("div#makeMeScrollable").smoothDivScroll("swapFirstToLast");
    if($('#makeMeScrollable .scrollableArea').children(":last").html().length <= 1){
            var id = $('#makeMeScrollable .scrollableArea').children(":last").attr("id")
            $.ajax({
                 url:"/wp-admin/admin-ajax.php",
                 type:'POST',
                 dataType: 'json',
                 data:'action=show_content_ajax_call&postID='+$('#'+id).attr("title")+'&t=3&slu
+ id,
                 success:function(results){// load into div
                       $('#' + results['slug']).html(results['content']);
                       $('#' + results['slug']+' .jst_BoxContaner').hide().fadeIn();;
                       $('#' + results['slug']).removeClass('jsf_ajaxOnLoad');
                 }
            })
        }
}
Custom content in TinyMCE
TinyMCE editor css

Create a editor-style.css file in your theme root
add_editor_style();

Tip: use the same style sheet in the theme

wp_register_style('jsf_BoxStyles', get_stylesheet_directory_uri().'/editor-
style.css');
wp_enqueue_style( 'jsf_BoxStyles')


http://codex.wordpress.org/Function_Reference/add_editor_style
Injecting code into the TinyMCE
editor
 Server side
add_filter('default_content', 'my_editor_content');
function my_editor_content( $content ) {
      $content = "If you enjoyed this post, make sure to subscribe to my
rss feed.";
      return $content;
}


 Client side
var jsf_ed = tinyMCE.activeEditor;
jsf_ed.selection.select(jsf_ed.getBody(), true);
window.send_to_editor(“<div>content);
How to add button to tinyMCE editor



// Add only in Rich Editor mode
if ( get_user_option('rich_editing') == 'true') {
         add_filter("mce_external_plugins",
"add_hhh_custom_tinymce_plugin");
         add_filter('mce_buttons', register_hhh_custom_button');
}
How to add button to tinyMCE editor

function register_hhh_custom_button($buttons) {
       array_push($buttons, "|", "hhh_highlight");
       return $buttons;
}

function add_hhh_custom_tinymce_plugin($plugin_array)
{
       $plugin_array['hhh_highlight'] =
get_stylesheet_directory_uri().'/mce/editor_plugin.js';
       return $plugin_array;
}
editor_plugin.js
(function() {

                tinymce.create('tinymce.plugins.hhh_highlightPlugin', {
                init : function(ed, url) {            ed.addCommand('mceHighlight', function() {
                                        ed.windowManager.open({
                                        file : url + '/set_behavior.htm',
                                        width : 400,height : 600 ,inline : 1
                            }, {plugin_url : url});
                });
            ed.addButton('hhh_highlight', {title : 'Highlight', cmd : 'mceHighlight', image:
url + '/hhhicon.gif' });
                },
           getInfo : function() {return {longname : 'Set Behavior',author : 'Paul
Bearne',authorurl : 'http://www.bearne.ca',infourl :
'http://www.thejuiceagency.com',version : tinymce.majorVersion + "." +
tinymce.minorVersion              };
                }
                });
tinymce.PluginManager.add('hhh_highlight', tinymce.plugins.hhh_highlightPlugin);
})();
How to add button to full screen
editor
function hhh_fullscreen_buttons($buttons){
   $buttons[] = 'separator'; // add a separator
   $buttons['hhh_highlight'] = array(
        'title' => __('Highlighter'), // Title of the button
        'onclick' =>
"tinyMCE.execCommand('mceHighlight');",                 'both' =>
false// Show on visual AND html mode
        );
        return $buttons;
}
add_filter( 'wp_fullscreen_buttons',
'hhh_fullscreen_buttons' );
Slides @ http://www.slideshare.net/pbearne
How to read from TinyMCE editor
<script type="text/javascript" src="/wp-admin/load-
scripts.php?c=1&load=jquery &ver=XXXX"></script>
<script type="text/javascript" src="/wp-
includes/js/tinymce/tiny_mce_popup.js?v=3211"></script>
var HighlightDialog = {
         local_ed : 'ed',
         init : function(ed) {
                   HighlightDialog.local_ed = ed;
          if (jQuery.trim( HighlightDialog.local_ed.selection.getContent()
).length < 1){

         tinyMCEPopup.execCommand('mceSelectNodeDepth',false,0);}
         // if we did get with above if lets walk out untill we do
while (-1 ==
HighlightDialog.local_ed.selection.getContent().indexOf("hhh_box")) ){
         tinyMCEPopup.execCommand('mceSelectNodeDepth',false,1);}
tinyMCEPopup.resizeToInnerSize();
},                                                                   Cont on next
How to write to TinyMCE editor
Cont. from last slide..
insert : function insertHighlightSection(ed) {
         // get selected text
         output =
HighlightDialog.local_ed.selection.getContent();
….. Change it as needed ……………
         // write the value back to the editor replace all
content
         tinyMCEPopup.execCommand('mceInsertRawHTM
L', false, output);
         tinyMCEPopup.close(); // all done close the popup
};
// call on load function
 tinyMCEPopup.onInit.add(HighlightDialog.init,
PopUp pages in dialogs
 Used to provide extended detail
If is a detail page then show in a
dialog
dialog = jQuery('<div class="hhh_dialog" id="dialog“
style="display:hidden"></div>').appendTo('body');


dialog.load( jQuery.bbq.getState("detail"),{},
         function(responseText, textStatus, XMLHttpRequest) {
         dialog.dialog({
            modal: true,height: 720,width: 1050,position: 'top',
closeText: 'X' ,
            open: function(event, ui) {

jQuery("div#makeMeScrollable").smoothDivScroll("scrollToElement
", "id",
                                    jQuery.bbq.getState("collection") );
             },
             close: function(event, ui) {
                   jQuery.bbq.removeState("detail");
             },
         });
If not an AJAX call then redirect
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) ==
'xmlhttprequest') {
          $ajaxcall = true;
}
if(!$ajaxcall){
          $hhh_rediect_url =
get_post_meta(get_the_ID(),'_hhh_rediect_url',TRUE);
          if (strlen($hhh_rediect_url) > 0){
                     $hhh_rediect_url .= '#detail='. get_permalink();
                             ?><script type="text/javascript">/* <![CDATA[ */
                             window.location = "<?php echo
$hhh_rediect_url ?>"
                             /* ]]> */</script><?php
          }
}else{
          the_post()
}
The links
 Slides @ http://www.slideshare.net/pbearne




 @pbearne
 pbearne@gmail.com

More Related Content

What's hot

Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
Windows Azure Storage & Sql Azure
Windows Azure Storage & Sql AzureWindows Azure Storage & Sql Azure
Windows Azure Storage & Sql AzureMaarten Balliauw
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From IusethisMarcus Ramberg
 
jQuery: Nuts, Bolts and Bling
jQuery: Nuts, Bolts and BlingjQuery: Nuts, Bolts and Bling
jQuery: Nuts, Bolts and BlingDoug Neiner
 
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Fabien Potencier
 
Web::Machine - Simpl{e,y} HTTP
Web::Machine - Simpl{e,y} HTTPWeb::Machine - Simpl{e,y} HTTP
Web::Machine - Simpl{e,y} HTTPMichael Francis
 
J query b_dotnet_ug_meet_12_may_2012
J query b_dotnet_ug_meet_12_may_2012J query b_dotnet_ug_meet_12_may_2012
J query b_dotnet_ug_meet_12_may_2012ghnash
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Kick start with j query
Kick start with j queryKick start with j query
Kick start with j queryMd. Ziaul Haq
 
jQuery UI Widgets, Drag and Drop, Drupal 7 Javascript
jQuery UI Widgets, Drag and Drop, Drupal 7 JavascriptjQuery UI Widgets, Drag and Drop, Drupal 7 Javascript
jQuery UI Widgets, Drag and Drop, Drupal 7 JavascriptDarren Mothersele
 
Zero to Hero, a jQuery Primer
Zero to Hero, a jQuery PrimerZero to Hero, a jQuery Primer
Zero to Hero, a jQuery PrimerMatthew Buchanan
 
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011Alessandro Nadalin
 
Jquery In Rails
Jquery In RailsJquery In Rails
Jquery In Railsshen liu
 
Dig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoDig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoMohamed Mosaad
 

What's hot (20)

jQuery Basic API
jQuery Basic APIjQuery Basic API
jQuery Basic API
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Windows Azure Storage & Sql Azure
Windows Azure Storage & Sql AzureWindows Azure Storage & Sql Azure
Windows Azure Storage & Sql Azure
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From Iusethis
 
Jquery
JqueryJquery
Jquery
 
jQuery: Nuts, Bolts and Bling
jQuery: Nuts, Bolts and BlingjQuery: Nuts, Bolts and Bling
jQuery: Nuts, Bolts and Bling
 
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
 
Web::Machine - Simpl{e,y} HTTP
Web::Machine - Simpl{e,y} HTTPWeb::Machine - Simpl{e,y} HTTP
Web::Machine - Simpl{e,y} HTTP
 
J query b_dotnet_ug_meet_12_may_2012
J query b_dotnet_ug_meet_12_may_2012J query b_dotnet_ug_meet_12_may_2012
J query b_dotnet_ug_meet_12_may_2012
 
logic321
logic321logic321
logic321
 
jQuery
jQueryjQuery
jQuery
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Kick start with j query
Kick start with j queryKick start with j query
Kick start with j query
 
jQuery UI Widgets, Drag and Drop, Drupal 7 Javascript
jQuery UI Widgets, Drag and Drop, Drupal 7 JavascriptjQuery UI Widgets, Drag and Drop, Drupal 7 Javascript
jQuery UI Widgets, Drag and Drop, Drupal 7 Javascript
 
Zero to Hero, a jQuery Primer
Zero to Hero, a jQuery PrimerZero to Hero, a jQuery Primer
Zero to Hero, a jQuery Primer
 
Your Entity, Your Code
Your Entity, Your CodeYour Entity, Your Code
Your Entity, Your Code
 
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 
Jquery In Rails
Jquery In RailsJquery In Rails
Jquery In Rails
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
Dig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoDig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup Cairo
 

Viewers also liked

Sarah's Case
Sarah's CaseSarah's Case
Sarah's Caseangeladh
 
Using WordPress as your application stack
Using WordPress as your application stackUsing WordPress as your application stack
Using WordPress as your application stackPaul Bearne
 
Professional Frontend Engineering
Professional Frontend EngineeringProfessional Frontend Engineering
Professional Frontend EngineeringCheton Wu
 
WordPress overloading Gravityforms using hooks, filters and extending classes
WordPress overloading Gravityforms using hooks, filters and extending classes WordPress overloading Gravityforms using hooks, filters and extending classes
WordPress overloading Gravityforms using hooks, filters and extending classes Paul Bearne
 
High Performance Web Sites - Tips for faster pages
High Performance Web Sites - Tips for faster pagesHigh Performance Web Sites - Tips for faster pages
High Performance Web Sites - Tips for faster pagesCheton Wu
 
Vagrant WordCamp Hamilton
Vagrant  WordCamp HamiltonVagrant  WordCamp Hamilton
Vagrant WordCamp HamiltonPaul Bearne
 

Viewers also liked (8)

Sarah's Case
Sarah's CaseSarah's Case
Sarah's Case
 
Using WordPress as your application stack
Using WordPress as your application stackUsing WordPress as your application stack
Using WordPress as your application stack
 
Professional Frontend Engineering
Professional Frontend EngineeringProfessional Frontend Engineering
Professional Frontend Engineering
 
WordPress overloading Gravityforms using hooks, filters and extending classes
WordPress overloading Gravityforms using hooks, filters and extending classes WordPress overloading Gravityforms using hooks, filters and extending classes
WordPress overloading Gravityforms using hooks, filters and extending classes
 
Daughter Themes
Daughter ThemesDaughter Themes
Daughter Themes
 
High Performance Web Sites - Tips for faster pages
High Performance Web Sites - Tips for faster pagesHigh Performance Web Sites - Tips for faster pages
High Performance Web Sites - Tips for faster pages
 
Vagrant WordCamp Hamilton
Vagrant  WordCamp HamiltonVagrant  WordCamp Hamilton
Vagrant WordCamp Hamilton
 
WP json api
WP json apiWP json api
WP json api
 

Similar to HirshHorn theme: how I created it

WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3Mizanur Rahaman Mizan
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretssmueller_sandsmedia
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkIndicThreads
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Frameworkvhazrati
 
Grok Drupal (7) Theming
Grok Drupal (7) ThemingGrok Drupal (7) Theming
Grok Drupal (7) ThemingPINGV
 
Apostrophe
ApostropheApostrophe
Apostrophetompunk
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejsNick Lee
 
Introduction to jQuery - Barcamp London 9
Introduction to jQuery - Barcamp London 9Introduction to jQuery - Barcamp London 9
Introduction to jQuery - Barcamp London 9Jack Franklin
 
Jquery presentation
Jquery presentationJquery presentation
Jquery presentationMevin Mohan
 

Similar to HirshHorn theme: how I created it (20)

Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
 
Php
PhpPhp
Php
 
jQuery secrets
jQuery secretsjQuery secrets
jQuery secrets
 
WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3
 
jQuery
jQueryjQuery
jQuery
 
Introducing jQuery
Introducing jQueryIntroducing jQuery
Introducing jQuery
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secrets
 
Overview Of Lift Framework
Overview Of Lift FrameworkOverview Of Lift Framework
Overview Of Lift Framework
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web Framework
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Framework
 
Grok Drupal (7) Theming
Grok Drupal (7) ThemingGrok Drupal (7) Theming
Grok Drupal (7) Theming
 
Flask – Python
Flask – PythonFlask – Python
Flask – Python
 
Apostrophe
ApostropheApostrophe
Apostrophe
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejs
 
Backbone - TDC 2011 Floripa
Backbone - TDC 2011 FloripaBackbone - TDC 2011 Floripa
Backbone - TDC 2011 Floripa
 
Introduction to jQuery - Barcamp London 9
Introduction to jQuery - Barcamp London 9Introduction to jQuery - Barcamp London 9
Introduction to jQuery - Barcamp London 9
 
Jquery introduction
Jquery introductionJquery introduction
Jquery introduction
 
Jquery presentation
Jquery presentationJquery presentation
Jquery presentation
 
jQuery
jQueryjQuery
jQuery
 
Php (1)
Php (1)Php (1)
Php (1)
 

HirshHorn theme: how I created it

  • 1. The HirshHorn Theme How I created it Snippets of code and techniques I used
  • 2. Credits  Client: Hirshhorn Museum and Sculpture Garden , Smithsonian, Washington, D.C.  Design: Bruce Mau Design  Media Agency: Art & Science (formerly Juice).  Technical director: Spencer Saunders  WordPress coding: Paul Bearne
  • 3. This might not be the only or best way!  What you will see is how I solved the problems at the point in time (Sept 2011) when I did this project.  There is a lot of WordPress code in this talk; I am assuming that you can read and understand the code!  I am using code snippets so that I can get them on the slides, so not all the comments or code are shown!
  • 4. Notes  At the end I am going to ask what you found the most useful  Slides @ http://www.slideshare.net/pbearne
  • 6. Wire frame Layout menu Prev page … Current page Next page … footer Screen
  • 7. Viewsource <body class="single single-collection postid-1349"> <div id="wrapper" class="hfeed"> <div id="header"> Standard WP menu header </div><!-- #header--> <div id="main"> <div id="container"> <div id="content"> <div class="entry-content" id="makeMeScrollable"> <div id="detail-of..." data-id="7639" title="Detail of..." class="hhh_T_6 jsf_LoadViaAjax post-7639 collection type-collection status-publish hentry" ></div> <div id="..." data-id="3734" title="...“ class="hhh_T_3 jsf_LoadViaAjax post-3734 collection type-collection status-publish hentry"></div> ...... </div> </div> </div> </div> </div> </body>
  • 8. <div id="home" data-id="1349" title="Home" class="hhh_T_7 jsf_Loaded post-1349 collection type-collection status-publish hentry" <div id="page10" class="jst_BoxContaner hhh_template10"> <div class="hhh_link hhh_box13 hhh_item_1"> <a href="http://link to bio"> <img src="...." /></a> </div> <div class="hhh_box2 hhh_item_2"> <h4>Headline text</h4> <p>Random text</p> </div> <div class="hhh_videoInline hhh_box8 hhh_item_3"> http://youtu.be/DeYZVBzty0w </div>
  • 9. The scrolling plugin  http://www.smoothdivscroll.com (forked version) $(document).ready(function () { $("#makeMeScrollable").smoothDivScroll({ mousewheelScrolling: "allDirections", manualContinuousScrolling: true, autoScrollingMode: "onStart" }); }); Note: not all the settings I used are shown
  • 10. Changes to smoothdevscroll swapLastToFirst: function(){ var self = this, el = this.element, o = this.options; el.data("swappedElement", el.data("scrollableArea") .children(":last").detach()); el.data("scrollableArea").prepend(el.data("swappedElem ent")); el.data("scrollWrapper") .scrollLeft(el.data("scrollWrapper") .scrollLeft() + el.ata("swappedElement") .outerWidth(true)); el.data("getNextElementWidth", true); el.data("enabled", true); self._showHideHotSpots();
  • 11. Changes to smoothdevscroll _updateHash : function(){ var self = this, el = this.element, o = this.options, allBoxContaners=[], CurrentScrollLeft, currentDivId = 0 $('#makeMeScrollable .scrollableArea').children('div').each(function(index,element){ allBoxContaners.push([$(element).attr('id'), Math.round( $(element).position().left)]) }); CurrentScrollLeft = $(".scrollWrapper").scrollLeft() if(allBoxContaners.length > 0){ while(allBoxContaners[currentDivId][1] < CurrentScrollLeft - ($(window).width()/2)+100 ){ currentDivId ++; } var wall = allBoxContaners[i][0] if ($.bbq.getState("collection") != wall){ $.bbq.pushState({collection : wall }); }
  • 12. Keeping state and bookmarks www.hirshhorn.si.edu/collection/home/#collection=home #collection=doug-aitken-2 &detail=http%3A//www.hirshhorn.si.edu/bio/doug-aitken-interviews/ &title=Doug+Aitken+Interviews
  • 13. JQUERY BBQ: BACK BUTTON & QUERY LIBRARY  HTTP://BENALMAN.COM/PROJECTS/JQUERY-BBQ-PLUGIN // PUSH THIS URL "STATE" ONTO THE HISTORY HASH. $.BBQ.PUSHSTATE({ URL: HREF }); $(WINDOW).BIND( "HASHCHANGE", FUNCTION(E) { PUT THE ACTION CODE HERE } $(WINDOW).TRIGGER( "HASHCHANGE" );
  • 14. Over riding the menu URLs jQuery('#menu a').live('click', function(e) { var href = this.href; // does the clicked URL and current URL have '/collection/' in the path? if (href.indexOf('/collection/') > 0 && document.URL.indexOf('/collection/') > 0){ var clickId = href.toLowerCase().split('/'); // remove any current state jQuery.bbq.removeState("wall", "title", "detail"); // and set new state jQuery.bbq.pushState({ collection: clickId }); // stop any other on-clicks e.stopImmediatePropagation(); return false; }
  • 15. Example hashchange function jQuery(window).bind("hashchange", function(e) { collectionURL = jQuery.bbq.getState("collection"); // try to get an title from somewhere. title = jQuery.bbq.getState("title") ? jQuery.bbq.getState("title") : jQuery('#' + collectionURL).attr('title'); document.title = title; if (undefined === collectionURL) { collectionURL = jQuery('.jsf_Loaded').attr('id'); } jQuery("div#makeMeScrollable").smoothDivScroll("scrollToElement", "id", collectionURL); }
  • 16. Example wall fragment <div class="hhh_link hhh_box13 hhh_item_1"> <a href="http://www.hirshhorn.si.edu/collection/dark- matters/"> <img src="...." /> </a> </div>
  • 17. Example wall click action // add the scroll to action to wall links jQuery('.hhh_link a').on('click', function(e) { var clickId = this.href.toLowerCase().split('/'); var l = clickId.length if ( clickId[l-1].length > 1){ var scrollToId = clickId[l-1] }else{ var scrollToId = clickId[l-2] } jQuery("div#makeMeScrollable").smoothDivScroll("scrollToElement", "id",scrollToId); // stop any other onclicks e.stopImmediatePropagation() return false; }); Note: no hashchange this is done in the move finished callback from smoothDivScroll
  • 18. Using a menu to store the order register_nav_menu( „collection‟, 'Select the slider content menu.');
  • 19. Collection page PHP // get the menu object for theme menu location “collection” $menu_items = wp_get_nav_menu_items($locations['collection';]); // loop the menu object again to insert the current page and update the div before and 4 dev‟s after so that content we loaded on page load foreach ( (array) $menu_items as $key => $menu_item ) { $title = $menu_item->title; $url = $menu_item->url; $id = $menu_item->object_id; $templateId= 'hhh_T_'.get_post_meta($id, 'hhh_template_Id', true).' '; $slug = basename(get_permalink($id)); // is this post in the menu the current post if ($post->ID == $id) { Next slide……
  • 20. Collection page PHP if ($post->ID == $id) { //check it not a single post to handle preview if(count($array_of_divs)>0){ $last_id = $array_of_divs[count($array_of_divs)- 1][0]; $div_text = '<div id="'.basename(get_permalink($last_id)).'" title="'.$last_id.'" class="'.$templateId.implode(" ",get_post_class("jsf_ajaxOnLoad",$last_id)).'" ></div>' ; array_pop($array_of_divs); // remove the last empty div array_push( $array_of_divs , array($last_id , $div_text) ); // add it back in with extra class "jsf_ajaxOnLoad" } // load the content into a div $div_text = '<div id="'.basename(get_permalink($id)).'" title="'.$id.'" class="'.$templateId.'jsf_Loaded '.implode(" ",get_post_class("",$id)).'" >'.get_the_content().'</div>' ; $jsf_ajaxOnLoad = 5; }else{
  • 21. Collection page PHP }else{ if ($jsf_ajaxOnLoad > 0){ // 4 div after the loaded content $jsf_ajaxOnLoad -- ; $extra_class_test = $templateId."jsf_ajaxOnLoad "; }else{ $extra_class_test = $templateId."jsf_LoadViaAjax "; } $div_text = '<div id="'.basename(get_permalink($id)).'" title="'.$id.'" class="'.$extra_class_test.implode(" ",get_post_class("",$id)).'" ></div>' ;
  • 22. Collection page PHP <div class="entry-content" id="makeMeScrollable"> <?php foreach ( (array)$array_of_divs as $jsf_div){ echo($jsf_div[1]); } ?> </div><!-- .entry-content -->
  • 23. Now to call AJAX in WordPress URL: /wp-admin/admin- ajax.php?action=show_content_ajax_call add_action('wp_ajax_show_content_ajax_call', array( $this, 'jsf_show_content_ajax')); add_action('wp_ajax_nopriv_show_content_ajax_c all', array( $this, 'jsf_show_content_ajax'));
  • 24. Content fetch AJAX PHP function function jsf_show_content_ajax($id){ $postID = $_POST['postID']; $content_post = get_post($postID); $content = $content_post->post_content; $content = apply_filters('the_content', $content); $jsonpost = array(); $jsonpost["id"] = $postID; $jsonpost["slug"] = basename(get_permalink($postID) $jsonpost["content"] = str_replace(']]>', ']]>', $content); header( 'Content-Type: application/json' ); echo json_encode($jsonpost);; exit; }
  • 25. Content fetch AJAX function scrollerRightLimitReached: function() { $("div#makeMeScrollable").smoothDivScroll("swapFirstToLast"); if($('#makeMeScrollable .scrollableArea').children(":last").html().length <= 1){ var id = $('#makeMeScrollable .scrollableArea').children(":last").attr("id") $.ajax({ url:"/wp-admin/admin-ajax.php", type:'POST', dataType: 'json', data:'action=show_content_ajax_call&postID='+$('#'+id).attr("title")+'&t=3&slu + id, success:function(results){// load into div $('#' + results['slug']).html(results['content']); $('#' + results['slug']+' .jst_BoxContaner').hide().fadeIn();; $('#' + results['slug']).removeClass('jsf_ajaxOnLoad'); } }) } }
  • 26. Custom content in TinyMCE
  • 27. TinyMCE editor css Create a editor-style.css file in your theme root add_editor_style(); Tip: use the same style sheet in the theme wp_register_style('jsf_BoxStyles', get_stylesheet_directory_uri().'/editor- style.css'); wp_enqueue_style( 'jsf_BoxStyles') http://codex.wordpress.org/Function_Reference/add_editor_style
  • 28. Injecting code into the TinyMCE editor  Server side add_filter('default_content', 'my_editor_content'); function my_editor_content( $content ) { $content = "If you enjoyed this post, make sure to subscribe to my rss feed."; return $content; }  Client side var jsf_ed = tinyMCE.activeEditor; jsf_ed.selection.select(jsf_ed.getBody(), true); window.send_to_editor(“<div>content);
  • 29. How to add button to tinyMCE editor // Add only in Rich Editor mode if ( get_user_option('rich_editing') == 'true') { add_filter("mce_external_plugins", "add_hhh_custom_tinymce_plugin"); add_filter('mce_buttons', register_hhh_custom_button'); }
  • 30. How to add button to tinyMCE editor function register_hhh_custom_button($buttons) { array_push($buttons, "|", "hhh_highlight"); return $buttons; } function add_hhh_custom_tinymce_plugin($plugin_array) { $plugin_array['hhh_highlight'] = get_stylesheet_directory_uri().'/mce/editor_plugin.js'; return $plugin_array; }
  • 31. editor_plugin.js (function() { tinymce.create('tinymce.plugins.hhh_highlightPlugin', { init : function(ed, url) { ed.addCommand('mceHighlight', function() { ed.windowManager.open({ file : url + '/set_behavior.htm', width : 400,height : 600 ,inline : 1 }, {plugin_url : url}); }); ed.addButton('hhh_highlight', {title : 'Highlight', cmd : 'mceHighlight', image: url + '/hhhicon.gif' }); }, getInfo : function() {return {longname : 'Set Behavior',author : 'Paul Bearne',authorurl : 'http://www.bearne.ca',infourl : 'http://www.thejuiceagency.com',version : tinymce.majorVersion + "." + tinymce.minorVersion }; } }); tinymce.PluginManager.add('hhh_highlight', tinymce.plugins.hhh_highlightPlugin); })();
  • 32. How to add button to full screen editor function hhh_fullscreen_buttons($buttons){ $buttons[] = 'separator'; // add a separator $buttons['hhh_highlight'] = array( 'title' => __('Highlighter'), // Title of the button 'onclick' => "tinyMCE.execCommand('mceHighlight');", 'both' => false// Show on visual AND html mode ); return $buttons; } add_filter( 'wp_fullscreen_buttons', 'hhh_fullscreen_buttons' );
  • 34. How to read from TinyMCE editor <script type="text/javascript" src="/wp-admin/load- scripts.php?c=1&load=jquery &ver=XXXX"></script> <script type="text/javascript" src="/wp- includes/js/tinymce/tiny_mce_popup.js?v=3211"></script> var HighlightDialog = { local_ed : 'ed', init : function(ed) { HighlightDialog.local_ed = ed; if (jQuery.trim( HighlightDialog.local_ed.selection.getContent() ).length < 1){ tinyMCEPopup.execCommand('mceSelectNodeDepth',false,0);} // if we did get with above if lets walk out untill we do while (-1 == HighlightDialog.local_ed.selection.getContent().indexOf("hhh_box")) ){ tinyMCEPopup.execCommand('mceSelectNodeDepth',false,1);} tinyMCEPopup.resizeToInnerSize(); }, Cont on next
  • 35. How to write to TinyMCE editor Cont. from last slide.. insert : function insertHighlightSection(ed) { // get selected text output = HighlightDialog.local_ed.selection.getContent(); ….. Change it as needed …………… // write the value back to the editor replace all content tinyMCEPopup.execCommand('mceInsertRawHTM L', false, output); tinyMCEPopup.close(); // all done close the popup }; // call on load function tinyMCEPopup.onInit.add(HighlightDialog.init,
  • 36. PopUp pages in dialogs  Used to provide extended detail
  • 37. If is a detail page then show in a dialog dialog = jQuery('<div class="hhh_dialog" id="dialog“ style="display:hidden"></div>').appendTo('body'); dialog.load( jQuery.bbq.getState("detail"),{}, function(responseText, textStatus, XMLHttpRequest) { dialog.dialog({ modal: true,height: 720,width: 1050,position: 'top', closeText: 'X' , open: function(event, ui) { jQuery("div#makeMeScrollable").smoothDivScroll("scrollToElement ", "id", jQuery.bbq.getState("collection") ); }, close: function(event, ui) { jQuery.bbq.removeState("detail"); }, });
  • 38. If not an AJAX call then redirect if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { $ajaxcall = true; } if(!$ajaxcall){ $hhh_rediect_url = get_post_meta(get_the_ID(),'_hhh_rediect_url',TRUE); if (strlen($hhh_rediect_url) > 0){ $hhh_rediect_url .= '#detail='. get_permalink(); ?><script type="text/javascript">/* <![CDATA[ */ window.location = "<?php echo $hhh_rediect_url ?>" /* ]]> */</script><?php } }else{ the_post() }
  • 39. The links  Slides @ http://www.slideshare.net/pbearne  @pbearne  pbearne@gmail.com