JavaScript og WordPress

Jens Ahrengot Boddum

WordPress konsulent

Hvorfor JavaScript?

LocalStorage
Web Sockets
Offline Web Apps
Drag 'n Drop
SessionStorage
Geolocation
File API
Web Audio API
Web RTC
Peer-to-Peer
Canvas
WebGL

Det kommer til at handle om ...

Spagettikode med jQuery
Struktur med genbrugelige moduler
Use case fra den virkelige verden
Asynkron Modul Difinition



"Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling..."
- Backbonejs.org


Hvem bruger Backbone?


 wp_enqueue_script( "backbone" );


Demo time!


Et eksempel fra 

den virkelige verden



this.presentation.set( "geekMode", true );


Data fra WordPress DB > Backbone

Advanced Custom Fields
<article
    <?php post_class( 'normal untoggled' ); ?>
    data-twitterhandle="<?php the_field( 'twitterfeed_username' ); ?>"
    data-tags="<?php echo implode( '|||', $tags ); ?>"
    data-img-normal="<?php echo $img_normal; ?>"
    data-img-full="<?php $img_full; ?>"
    data-videos="<?php echo implode( '|||', $videos ); ?>"
    data-spotify-tracks="<?php echo implode( '|||', $spotify_tracks ); ?>"
    data-slug="<?php echo basename( get_permalink() ); ?>"
    data-title="<? the_title(); ?>"
    data-permalink="<?php echo get_permalink(); ?>"
    data-comments-open="<?php echo comments_open(); ?>"
>
    <p><?php the_content(); ?></p>
    <ul class="videos"></ul>
    <ul class="spotify-tracks"></ul>
    <ul class="twitterfeed"></ul>
    <ul class="comments"></ul>
</article>

HTML

<article
    class="post-5621 artist untoggled"
    data-twitterhandle="@arcadefire"
    data-tags="alternative|||indie|||rock|||søndag|||green-stage|||20"
    data-img-normal="http://...ArcadeFire_wide_1200x453-460x370.png"
    data-img-full="http://...ArcadeFire_wide_1200x453.png"
    data-videos="7E0fVfectDo|||5Euj9f3gdyM"
    data-spotify-tracks="spotify:track:0UjGKszZwvDrxl0WlAU7Wc"
    data-slug="arcade-fire"
    data-title="Arcade Fire"
    data-permalink="http://www.northside.dk/artist/arcadefire/"
    data-comments-open=""
>
    <p>Koncert beskrivelse bla bla ...</p>
    <ul class="videos"></ul>
    <ul class="spotify-tracks"></ul>
    <ul class="twitterfeed"></ul>
    <ul class="comments"></ul>
</article>

Backbone model

var Toggleable = Backbone.Model.extend({
    initialize: function() {
        this.splitString('videos');
        this.splitString('spotifyTracks');
        this.splitString('tags');
    },
    splitString: function(attr) {
        var data = this.get(attr);
        if (data && typeof data === 'string') {
        this.set(attr, data.split('|||'));
    }
    }
});

Backbone view

ToggleableView

var ToggleableView = Backbone.View.extend({
    events: {
        'click': 'toggleOpen'
        'click .close-toggleable': 'toggleClosed'
    },
    initialize: function() {
        this.model.on('change:toggled:true', this.open, this);
        this.model.on('change:toggled:false', this.close, this);
    },
    toggleOpen: function(e) {
        window.location.hash = this.model.get('slug');
    },
    toggleClosed: function(e) {
        ns.toggleRouter.navigate("/", true);
    },
    open: function() {
        this.$el.addClass("toggled");
    },
    close: function() {
        this.$el.removeClass("toggled");
    }
}); 

northside.dk/kunstnere/ bliver til northside.dk/kunstnere/#/arcade-fire

Backbone view

ToggleableArtistView

var ToggleableArtistView = ahrengot.view.ToggleableView.extend({
  open: function() {
    this.updateImage();
    this.$el.addClass('toggled');
    this.createSubViews();
  },
  close: function() {
    this.$el.removeClass('toggled');
    this.updateImage();
  },
  updateImage: function() {
    // Switch large / small image
  },
  createSubViews: function() {
    var $content = this.$el.find('.post_content');

    // Spawn sub views
    if (this.model.get('spotifyTracks')) {
      this.subViews.tracks = new ahrengot.view.SpotifyTracksSection({model: this.model });
      $content.find('.spotify-tracks').html(this.subViews.tracks.el);
    }

    if (this.model.get('videos')) {
      this.subViews.videos = new ahrengot.view.VideoSection({ model: this.model });
      $content.find('.videos').html(this.subViews.videos.el);
    }

    if (this.model.get('twitterhandle')) {
      this.subViews.twitterfeed = new ahrengot.view.TwitterSection({ model: this.model });
      $content.find('.twitterfeed .feed').html(this.subViews.twitterfeed.el);
    }

    if (this.model.get('commentsOpen')) {
      this.subViews.comments = new ahrengot.view.CommentsSection({ model: this.model });
      $content.find('.comments').append(this.subViews.comments.el);
    }
  }
});
	

Artist Sub-view

TwitterSection

var TwitterSection = ahrengot.view.Subsection.extend({
  className: 'feed',
  configureFeed: function() {
    var query = encodeURI("from:" + this.model.get('twitterhandle'));
    this.feed = new TwitterFeed(this.$el, query, 'twitterfeed-artist');
  },
  render: function() {
    this.configureFeed();
  }
});
	


En bedre måde at
loade scripts I WordPress

wp_enqueue_script();

  1. Intet overblik hvis du har meget JS
  2. Mange HTTP requests
  3. Ingen load on-demand

Northside theme med wp_enqueue_script();

43 scripts — De afhænger af hinanden på kryds og tværs.

<?php

$cache_bust = '4.3';
$base_url = get_bloginfo( 'template_url' ) . 'library/js/';

wp_enqueue_script( "modernizr", $base_url . 'libs/modernizr-2.6.1.min.js', false, $cache_bust );
wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'underscore' );
wp_enqueue_script( 'backbone' );
wp_enqueue_script( 'isotope', $base_url . 'libs/jquery.isotope.min.js', array( 'jquery' ), $cachebust, true );
wp_enqueue_script( 'namespaces', $base_url . 'Namespaces.js', array(), $cachebust, true );
wp_enqueue_script( 'ctrl-cheesy-tickets', $base_url . 'controllers/CheesyTickets.js', array(), $cachebust, true );
wp_enqueue_script( 'ctrl-facebooksdk', $base_url . 'controllers/FadebookSDK.js', array(), $cachebust, true );
wp_enqueue_script( 'ctrl-factswidget', $base_url . 'controllers/FactsWidget.js', array(), $cachebust, true );
wp_enqueue_script( 'ctrl-faqgui', $base_url . 'controllers/FAQGui.js', array(), $cachebust, true );
wp_enqueue_script( 'ctrl-faqsearchfilter', $base_url . 'controllers/SearchFilter.js', array(), $cachebust, true );
wp_enqueue_script( 'ctrl-fbattendees', $base_url . 'controllers/FBAttendees.js', array(), $cachebust, true );
wp_enqueue_script( 'ctrl-factswidget', $base_url . 'controllers/FactsWidget.js', array(), $cachebust, true );
wp_enqueue_script( 'ctrl-floatingsidebar', $base_url . 'controllers/FloatingSidebar.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-instagramwidget', $base_url . 'controllers/InstagramWidget.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-isotopefilter', $base_url . 'controllers/IsotopeFilter.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-linkhijacker', $base_url . 'controllers/LinkHijacker.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-mobilenavigation', $base_url . 'controllers/MobileNavigation.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-modal', $base_url . 'controllers/Modal.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-newslettersignup', $base_url . 'controllers/NewsletterSignup.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-pumpit', $base_url . 'controllers/PumpIt.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-rightnowwidget', $base_url . 'controllers/RightNowWidget.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-schedulegui', $base_url . 'controllers/ScheduleGui.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-scrollmanager', $base_url . 'controllers/ScrollManager.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-searchfilter', $base_url . 'controllers/SearchFilter.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-slidercontroller', $base_url . 'controllers/SliderController.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-twitterfeed', $base_url . 'controllers/TwitterFeed.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-weatherwidget', $base_url . 'controllers/WeatherWidget.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-widgetbottomlayout', $base_url . 'controllers/WidgetBottomLayout.js', array(), $cache_bust, true );
wp_enqueue_script( 'ctrl-widgetlayout', $base_url . 'controllers/WidgetLayout.js', array(), $cache_bust, true );
wp_enqueue_script( 'model-toggleable', $base_url . 'model/Toggleable.js', array(), $cache_bust, true );
wp_enqueue_script( 'collection-toggleables', $base_url . 'collections/Toggleables.js', array('model-toggleable'), $cache_bust, true );
wp_enqueue_script( 'view-subsection', $base_url . 'views/Subsection.js', array(), $cache_bust, true );
wp_enqueue_script( 'view-submitquestion', $base_url . 'views/SubmitQuestion.js', array('view-subsection'), $cache_bust, true );
wp_enqueue_script( 'view-videosection', $base_url . 'views/VideoSection.js', array('view-subsection'), $cache_bust, true );
wp_enqueue_script( 'view-singlevideosection', $base_url . 'views/SingleVideoSection.js', array('view-videosection'), $cache_bust, true );
wp_enqueue_script( 'view-spotifytrackssection', $base_url . 'views/SpotifyTracksSection.js', array('view-subsection'), $cache_bust, true );
wp_enqueue_script( 'view-twittersection', $base_url . 'views/TwitterSection.js', array('view-subsection'), $cache_bust, true );
wp_enqueue_script( 'view-commentssection', $base_url . 'views/CommentsSection.js', array('view-subsection'), $cache_bust, true );
wp_enqueue_script( 'view-likebtnsection', $base_url . 'views/LikeBtnSection.js', array('view-subsection'), $cache_bust, true );
wp_enqueue_script( 'view-toggleableview', $base_url . 'views/ToggleableView.js', array('view-subsection'), $cache_bust, true );
wp_enqueue_script( 'view-toggleableartist', $base_url . 'views/ToggleableArtist.js', array('view-subsection'), $cache_bust, true );
wp_enqueue_script( 'view-toggleablenews', $base_url . 'views/ToggleableNews.js', array('view-subsection'), $cache_bust, true );
wp_enqueue_script( 'view-toggleablevideo', $base_url . 'views/ToggleableVideo.js', array('view-subsection'), $cache_bust, true );
wp_enqueue_script( 'router-togglerouter', $base_url . 'routers/ToggleRouter.js', array('model-toggleable', 'view-toggleable', 'view-toggleableartist', 'view-toggleablenews', 'view-toggleablevider'), $cache_bust, true );
wp_enqueue_script( 'ns-main', $base_url . 'Main.js', array('backbone'), $cachebust, true );
	

Asynkron Modul Definition
med Require.js


  1. Intet Overblik hvis du har meget JS
  2. Loader scripts on-demand
  3. Bedre "responsive design"
  4. Indbygget build script


Resultat: Hurtigere sider

Definér modul

define(["backbone"], function(Backbone) {
  var CustomView = Backbone.View.extend({
    render: function() {
      this.$el.text("Weeeeee!");
    }
  });

  return CustomView;
});
	

Inkluder modul

require(["sti/til/CustomView"], function(CustomView) {
  new CustomView();
});
	

Toggleable.js

define(["backbone"], function(Backbone) {
  var ToggleableView = Backbone.View.extend({
    // Toggleable methods...
  });
  return ToggleableView;
});

ToggleableArtist.js

define(["views/Toggleable", "views/VideoSection", "views/SpotifySection", "views/TwitterfeedSection", "views/CommentsSection"], function(ToggleableView, VideoSection, SpotifySection, TwitterfeedSection, CommentsSection) {
  var ToggleableArtistView = ToggleableView.extend({
    // ToggleableArtist View methods...
  });
  return ToggleableArtistView;
});

ToggleableNews.js

define(["views/ToggleableArtist"], function(ToggleableArtistView){
  var ToggleableNewsView = ToggleableArtistView.extend({
    // ToggleableNews methods...
  });
  return ToggleableNewsView;
});
	

Load af ToggleableNews.js

require(["views/toggleableNews"], function(ToggleableNewsView) {
    new ToggleableNewsView();
});

Dynamisk og aynkront indsat i <head>

<script async src="sti/til/jquery.js"></script>
<script async src="underscore.js"></script>
<script async src="backbone.js"></script>
<script async src="views/Toggleable.js"></script>
<script async src="views/VideoSection.js"></script>
<script async src="views/SpotifySection.js"></script>
<script async src="views/TwitterfeedSection.js"></script>
<script async src="views/CommentsSection.js"></script>
<script async src="views/ToggleableArtist.js"></script>
<script async src="views/ToggleableNews.js"></script>
	

this.presentation.set( "geekMode", false );


Jens Ahrengot Boddum

Slides: slides.com/ahrengot/js-og-wp/

Codepen demo: codepen.io/Ahrengot/pen/ebyqz

Mit website: ahrengot.com

Twitter: @Ahrengot

LinkedIn: linkedin.com/in/ahrengot

WordPress og JavaScript

By Jens Ahrengot Boddum

WordPress og JavaScript

(Danish) Bedre JavaScript workflow I WordPress med Backbone og Require.js. WordCamp Denmark d. 25 maj 2014.

  • 5,431