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

Vue.js + WordPress

Vue.js + WordPress

From WordCamp Raleigh 2017.

The popularity of JavaScript has lead to an ecosystem that’s vibrant, growing, and to be honest, somewhat out of control. Each day leads to a new framework labeled as the next great thing, but each framework presents it’s own unique set of pros, cons, and frustrations.

In this talk, we will look at Vue.js, one of the most popular JavaScript frameworks available. In 2016, stateofjs.com conducted a survey where over 89% of the surveyed developers gave Vue.js a satisfactory rating, which rates it as the second highest rated framework behind React, which received a rating of 92%. We will look at real world examples of how Vue.js can be integrated into a WordPress project for the front end, the back end, and interaction with the WordPress Rest API.

Allen Moore

April 23, 2017
Tweet

More Decks by Allen Moore

Other Decks in Technology

Transcript

  1. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 + A

    L L E N M O O R E | S E N I O R F R O N T E N D E N G I N E E R
  2. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 W H

    E R E TO F I N D M E @creativeallen https://allenmoore.me https://github.com/allenmoore
  3. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 This is

    not an attempt to discredit other MVC Frameworks, such as React or Angular
  4. “Just because you have access to jQuery does not mean

    that it should be or has to be used.”
  5. – A L L E N M O O R

    E “Just because you have access to jQuery does not mean that it should be or has to be used.”
  6. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 W H

    AT I S V U E . J S A N D W H Y S H O U L D I C A R E ?
  7. “Vue (pronounced /vjuː/, like view) is a progressive framework for

    building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable.”
  8. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 W H

    Y ? • Versatility • Easy on-boarding • Vanilla JavaScript
  9. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 W H

    Y ? • Versatility • Easy on-boarding • Vanilla JavaScript • Lack of dependency requirements
  10. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 <?php

    2 $defaults = array( 3 'label' => 'Upload an Image', 4 'name' => 'cmm-image-upload', 5 'image_id' => 0, 6 'image_size' => 'thumbnail', 7 'max_uploads' => 50, 8 'type' => 'option', 9 ); 10 11 $args = wp_parse_args( $args, $defaults ); 12 13 $image_src = wp_get_attachment_image_src( $args['image_id'], $args['image_size'] ); 14 $image_src = is_array( $image_src ) ? reset( $image_src ): '';
  11. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 <?php

    2 wp_enqueue_script( 'media-upload' ); 3 wp_enqueue_script( 'cmmis-admin-scripts' ); 4 5 $images = self::getDataType( $args['type'], $args['name'] ); 6 $fieldName = $args['name']; 7 $imageData = self::getImages( $images ); 8 $data = [ 9 'fieldName' => $fieldName, 10 'images' => $imageData, 11 'maxUploads' => $args['max_uploads'], 12 ]; 13 14 wp_localize_script( 15 'cmmis-admin-scripts', 16 'cmmisImageData', 17 $data 18 );
  12. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 import

    Vue from 'vue'; 2 3 4 /** 5 * Instantiate the Vue instance. 6 * 7 * @author Allen Moore 8 * @returns {void} 9 */ 10 new Vue( {el: '#app'} );
  13. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 <template>

    2 </template> 3 4 <script> 5 </script> 6 7 <style> 8 </style>
  14. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 <template>

    2 <div id="app"> 3 <div class="cmmis-images"> 4 <div class="cmmis-image" v-for="image in images" v-bind:data-cmmis-image="image.id"> 5 </div> 6 </div> 7 </div> 8 </template>
  15. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 <div

    class="cmmis-image" v-for="image in images" v-bind:data-cmmis-image="image.id"> 2 <div class="image-item"> 3 <input class="image-id" type="hidden" v-bind:name="field" v-bind:id="field" 4 v-bind:value="image.id"/> 5 <img class="image" v-bind:src="image.src" /> 6 <div class="image-actions"> 7 <a v-bind:href="image.edit" class="cmmis-button -edit"> 8 <svgicon class="svg-edit" icon="edit" width="14" height="14"></svgicon> 9 <span class="screen-reader-text">Edit Image</span> 10 </a> 11 <button class="cmmis-button -delete" aria-pressed="false" v-on:click="deleteImage( image )"> 12 <svgicon class="svg-delete" icon="delete" width="11" height="14"></svgicon> 13 <span class="screen-reader-text">Delete Image</span> 14 </button> 15 </div> 16 </div> 17 <div class="image-caption">{{ image.name }}</div> 18 </div>
  16. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 <div

    class="cmmis-footer"> 2 <button class="button button-primary button-large" aria-pressed="false" v-on:click="openModal"> 3 <svgicon class="svg-plus" icon="plus" width="13" height="13"></svgicon> 4 Add Image 5 </button> 6 </div>
  17. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 /*

    global cmmisImageData */ 2 import './components/icons'; 3 4 export default { 5 6 name: 'app', 7 8 data() { 9 return {}; 10 }, 11 12 methods: {}, 13 14 mounted() {} 15 };
  18. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 data()

    { 2 return { 3 field: `${cmmisImageData.fieldName}[]`, 4 images: [] 5 } 6 }
  19. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 methods:

    { 2 getImages() { 3 const images = cmmisImageData.images; 4 let image; 5 6 for ( let i = 0, len = images.length; i < len; i++ ) { 7 image = images[i]; 8 this.images.push( image ); 9 } 10 } 11 }
  20. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 methods:

    { 2 insertImg( frame ) { 3 const selection = frame.state().get( 'selection' ), 4 length = selection.length, 5 images = selection.models; 6 let imgData = {}, 7 img, 8 imgEditLink, 9 imgId, 10 imgTitle, 11 imgUrl; 12 13 for ( let i = 0; i < length; i++ ) { 14 img = images[i]; 15 imgEditLink = img.changed.editLink; 16 imgId = img.id; 17 imgTitle = img.changed.title; 18 imgUrl = img.changed.sizes.thumbnail.url; 19 imgData = { 20 edit: imgEditLink, 21 id: imgId, 22 name: imgTitle, 23 src: imgUrl 24 }; 25 this.images.push( imgData ); 26 } 27 } 28 }
  21. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 methods:

    { 2 openModal( event ) { 3 const self = this; 4 let frame; 5 6 if ( event ) { 7 event.preventDefault(); 8 } 9 frame = wp.media( { 10 frame: 'post', 11 title: 'Choose an Image', 12 library: { 13 type: 'image' 14 }, 15 multiple: true, 16 button: { 17 text: 'Select Image' 18 } 19 } ); 20 frame.open(); 21 frame.on( 'insert', function() { 22 self.insertImg( frame ); 23 } ); 24 } 25 }
  22. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 methods:

    { 2 deleteImage( img ) { 3 this.images.splice( this.images.indexOf( img ), 1 ); 4 } 5 }
  23. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 import

    Vue from 'vue'; 2 import svgicon from 'vue-svgicon'; 3 import App from './App.vue'; 4 5 Vue.use( svgicon, {tagName: 'svgicon'} ); 6 7 new Vue( { 8 el: '#app', 9 render: h => h( App ) 10 } );
  24. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 const

    wpApiUrl = 'https://allenmoore.me/wp-json/wp/v2/posts/?_embed&per_page=5'; 2 3 class DisplayPosts extends Vue { 4 constructor() {} 5 } 6 7 new DisplayPosts();
  25. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 class

    DisplayPosts extends Vue { 2 getPosts( res ) { 3 this.posts = JSON.parse( res.responseText ); 4 5 return this.posts; 6 } 7 }
  26. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 class

    DisplayPosts extends Vue { 2 getData( res, posts = null ) { 3 const self = this; 4 5 res.open( 'GET', wpApiUrl ); 6 res.onload = function() { 7 self.getPosts( res ); 8 }; 9 res.send(); 10 } 11 }
  27. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 class

    DisplayPosts extends Vue { 2 constructor() { 3 const props = { 4 el: '#app', 5 data: {posts: null}, 6 created() { 7 this.fetchPosts(); 8 }, 9 methods: { 10 fetchPosts() { 11 const xhr = new XMLHttpRequest(), 12 self = this; 13 14 this.getData( xhr ); 15 } 16 } 17 }; 18 19 super( props ); 20 this.posts = null; 21 } 22 }
  28. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 <template

    v-for="post in posts"> 2 <article class="entry" role="article"> 3 </article> 4 </template>
  29. Allen Moore • @creativeallen • #wcraleigh • allenmoore.me/wcraleigh-2017 1 <section

    v-if="post._embedded['wp:featuredmedia'] [0].media_details.sizes['article-thumb']" class="entry-thumbnail"> 2 <a :href="post.link"><img :src="post._embedded['wp:featuredmedia'] [0].media_details.sizes['article-thumb'].source_url" /></a> 3 </section> 4 <header class="entry-header" role="banner"> 5 <h3 class="entry-title" itemprop="headline"><a :href="post.link" rel="bookmark">{{ post.title.rendered }}</a></h3> 6 </header> 7 <section class="entry-content" v-if="post.excerpt.rendered" v- html="post.excerpt.rendered" itemprop="articleBody"></section>