1 of 67

How I created WPBingo.com

Using Vue.js, Tailwind CSS, and the WP REST API

#wcmia

@rzen

Making WPBingo

2 of 67

I kind of like to create disruption...

Bingo!

#wcmia

@rzen

Making WPBingo

3 of 67

I really like to create disruption...

Bingo!

Bingo!

Bingo!

Bingo!

Bingo!

Bingo!

#wcmia

@rzen

Making WPBingo

4 of 67

What this talk is not...

#wcmia

@rzen

Making WPBingo

5 of 67

Part 1: The Idea

#wcmia

@rzen

Making WPBingo

6 of 67

Just a bulleted list in evernote...

#wcmia

@rzen

Making WPBingo

7 of 67

...wouldn’t it be more fun to play with friends?

#wcmia

@rzen

Making WPBingo

8 of 67

...besides, I needed an excuse to play with some new libraries anyway...

#wcmia

@rzen

Making WPBingo

9 of 67

What I wanted to accomplish:

  • Learn a new JS framework (Vue.js)
  • Experiment with local storage
  • Try atomic, utility-based CSS
  • Customize WP REST API responses

#wcmia

@rzen

Making WPBingo

10 of 67

Here’s what I created...

#wcmia

@rzen

Making WPBingo

11 of 67

#wcmia

@rzen

Making WPBingo

12 of 67

Part 2: Exploration

#wcmia

@rzen

Making WPBingo

13 of 67

Why Vue.js?�Why not [framework]?

#wcmia

@rzen

Making WPBingo

14 of 67

Two Good Reasons:

  1. Zero external dependencies
  2. 30kb package when min+gzipped

(Plus, this was a learning exercise. I’ve already practiced with others)

#wcmia

@rzen

Making WPBingo

15 of 67

Vue.js is capable of a lot of cool things and works like I expect/predict.

#wcmia

@rzen

Making WPBingo

16 of 67

Pause: A Primer

on Vue.js

#wcmia

@rzen

Making WPBingo

17 of 67

Creating a Vue Instance

#wcmia

@rzen

Making WPBingo

18 of 67

Vue Directives

v-model: bind an input to a dynamic data from JavaScript

<input v-model="message">

#wcmia

@rzen

Making WPBingo

19 of 67

Vue Directives

<div class="edit-product" v-if="product.id">

v-if: only render element if something evaluates truthy

#wcmia

@rzen

Making WPBingo

20 of 67

Vue Directives

v-for: repeat an element in a for-style loop

<tr v-for="product in products">

<td>{{ product.id }}</td>

<td>{{ product.name }}</td>

<td>{{ product.stock_quantity }}</td>

</tr>

#wcmia

@rzen

Making WPBingo

21 of 67

Vue Directives

v-bind: bind an element’s attribute to dynamically controlled data

<a v-bind:href="link">Visit Link</a>

Shorthand: just use a colon, followed by value

<a :href="link">Visit Link</a>

#wcmia

@rzen

Making WPBingo

22 of 67

Vue Directives

v-on: bind a method to an event

<button v-on:click="saveProduct">Save</button>

Shorthand: just use an @, followed by event

<button @click="saveProduct">Save</button>

#wcmia

@rzen

Making WPBingo

23 of 67

Vue Directives

v-on: also accepts stock event modifiers, like preventDefault():

<button v-on:click.prevent="saveProduct">Save</button>

Shorthand works the same way here, too:

<button @click.prevent="saveProduct">Save</button>

#wcmia

@rzen

Making WPBingo

24 of 67

Let’s talk about CSS

#wcmia

@rzen

Making WPBingo

25 of 67

Object Oriented CSS (OOCSS)

#wcmia

@rzen

Making WPBingo

26 of 67

Block - Element - Modifier (BEM)

#wcmia

@rzen

Making WPBingo

27 of 67

Scalable and Modular Architecture for CSS (SMACSS)

#wcmia

@rzen

Making WPBingo

28 of 67

Atomic CSS

#wcmia

@rzen

Making WPBingo

29 of 67

#wcmia

@rzen

Making WPBingo

30 of 67

#wcmia

@rzen

Making WPBingo

31 of 67

mx-auto

#wcmia

@rzen

Making WPBingo

32 of 67

mx-auto

Set margin left and right to “auto”

#wcmia

@rzen

Making WPBingo

33 of 67

my-4

#wcmia

@rzen

Making WPBingo

34 of 67

my-4

Set margin top and bottom to 1rem

#wcmia

@rzen

Making WPBingo

35 of 67

p-4

#wcmia

@rzen

Making WPBingo

36 of 67

p-4

Set padding on all sides to 1rem

#wcmia

@rzen

Making WPBingo

37 of 67

#wcmia

@rzen

Making WPBingo

38 of 67

Part 3: Prototyping

#wcmia

@rzen

Making WPBingo

39 of 67

[Recap] What I wanted to practice:

  • Learn a new JS framework (Vue.js)
  • Experiment with local storage
  • Try atomic, utility-based CSS
  • Customize WP REST API responses

#wcmia

@rzen

Making WPBingo

40 of 67

I really enjoyed Vue’s syntax

v-if

v-for

v-bind

v-model

@click

@change

v-show

data: {}

methods: {}

created()

#wcmia

@rzen

Making WPBingo

41 of 67

Data prep

#wcmia

@rzen

Making WPBingo

42 of 67

Creating markup

<div v-if="gameBoard">

<div v-for="cell in gameBoard">

<label>

<span v-html="cell.label"></span>

<input class="hidden" type="checkbox"

v-model="cell.found" @change="trackChange()">

</label>

</div>

</div>

#wcmia

@rzen

Making WPBingo

43 of 67

Adding custom methods

[code redacted]

#wcmia

@rzen

Making WPBingo

44 of 67

Tapping into local storage is super easy.

#wcmia

@rzen

Making WPBingo

45 of 67

Storing data to local storage

setLocalStorage() {

localStorage.setItem(

'startTime',

this.startTime

);

localStorage.setItem(

'gameBoard',

JSON.stringify( this.gameBoard )

);

}

#wcmia

@rzen

Making WPBingo

46 of 67

Fetching data from local storage

getLocalStorage() {

this.startTime = localStorage.getItem( 'startTime' );

this.startTime = JSON.parse(

localStorage.getItem( 'gameBoard' )

);

}

#wcmia

@rzen

Making WPBingo

47 of 67

Atomic CSS is real slick, with a pre-built and well-documented framework

#wcmia

@rzen

Making WPBingo

48 of 67

The list of classes gets a bit unwieldy...

<div class="container mx-auto mb-4 px-2 flex flex-wrap">

<div class="cell flex w-1/5 p-2 border-grey-lighter border-2 bg-white">

<label class="text-xs self-center text-center w-full h-full block flex">

<span class="self-center text-center w-full" v-html="cell.label"></span>>

</label>

</div>

</div>

#wcmia

@rzen

Making WPBingo

49 of 67

But this is the entirety of my custom CSS:

<style>

.cell {

height: 20vw;

max-height: 150px;

}

</style>

#wcmia

@rzen

Making WPBingo

50 of 67

Scoring a bingo game was an undocumented, fun new challenge

#wcmia

@rzen

Making WPBingo

51 of 67

  1. Define winning cell combinations

#wcmia

@rzen

Making WPBingo

52 of 67

  • Define winning cell combinations

#wcmia

@rzen

Making WPBingo

53 of 67

2. Score a set of squares

#wcmia

@rzen

Making WPBingo

54 of 67

3. Check if any set has a score of 5

#wcmia

@rzen

Making WPBingo

55 of 67

Registering custom endpoints

was the easiest part of all

#wcmia

@rzen

Making WPBingo

56 of 67

Feed data from WP REST API

#wcmia

@rzen

Making WPBingo

57 of 67

$> wp scaffold plugin wpbingo --skip-tests --activate

Success: Created plugin files.

$> wp scaffold post-type wpbingo --title="Bingo Square" --dashicon=grid-view --plugin=wpbingo

Success: Created post type 'Bingo Square'.

$> wp scaffold taxonomy wpbingo-card --post_types=wpbingo --label="Bingo Card" --plugin=wpbingo

Success: Created taxonomy 'Bingo Card'.

$> wp scaffold taxonomy wpbingo-category --post_types=wpbingo --label="Square Category" --plugin=wpbingo

Success: Created taxonomy 'Square Category'.

#wcmia

@rzen

Making WPBingo

58 of 67

Here’s the magic REST bit:

// Allow random ordering in wpbingo REST endpoint

function wpbingo_init( $params ) {

register_post_type( 'wpbingo', array(

// ...

'show_in_rest' => true,

'rest_base' => 'wpbingo',

'rest_controller_class' => 'WP_REST_Posts_Controller',

) );

}

add_filter( 'init', 'wpbingo_init' );

#wcmia

@rzen

Making WPBingo

59 of 67

Next, add random sorting

// Allow random ordering in wpbingo REST endpoint

function wpbingo_rest_allow_rand_orderby( $params ) {

$params['orderby']['enum'][] = 'rand';

return $params;

}

add_filter( 'rest_wpbingo_collection_params', 'wpbingo_rest_allow_rand_orderby' );

#wcmia

@rzen

Making WPBingo

60 of 67

WARNING: Random sort is non-cacheable and non-performant, which is why core excludes support by default.

#wcmia

@rzen

Making WPBingo

61 of 67

Finally, modify the REST response

// Modify wpbingo REST response

function wpbingo_rest_modify_fields( $data ) {

return [

'label' => $data->data['title']['rendered'],

'found' => 0,

];

}

add_filter( 'rest_prepare_wpbingo', 'wpbingo_rest_modify_fields', 12 );

#wcmia

@rzen

Making WPBingo

62 of 67

Et voila, the desired random output:

Postman HTTP Client

#wcmia

@rzen

Making WPBingo

63 of 67

Additional Resources

#wcmia

@rzen

Making WPBingo

64 of 67

Great presentations on WPSessions

#wcmia

@rzen

Making WPBingo

65 of 67

Vue Tutorials

#wcmia

@rzen

Making WPBingo

66 of 67

Learn more about Tailwind and Atomic CSS

#wcmia

@rzen

Making WPBingo

67 of 67

Thanks!

Don’t forget to play WPBingo during the 4:40pm keynote for a chance to win a prize!

Slides & Discount: https://wpsessions.com/wcmia

#wcmia

@rzen

Making WPBingo