This repo is a boilerplate WordPress theme that makes WP and Vue work well together. You might be looking for VuePress, the Vue-powered static site generator. We only just found out about the name conflict, so we're figuring out what to do from here!
Vuepress is a boilerplate used to build fast, responsive WordPress templates with Vue.js.
Head over to the tutorial to learn how to build Vue.js + WordPress sites with Vuepress!
- Install
- Common Tasks
- The Developer Role and Developer IDs
- Vuex and State
- Vuepress Events
- Partials
- Deploying
- Recommended Reading
- In a WordPress
themes/
directory:git clone https://github.com/funkhaus/vuepress my-theme
cd my-theme
npm install
- Go to the WordPress back-end, activate, the Vuepress theme, and follow the instructions to install Rest-Easy.
npm run dev
- To build:
npm run build
- (Optional) To build and deploy to server using fh-deploy:
npm run deploy
Paste these anywhere in your <script>
tags to use them in your own templates. This assumes you've included
import _get from 'lodash/get'
All results from The Loop:
_get(this.$store, 'state.loop')
The first result from The Loop:
this.$store.getters.post
The featured image from the first result in The Loop:
_get(this.$store.getters.post, 'featured_attachment')
The children of the first result of The Loop:
_get(this.$store.getters.post, 'related.children')
Vuepress includes the Google/Typekit Web Font Loader in parts/font-loader.php
. Follow the instructions on that repo to load fonts from Google, Typekit, or your own uploads.
// font loader example
WebFontConfig = {
google: {
// your google fonts families here
families: []
},
typekit: {
id: ''
},
custom: {
// your custom font families here
families: [],
urls: [
'<?php echo get_template_directory_uri(); ?>/static/fonts/fonts.css'
]
}
}
-
Place the .svg file in
src/svgs/
. -
In the
script
section of the template where you want to use the SVG, add:import exampleSvg from 'src/svgs/example.svg' export default { data() { return { exampleSvg } } }
-
In the location where you want to use the SVG:
<div v-html="exampleSvg"></div>
That's it!
Vuepress comes with a component called responsive-image
that provides some built-in image handling, including fading in images as they load. You can pass an image object from Rest-Easy's attachment serializer and it will build itself automatically:
<!-- Build a responsive image component from the featured image of the first post in The Loop -->
<responsive-image :object="$store.state.loop[0].featured_attachment"/>
You can also include any of the following attributes:
<responsive-image
src="source-url"
height="height in px"
width="width in px"
aspect="aspect ratio, as percent (ie '56' for 56%)"
size="WordPress-defined size slug"
color="background color of pre-loaded space"
/>
You must include either an object
or a src
parameter on a responsive-image
element; all other values are optional.
All images in Vuepress have an associated video URL (saved as a metafield called custom_video_url
). You can access this in a serialized image in Vuex with image.videoUrl
.
Vuepress supports SCSS out of the box, and comes with a style vars file in src/styles/_vars.scss
and the base styling for the entire site in src/styles/_base.scss
.
You can import the vars file in any Vue template like this:
<style lang="scss">
@import 'src/styles/vars';
// Now you have access to the $vars!
</style>
Vuepress also comes with a few suggested breakpoints in that same vars file - you can use them in a media query like this:
@media #{ $lt-phone } {
// your styling
}
The default breakpoints (with lt
for "less than" and gt
for "greater than") are:
gt-cinema
-only screen and (min-width: 1800px)
lt-desktop
-only screen and (max-width: 1100px)
lt-phone
-only screen and (max-width: 750px)
lt-phone-landscape
-only screen and (max-width: 750px) and (orientation: landscape)
Since URLs can easily change in the WordPress backend, Vuepress includes a new WP role, Developer, that has access to a set of controls that other roles (even Administrator) can't see. One of these controls is for a page's "Developer ID" - an arbitrary value that can reliably identify a page.
The Developer ID is accessible via a post object's custom_developer_id
property - for example, $post->custom_developer_id
.
If we set the About page's Developer ID to about
, then rewrite the relevant line in add_routes_to_json
like the following:
...
// path_from_dev_id is a Vuepress function that retrieves a page's relative path from its Developer ID
path_from_dev_id('about') => 'About'
...
This will guarantee that the path to this page will always render the About template, even if the user changes that path later on.
The Developer role in Vuepress has a few extra capabilities available:
Any missing page in the add_routes_to_json
function (for example, if get_page_by_dev_id('about')
didn't find any pages) would break the given route; a Developer can lock pages to prevent this type of bug. Check the "Prevent non-dev deletion" box in the Developer Meta screen to prevent other users from placing that page in the Trash accidentally.
Check the "Hide Rich Editor" box to prevent non-Developer users from using WordPress's rich editor. This can be helpful to maintain stricter controls over the template and class names in a page's content.
Take a look at the path-to-regexp documentation for examples of routing using regex capabilities.
The routing table in Vuepress automatically converts a string-string key-value pair to a Vue route object:
array(
path_from_dev_id('my-developer-id') => 'MyComponentName'
)
...turns to:
const router = new VueRouter({
routes: [{ path: '/my-developer-id', component: 'MyComponentName.vue' }]
})
You can take advantage of the Vue router's more advanced capabilities, like redirect/alias, naming, and more by setting the value to an object:
array(
path_from_dev_id('your-developer-id') => array(
// Redirect to a path - in this case, to the path of the first child
'redirect' => get_child_of_dev_id_path('work')
),
path_from_dev_id('your-developer0id', '/:medium*') => array(
// Define a component and a name for the route
'component' => 'WorkGrid',
'name' => 'work-grid'
),
path_from_dev_id('your-developer-id') => array(
// Redirect to a named route
'redirect' => array(
'name': => 'work-grid'
)
)
)
This isn't the limit of the routing table's capabilities - anything the Vue router can do, you can build in the add_routes_to_json
function.
When trying to get the children of the front page, you'll need to use slug_from_dev_id
instead of path_from_dev_id
:
'/' . slug_from_dev_id('front-page') . '/:detail' => 'FrontPageChild',
path_from_dev_id
would return a slash as the relative path to the front page, but slug_from_dev_id
ensures that you're getting the front page's name.
Vuepress defines a few utility functions to make building the routing table easier:
get_child_of_dev_id($dev_id, $nth_child = 0)
- Get the post object of the nth child (zero-based, default0
) of a page with the given Developer ID.get_child_of_dev_id_path($dev_id, $nth_child = 0, $after = '')
- Get the relative path of the nth child of a page with the given Developer ID. Adds$after
to the retrieved path.get_children_of_dev_id($dev_id)
- Get the children of a page with the given Developer ID. Returnsfalse
if no page with Developer ID exists or an empty array if no children found.get_page_by_dev_id($dev_id)
- Get the first page with a given Developer ID. Returns the complete WP Post object orfalse
if none found.path_from_dev_id($dev_id, $after = '')
- Get the relative path of a page with a given Developer ID. Adds$after
to the retrieved path. Returns'#404'
if no page with the given Developer ID is found.slug_from_dev_id($dev_id)
- Get the slug of a page with a given Developer ID.user_is_developer()
- Boolean indicating whether the current logged-in user is a Developer or not.
If you need to upgrade your version of Rest-Easy, change the $latest_rest_easy
variable in functions/vuepress-plugins.php
to match the latest Rest Easy version. You'll be prompted to upgrade the next time you load any page on the WordPress backend.
Vuepress uses Vuex to handle a site's state. The default store in src/utils/store.js
is set up like this:
{
// From Rest-Easy
site: jsonData.site,
meta: jsonData.meta,
loop: jsonData.loop,
// Vuepress-specific
transitioning_in: false,
transitioning_out: false,
loaded: true
}
See the Rest-Easy documentation for more information on jsonData
and its properties, as well as the Vuex documentation for Vuex terms like store, state, mutation, etc.
You can commit a mutation from any Vue component by using:
this.$store.commit('MUTATION_NAME', payload)
Default Vuepress mutations:
'REPLACE_QUERYDATA', { site, meta, loop }
- Replaces thestore
'ssite
,meta
, andloop
properties with thesite
,meta
, andloop
properties of the payload.'SET_TRANSITIONING_IN, true | false'
- Setsstate.transitioning_in
to the given value.'SET_TRANSITIONING_OUT, true | false'
- Setsstate.transitioning_out
to the given value.'SET_LOADED', true | false
- Setsstate.loaded
to the given value.'OPEN_MENU'
- Setsstate.menuOpened
totrue
.'CLOSE_MENU'
- Setsstate.menuOpened
tofalse
.'UPDATE_REFERRAL_ROUTE'
- Setsstate.referral
to given referral object.
Where mutations are synchronous, actions are asynchronous:
this.$store.dispatch('ACTION_NAME', payload)
Default Vuepress actions:
'LOAD_AND_REPLACE_QUERYDATA, { path: 'url string' }'
- Runs the following process:- Sets
state.loaded
tofalse
. - Checks
src/utils/cache.js
(which is a global cache that can beimport
ed into any other file) for the givenpath
key. If none is found:- Commits
'SET_LOADED', false
- Fetches the data from the the URL at the payload path.
- Saves the data to the cache.
- Commits
- Commits
'REPLACE_QUERYDATA'
with the data from the cache. - Commits
'SET_LOADED', true
- Sets
Getters are shortcuts to dynamic state properties:
$store.state.getters.desiredGetter
Default Vuepress getters include:
loading
- Returns the opposite of$store.state.loaded
.post
- Returns either the first post in$store.state.loop
or, if none, an empty object.referralPath
- Returns either thefullPath
of the current value of$store.state.referral
or, if none, an empty string.
Throttled resize and scroll events are available to any child of the App component:
this.$root.$on('throttled.resize', () => {
// your throttled resize event here...
// default: 1 per 10ms
})
this.$root.$on('throttled.scroll', () => {
// your throttled scroll event here...
// default: 1 per 10ms
})
Both events are fired after the $root
element saves updated window dimensions/scroll positions for resize/scroll events.
Vuepress comes with a few SCSS partials to make writing CSS easier. In a Vue template file:
<style lang="scss">
@import 'src/styles/desired-partial';
</style>
Default partials include:
-
base
- Style applied inApp.vue
, affecting every page on the site. -
easings
- Several common easing functions. Includes:- easeIn, easeOut, and easeInOut for:
- Sine
- Quad
- Cubic
- Quart
- Quint
- Expo
- Circ
- Back
- Fast
- authenticMotion
- easeIn, easeOut, and easeInOut for:
-
transitions
- Common transitions applied inApp.vue
, affecting every page on the site. Includes:fade
slide-left
slide-right
Usable with:
<transition name="transition-name"><your-code-here/></transition>
-
vars
- Variables to use across the site. Import in any given template to make global CSS changes much easier to manage. Defaults include:$white: #ffffff;
$black: #000000;
$font-family: 'Helvetica';
$desktop-padding: 50px;
$mobile-padding: 20px;
$header-height: 80px;
The following are breakpoints that can be used with
@media #{$size} { /* your rules here */ }
:$gt-cinema: "only screen and (min-width: 1800px)";
$lt-desktop: "only screen and (max-width: 1100px)";
$lt-phone: "only screen and (max-width: 750px)";
$lt-phone-landscape: "only screen and (max-width: 750px) and (orientation: landscape)";
vars
includes the following mixins:fill
-position: absolute
withtop
,right
,bottom
, andleft
set to0
.cover
- Centered, no-repeat,background-size: cover
.contain
- Same ascover
, but withbackground-size: contain
.
Vuepress comes with fh-deploy to make deploying your site as easy as possible.
Run npm run deploy
to generate a config file based on a few user inputs. The queue of files to upload is in the package.json files
property. npm run deploy
automatically runs npm run build
and sends the queued files to your server!
Important note from fh-deploy readme:
Running fh-deploy will automatically overwrite any files of the same name on your server WITHOUT prompting. Assume your remote files are going to be overwritten as soon as you run fh-deploy and make sure you keep up-to-date backups!
Not Vuepress-specific reading material, but rather good practices and articles.
- Maintainable CSS, a guide to writing readable and easily-maintained CSS
- SVG Tips for Designers
Vuepress
Version: 1.1.6
- 1.1.6 - New user tutorial available, trimmed down readme, several misc fixes
- 1.1.5 - Several misc fixes, added fh-deploy version control in package.json
- 1.1.4 - Restructuring according to this issue
- 1.1.3 - Split Vuepress functionality into
/functions
directory - 1.1.2 - Added TGM Plugin Activation to require plugins. Switching to x.x.x version numbering.
- 1.11 - Switched
_custom_developer_id
tocustom_developer_id
- 1.1 - Switched
_custom_guid
to_custom_developer_id
- 1.0 - Initial release