Giter Site home page Giter Site logo

bshiluk / vue-wordpress Goto Github PK

View Code? Open in Web Editor NEW
482.0 34.0 114.0 843 KB

Use Vue.js and the WP REST API to build WordPress themes as SPAs with dynamic routing, HMR for development, SEO enabled, and SSR capable. Demo:

Home Page: http://vue-wordpress-demo.bshiluk.com

PHP 24.57% Vue 51.95% JavaScript 21.52% CSS 1.97%
vue vuejs vuejs2 wp wordpress wordpress-theme starter-theme spa

vue-wordpress's Introduction

Vue.wordpress icon

Vue.wordpress

A Wordpress starter theme built using the WP REST API and Vue.js. Optimized for SEO, performance, and ease of development.

This theme is intended to be used as a foundation for creating sites that function as a single-page application (SPA) on the front-end, while using Wordpress and the WP REST API to manage content and fetch data.

Check out a demo of the theme

Table of Contents

Features

  • Front and Back-End run on same host
  • Supports various client/server code partitioning strategies for optional SEO optimization
  • Hot Module Replacement ( HMR ) for development
  • Vue.js Single File Components
  • Production / Development Webpack configurations
  • Dynamic routing as set up in WP Dashboard ( Settings > Permalinks )
  • Vue Router internal link delegation ( no need to use <router-link /> in components )
  • Document title tag update on route change
  • Consistent in-component REST API data fetching
  • Integrated REST API request caching and batching
  • REST API Data Localizer for state initialization and making back-end REST API requests
  • Normalized data structure
  • Pagination enabled
  • Utility components, including ResponsiveImage, SiteLoading, ArchiveLink, e.t.c.

Libraries

To promote flexibility in implementation, styling and dependencies are limited. That said, the theme requires the following libraries:

Usage

  1. Clone or download this repo in your /wp-content/themes directory and activate
  2. Clone or download the REST API Data Localizer companion plugin in your /wp-content/plugins directory and activate.
  3. Ensure settings in Settings > Permalinks do not violate rules as described in Routing.
  4. Install dependencies npm install.
  5. Build the theme npm run build

Development

  1. Start development with HMR npm run dev
  2. Edit functions.php so Wordpress enqueues the bundle served from webpack dev server
// Enable For Production - Disable for Development
// wp_enqueue_script('vue_wordpress.js', get_template_directory_uri() . '/dist/vue-wordpress.js', array(), null, true);

// Enable For Development - Remove for Production
wp_enqueue_script( 'vue_wordpress.js', 'http://localhost:8080/vue-wordpress.js', array(), false, true );

Deployment

  1. Build the theme npm run build
  2. Only include Wordpress theme files ( i.e. style.css, functions.php, index.php, screenshot.png e.t.c.) and the /dist/ directory
  3. Edit functions.php so Wordpress enqueues the bundle served from your /dist/ directory
// Enable For Production - Disable for Development
wp_enqueue_script('vue_wordpress.js', get_template_directory_uri() . '/dist/vue-wordpress.js', array(), null, true);

General Overview

  1. Wordpress creates initial content and localizes a __VUE_WORDPRESS__ variable with initial state, routing info, and any client side data not accessible through the WP REST API.
  2. Client renders initial content, and once js is parsed, __VUE_WORDPRESS__ is used to create the Vuex store, Vue Router routes, and the app is mounted.
  3. Vue takes over all future in-site navigation, using the WP_REST_API to request data, essentially transforming the site into a SPA.

Routing

Permalinks to Routes

By default, routing works as defined in Settings > Permalinks. You can even define a custom structure.

Settings > Permalinks Screenshot

✔️ 'Day and Name' /%monthnum%/%day%/%postname%/

✔️ 'Month and Name' /%year%/%monthnum%/%day%/%postname%/

✔️ /my-blog/%category%/%postname%/

✔️ /%postname%/%author%/%category%/%year%/%monthnum%/

Exceptions

Using 'Plain', 'Numeric', or any custom structure that uses %post_id% as the sole identifier.

/%year%/%monthnum%/%post_id%/

/archives/%post_id%/

However, if you combine the %post_id% tag with the %postname% tag it will work.

✔️ /%author%/%post_id%/%category%/%postname%/

If for some reason you're set on using the post id in your permalink structure, editing the Single.vue component to use id as a prop and fetching the post by id instead of slug should make it work.

Using 'Post name'

/%postname%/

However, you can add a base to make it work

✔️ /some-base/%postname%/

Notes on Permalink Structure

  • Using /%category%/%postname%/ or /%tag%/%postname%/ will cause problems with nested pages
  • Problems with the permalink structure are generally because the router can't differentiate between a post and a page. While this may be solved with Navigation Guards and in component logic to check data and redirect when necessary, the introduced complexity is out of scope for this starter theme.
  • Routes for custom post types will be needed to be added as needed.
  • Routing is by default dynamic, however when a structure is defined it could be in the best interest of the developer to refactor out some of the dynamic qualities.

Category and Tag Base

If you want to edit the category and tag permalink bases within the same Settings > Permalinks screen, that is supported as well.

Homepage and Posts Per Page

Additionally, in Settings > Reading you can adjust what your home page displays and posts shown per page ( labeled 'Blog pages to show at most' ).

Internal Link Delegation

Within a Vue application, all links not implemented with <router-link /> trigger a full page reload. Since content is dynamic and managed using Wordpress, links within content are unavoidable and it would be impractical to try and convert all of them to <router-link />. To handle this, an event listener is bound to the root app component, so that all links referencing internal resources are delegated to Vue Router.

Adapted from Dennis Reimann's Delegating HTML links to vue-router

This has the added benefit of being able to compose components using the 'link' property returned from WP REST API resources without having to convert to a relative format corresponding to the router base for <router-link />.

Instead of:

<router-link :to="convertToRelative(tag.link)">{{ tag.name }}</router-link>

You can do:

<a :href="tag.link">{{ tag.name }}</a>

State Management and API Requests

A Vuex store is used to manage the state for this theme, so it is recommended at the very least to know what it is and become familiar with some of the core concepts. That said, you'd be surprised at the performant and user-friendly themes you can build without even modifying the Vuex files in /src/store/.

Vuex Initialization and Schema

Normally, you would find the schema ( structure ) of a Vuex store in the file that initializes it (or an imported state.js file ). Even though it is initialized in /src/store/index.js, the schema is defined in functions.php. This allows you to use the use the REST API Data Localizer to prepopulate the store with both WP REST API data in addition to any other data you may need for your state not available through the WP REST API.

Schema

// functions.php 

new RADL( '__VUE_WORDPRESS__', 'vue_wordpress.js', array(
    'routing' => RADL::callback( 'vue_wordpress_routing' ),
    'state' => array(
        'categories' => RADL::endpoint( 'categories'),
        'media'      => RADL::endpoint( 'media' ),
        'menus'      => RADL::callback( 'vue_wordpress_menus' ),
        'pages'      => RADL::endpoint( 'pages' ),
        'posts'      => RADL::endpoint( 'posts' ),
        'tags'       => RADL::endpoint( 'tags' ),
        'users'      => RADL::endpoint( 'users' ),
        'site'       => RADL::callback( 'vue_wordpress_site' ),
    ),
) );

Initialization

As you can see below, the __VUE_WORDPRESS__.state key is used to initialize the Vuex store.

// src/store/index.js

const { state } = __VUE_WORDPRESS__

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions
})

More advanced implementations may want to decouple this localized store from the Vuex store, but I think it decreases the initial complexity.

Requesting Data

Making WP REST API Requests

You will not see any WP REST API requests within the components of the theme. Instead, Vuex actions are dispatched signalling a need for asynchronous data. If the data is not available in the store, only then is a request made. When the request is returned the response data is added to the store.

Request Caching

Every time there is a request for a list of items, a request object is generated once the response is received.

// Example request object
{
  data: [ 121, 221, 83, 4, 23, 76 ], // ids of items 
  params: { page: 1, per_page: 6 }, 
  total: 21,
  totalPages: 4 
}

This object is added to the store and next time a list of items of the same type and params are requested, the data key is used to create the response instead of querying the server.

Note that these request objects are not created for requests for a single resource by its identifier because checking the store for them before making a request is trivial.

Actions Api Reference

Request an item of type by its slug

this.$store.dispatch('getSingleBySlug', { type, slug, showLoading })
  • type is the key in the store and the endpoint for the resource
    • string
    • required
  • slug is the alphanumeric identifier for the resource
    • string
    • required
  • showLoading indicates whether a loading indicator should be shown
    • boolean
    • default: false
Example
// request a page with slug 'about' and show loading indicator
this.$store.dispatch('getSingleBySlug', { type: 'pages', slug: 'about', showLoading: true })

Request an item of type by its id

this.$store.dispatch('getSingleById', { type, id, batch })
  • type is the key in the store and the endpoint for the resource
    • string
    • required
  • id is the numeric identifier for the resource
    • number
    • required
  • batch indicates whether a short delay will be added before making the request. During this delay any requests with duplicate ids are ignored and ids of the same type are consolidated into a single request using the include WP REST API argument.
    • boolean
    • default: false

View the theme demo, open the Network panel of your browser, and navigate to a posts feed to see the batch feature in action.

Examples
// request a tag with an id of 13 with batching
this.$store.dispatch('getSingleById', { type: 'tags', id: 13, batch: true })
// request a tag with an id of 21 with batching
this.$store.dispatch('getSingleById', { type: 'tags', id: 21, batch: true })

// Even if these are called from different components or instances of the same component, the batched request would look like /wp/v2/tags/?include[]=13&include[]=21&per_page=100

Request a list of items

this.$store.dispatch('getItems', { type, params, showLoading })
  • type is the key in the store and the endpoint for the resource
    • string
    • required
  • params are the parameters to use for the request
    • Object
    • required
  • showLoading indicates whether a loading indicator should be shown
    • boolean
    • default: false
Example
// request the first page of the most recent posts limited to 10 posts per page
this.$store.dispatch('getItems', { type: 'posts', params: [ page: 1, per_page: 10, orderby: 'date', order: 'desc' ] })

Getters Api Reference

You'll notice the arguments for the getters are a subset of their corresponding action arguments. This is because the actions use the getters themeselves to make sure the data is not already in the store before making a request.

Get an item of type by slug

this.$store.getters.singleBySlug({ type, slug })

Get an item of type by id

this.$store.getters.singleById({ type, id })

Get a list of items

this.$store.getters.requestedItems({ type, params })

SEO and Server Rendered Content

How It Works

What enables SEO and server rendered content with this theme is the routing. The Vue app routing mirrors that of how Wordpress resolves query strings to templates using the Template Hierarchy. So, on the server side, you know exactly what data the app will need when it renders at a specific location. The problem then becomes how to render the app with that data. Technically, the WP loop and template functions could produce output for crawlers, but it would be unusable for the app. Instead, the REST API Data Localizer is used to simulate the relevant GET requests internally corresponding to the WP template loaded, and localize that response data for the app on render.

The Three Basic Approaches

Each approach provides either explicit setup or specific examples and includes the php knowledge required to implement.

Pseudo Headless

Minimal to no php knowledge required

With this implementation, all you need is an index.php file that renders the element the app will mount on. Add your <html>, <head>, <meta>, and <body> tags, and call wp_head() and wp_footer(). These calls ensure Wordpress still manages <title>, adds <meta>, and enqueues scripts and stylesheets as configured.

Example index.php
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
    <head>
        <meta charset="<?php bloginfo( 'charset' ); ?>">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <?php wp_head(); ?>
    </head>
    <body>
        <div id="vue-wordpress-app">
            <!-- Enhancing this approach, you could show
            a loading indicator here while your app js
            is parsed and data is fetched -->
        </div>
        <?php wp_footer(); ?>
    </body>
</html>

Optionally, you can remove wp_head(), or wp_footer(), or even both and hard code in your <script>, <style> and <link> tags. In this case, the REST API Data Localizer would be incompatible and you would need to refactor the initialization of Vuex and Vue Router so they weren't dependent on its localized data.

Pseudo Headless SEO

Crawlers will no longer be able to properly index your site because even if they could parse js, they would still need asynchronous data on initialization. However, if SEO is not a concern of yours, no harm no foul. On the other hand, assuming you call wp_head() and the routing is properly synced, social sharing links should still work properly, as wp_head() manages meta in the <head> of your site.

Preload Data

Minimal php knowledge required

This approach allows you to eliminate all initial REST API requests, effectively decreasing initial time to interactive, and allowing crawlers that can render js to index your content. Wordpress resolves the query and uses the appropriate template as per the Template Hierarchy. Within these templates, you can just make the appropriate requests based on your apps needs. Since the Vue Router route components correspond to the WP templates this becomes straightforward.

The examples below will utilize the REST API Data Localizer and assume a schema as shown here. If you are confused on its usage follow the link and refer to the docs.

Example single.php

Assuming you need the post and its featured media, categories, and tags.

<?php
get_header();

$p = RADL::get( 'state.posts', get_the_ID() );
RADL::get( 'state.media', $p['featured_media'] );
RADL::get( 'state.categories', $p['categories'] );
RADL::get( 'state.tags', $p['tags'] );

get_footer();
Example category.php

Assuming you need the category, and N posts from X page that have that category ( N refers to the posts per page set in Settings > Reading ).

<?php
get_header();

$category_id = get_query_var('cat');
$per_page = RADL::get( 'state.site' )['posts_per_page'];
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;


RADL::get( 'state.categories', $category_id );
RADL::get( 'state.posts', array(
    'page' => $paged,
    'per_page' => $per_page,
    'categories' => $category_id
) );

get_footer();

The preceding examples use get_header() and wp_footer(), which are Wordpress functions that include the header.php and footer.php files respectively. If these functions were used in the Pseudo Headless Example there would be three files that looked like this:

index.php

<?php
get_header(); ?>
<!-- Enhancing this approach, you could show
a loading indicator here while your app js
is parsed and data is fetched -->
<?php
get_footer();

header.php

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
    <head>
        <meta charset="<?php bloginfo( 'charset' ); ?>">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <?php wp_head(); ?>
    </head>
    <body>
        <div id="vue-wordpress-app">

footer.php

</div><!-- #vue-wordpress-app -->
<?php wp_footer(); ?>
</body>
</html>
Preload Data SEO

When you preload required data, the Vue instance has everything it needs on render. This allows crawlers that can render js to index your site appropriately. However, it should be mentioned that just because these crawlers have the capability of rendering the js before indexing it doesn't mean they will. Here's an article about it for more information.

Of course the added UX benefit of this approach is that the end users will be able to interact with the content pretty much immediately ( after the js is parse and rendered, and not have to wait for the app to fetch data ).

Progressive Enhancement

Intermediate php knowledge required

The third and final approach involves recreating the php templates with the REST API Data Localizer corresponding to your different route components. The beauty of the approach is that you don't have to ( and probably shouldn't ) fully recreate how the Vue instance renders the app in your templates. You can opt for a progressive enhancement approach, creating skeleton templates that Vue enhances on render. By default, the theme fully recreates these templates, but it is a starter theme, so this makes sense. You can see this by viewing the theme demo, disabling javascript in the developer tools, and reloading the site.

Example home.php
<?php
get_header();
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$per_page = RADL::get( 'state.site' )['posts_per_page'];
$posts = RADL::get( 'state.posts', array( 'page' => 1, 'per_page' => $per_page ) ); ?>

<main>
    <section>

        <?php
        foreach ( $posts as $p ) {
            set_query_var( 'vw_post', $p );
            get_template_part( 'template-parts/post-item' );
        } ?>

    </section>

    <?php
    get_template_part( 'template-parts/pagination' ); ?>

</main>

<?php
get_footer();
  • get_template_part() is a wp function that includes the php template using the argument passed
  • set_query_var() is another wp function that sets variables you can access through get_query_var() in your template-part ( you can't pass arguments to get_template_part() )
  • Notice that the query vars set correlate to what's passed to the props of the vue component
  • If you want to see the post-item and pagination files refer to the /template-parts/post-item.php and /template-parts/pagination.php
Progressive Enhancement SEO

Crawlers can index your content and you don't have to rely on their ability to render js. Your users get content instantly without waiting for the Vue instance to render. The perceived load time is improved further as users get content instantly and enhanced with functionality and additional content once the Vue instance renders.

Upcoming Features

I do plan to extend the functionality of the theme depending on whether developers find it useful. Some things I plan to add support for ( in no particular order ) include:

  • Search
  • Comments
  • Page Templates
  • Post Formats
  • Widgets
  • ACF
  • Dynamic routing for custom post types

Final Thoughts

I hope you found this documentation useful. If there are any other topics you would like me to cover, or need clarification on feel free to add an issue.

vue-wordpress's People

Contributors

bshiluk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-wordpress's Issues

Error when installing Rest API Data Localizer plugin

Hey Bucky! This theme looks like exactly what I am trying to achieve when integrating Vue and Wordpress.

Running into the following issue when installing the localizer plugin:

Warning: require(/app/public/wp-content/plugins/rest-api-data-localizer/store/key/callback.php): failed to open stream: No such file or directory in /app/public/wp-content/plugins/rest-api-data-localizer-master/radl.php on line 62 Fatal error: require(): Failed opening required '/app/public/wp-content/plugins/rest-api-data-localizer/store/key/callback.php' (include_path='.:/usr/share/php:/www/wp-content/pear') in /app/public/wp-content/plugins/rest-api-data-localizer-master/radl.php on line 62

Running this locally on NGINX / PHP 7.2

Any Idea? Thank you for your work on this.

Custom post type routing

Hello,

I am using this vue- wordpress theme, I have added custom post type but I am facing issue with routing. Could you show me where I can change for routing for custom post type.

I have tried changing in routes.js and path.js but it's not working for me. So please help me with this.

Expecting reply from your end ASAP.

Thank you in Advance.

Use Wordpress shortcodes in a component

Hello,

In one of my page's content, I put a shortcode from the WpForms plugin to display a contact form.
When I access this page by using routes from my SPA, the JS and CSS files of WpForms are not attached.
However if I'm opening this page with its direct link, the JS and CSS files are attached.

How can I load the WP plugin's assets only on the contact page route?

Thank you.

Initialize project

Hi all!
I'm totaly newbie here.
I'm trying to deploy this theme on local machine. After pressing "activate" on rest-api-data-localizer plugin in WP dashboard - an error appears Fatal error: require(): Failed opening required '/Users/admin/Projects/mamp/zzz/wp-content/plugins/rest-api-data-localizer/store/key/callback.php' (include_path='.:/Applications/MAMP/bin/php/php7.1.32/lib/php') in /Users/admin/Projects/mamp/zzz/wp-content/plugins/rest-api-data-localizer-master/radl.php on line 62
The destination in the error is correct and there is callback.php file in /Users/admin/Projects/mamp/zzz/wp-content/plugins/rest-api-data-localizer/store/key folder.
Runing this on mamp with php 7,1.
Any help is appreciated.

Make pagination for my custom component

Hi there, sorry to bother you again. Hoping for some advice from you.

If i understand correctly, the current pagination component is dependent on the route path to fetch the current page number.

I am making some custom components to create post grids and was wondering how to create pagination for the said component independent of the route path since there's no need to change the route and there will be multiple grids on the single page.

I have created something similar before like so:

var postsList = new Vue({
                el: "#app",
                data: {
                    posts: [],
                    page: 1,
                    perPage: 10,
                    pageNumber: ''
                },
                mounted: function() {
                    this.fetchData();
                },
                methods: {
                    fetchData: function( page = this.page, perPage = this.perPage ) {

                        axios.get( '/wp-json/wp/v2/gallery', { 
                            params: {
                                    per_page: perPage,
                                    page: page
                            }
                        })
                        .then(response => {
                            this.posts = response.data,
                            this.pageNumber = response.headers['x-wp-totalpages']
                        })
                        .catch((error) => {
                                console.error(error)
                        })
                    }
                },
                watch: {
                    "perPage": function(pp) {
                        if(pp < 10 && pp > 0){
                        this.fetchData(1, pp);
                        this.page = 1;
                        }
                    }
                }

            })
<nav>
    <button type="button" v-if='page > 1' v-on:click="fetchData(page -= 1)" class="btn nav-prev">Newer</button>
    <button type="button" v-if='page != pageNumber' v-on:click="fetchData(page += 1)" class="btn nav-next">Older</button>
</nav>

I am a bit confused as to how to create the pagination with how the theme is currently setup.
This is my grid component:

<template>
    <div class="sw-module">
        <div class="sw-fa-wrapper sw-grid-1">
          <div v-if="posts.length" class="sw-fa-grid">
              <post-list
                v-for="post in posts"
                :key="post.id"
                :post="post"
                :size="post.media_414x276"
              />
          </div>
        </div>
  </div>
</template>

<script>
import PostList from '@/components/grids/PostList'
import ListPagination from '@/components/grids/ListPagination'

export default {
  name: 'GridOne',
  components: {
    PostList,
    ListPagination
  },
  props: {
    type: {
      type: String,
      required: true
    },
    offset: {
      type: Number,
      required: false
    },
    per_page: {
      type: Number,
      required: false
    }
  },
  data() {
    return {
      request: {
        type: this.type,
        params: { 
          per_page: this.per_page || this.$store.state.site.posts_per_page,
          offset: this.offset,
          page: 1
        }, 
        showLoading: true 
      },
      totalPages: 0
    }
  },
  computed: {
    posts() {
      return this.$store.getters.requestedItems(this.request)
    }
  },
  methods: {
    getPosts() {
      return this.$store.dispatch('getItems', this.request)
    },
    setTotalPages() {
      this.totalPages = this.$store.getters.totalPages(this.request)
    }
  },
  created() {
    this.getPosts().then(() => this.setTotalPages())
  }
}
</script>
<grid-one 
          type="video"
          :per_page=3
      />

Buddypress integration

I am wondering if it's possible to integrate this BP rest api plugin in this theme. If so, can you please explain a bit, how to go about it.

Thank you for your time and thank you for making this theme. Having fun learning here.

Using <router-link>?

I wanted to know why not using the <router-link>? We could use the benefit that comes with it, as such as the class="active" on the current & clicked nav item.

How do other folks deal with the class="active" on their theme?

Path for languages

Hi,
It's possible to add language paths in the routing file, but I've noticed that they're not working.

Thanks a lot

Newbie trying to make sense of it.

Hi. I will intensely work with this for the next few weeks (or at least, this is what I highly hope to do if my manager allows the project to continue).

I am a beginner in Vue, like, really nub. I know the basics, I understand the MVC model, the directives and stuff like that. My issue:

Is anybody here available for a couple of hours of chit chat on this subject? I'm seeking for help to understand the following:

  • How does the Vue receive the data from WordPress - How can I alter this, and how can I add post types and meta fields (from acf, for example) to my Vue?

  • How can I make components behave based on an external state, or ones state (actually I have a pretty good idea about this but haven't done it yet so I'll just lay it off here)?

  • How can I make it valid and make sure I don't write shitty code?

There are surely more How to's but I haven't hit them yet.

Even if no response is given to this issue, I am willing to discover those and log them here; for new people that might be using this and find their selves in this situation.

Hopefully it's approved for display,
Kind regards.

theme support

hey bucky, not an issue, rather a request: i want to support you supporting that theme. like catching up on the roadmap etc.
tell me how i can help, even if its simply money. but i do like what i see with that theme and i'd like to see it evolve..

Lazy Load Routes

This may be outside of the scope of the project, but can you give any insights or advice on getting code splitting/lazy loading routes to this theme?

Bundle sizes can get out of control, so having this would put this theme over the top of anything else I've found.

Thanks!

Form plugin ajax submit not working

Hi, thank you for the theme.

I would like to develop this theme into an interactive forum (like bbpress). I have some experience in working with Wordpress but I'm still new to Vue. I usually use a form plugin called Formidable Forms for user interactions within my site.

  1. I created a "Submit a forum topic" form for users to submit new topic. I tried integrating the form plugin, using shortcodes in pages, within this theme. It does submit the topic correctly, however, it reloads the page. The form has a "submit with ajax" option but it isn't working here.

  2. Can you please guide me in how to make the comment system work (validation, submission, pagination & replying on comments) in this so that users can comment on the topics?

  3. How do I get the logged in user info? Do I need to create a callback in the RADL or is it already integrated in the theme.

Cannot run the dev mode (npm run dev)

Hi @bucky355
Thanks for this awesome work you made with this repo. Very interesting aproach. I'll give it a try.

So far it's all working. Except that I can't run the dev mode (meaning: npm run dev). "npm run build" is perfectly working though.

The steps I tried (following your docs):
1.) startet "npm run dev" in the console, where the theme lives (seems to work: "compiled successfully")
2.) edited functions.php as described
3.) I open the url (localhost:8080) and only get a listing with files and folders of the root folder in my WordPress theme.

grafik

What am I doing wrong?

Thanks so much for helping me out.

Cheers

Michael

Woocommerce routing

Hi!

Can anyone point me in the right direction on how can routing properly for woocommerce ?
Actually, I follow the steps from [#15], but still not working.

Any solutions? Thanks in advance.

Searchpage

i used Open Search to compile the results page, i created search.php file but the page return me allways 40 template.

Whats wrong?

Bye

Page routes load Single.vue

I'm trying to open open single pages and instead of rendering the component Page.vue it renders the Single.vue component giving me this error

image

I thought this is was my issue and was worried that the vue-router could not distinguish the difference between a post and a page, because the URL was basically the same (which was a bad thought on my part).
I used the url http://vue-wordpress-demo.bshiluk.com/wp-json/wp/v2/pages and saw that you were in fact navigating between POSTS and Pages with no problems.

I don't know what else to do , i even cloned the repository again to try to reproduce the errors, and without changing any code the error ocurred again.

Sorry to bother , but i could use the help.

The only diferrence between my code and yours right now, is that i use dynamic routing

routes.js

import { loaderPage } from '@helpers/loaderComponents';

and for example

 {
    path: '/404',
    component: loaderPage('NotFound'),
    name: '404'
  },

loaderComponent.js

export const loaderComponent = (path) => () => import(/* webpackChunkName: '[request]' */ `@components/${path}`).then(m => m.default || m);
export const loaderPage = (path) => () => import(/* webpackChunkName: '[request]' */ `@pages/${path}`).then(m => m.default || m);

I can navigate to posts, author page and categories pages with no problem, but as soon as i enter a page it does not load

Problems with sass

Hi, thanks for the topic it is very good
I couldn't install sass it generates errors and I tried to install many npm of scss but I manage to advance the maximum that I have advanced in this is with this error.

ERROR in ./src/app.js Module not found: Error: Can't resolve './scss/styles.scss' in 'C:\laragon\www\demo2a\wp-content\themes\vue-wordpress\src' @ ./src/app.js 5:0-28 @ multi (webpack)-dev-server/client?http://localhost:8080 (webpack)/hot/dev-server.js ./src/app.js i 「wdm」: Failed to compile.

this is my json
{ "name": "vue-wordpress", "private": true, "scripts": { "dev": "webpack-dev-server --env=dev", "build": "webpack --env=prod" }, "devDependencies": { "@babel/core": "^7.2.2", "axios": "^0.18.0", "babel-core": "^6.26.3", "babel-loader": "^8.0.5", "babel-preset-env": "^1.7.0", "babel-preset-stage-3": "^6.24.1", "cross-env": "^5.2.0", "css-loader": "^2.1.0", "mini-css-extract-plugin": "^0.5.0", "node-sass": "^5.0.0", "sass": "^1.54.5", "sass-loader": "^10.0.5", "vue": "^2.6.6", "vue-loader": "^15.6.2", "vue-router": "^3.0.2", "vue-style-loader": "^4.1.2", "vue-template-compiler": "^2.6.6", "vuex": "^3.1.0", "webpack": "^4.46.0", "webpack-cli": "^3.2.3", "webpack-dev-server": "^3.1.14" }, "dependencies": { "@types/sass": "^1.43.1", "@types/sass-loader": "^8.0.3" } }
Thank you

Doesn't work if slug contains HTML entities

Hi again,
Another small issue. It fails to fetch the data if the slug contains html entities /wp-json/wp/v2/pages/?slug=this-is-a-%E0%A5%90-page. Happens with posts as well as pages.

Widgets

Can you tell me how to create sidebar and widgets in footer?

Yoast SEO title

Have you noticed that when you use Yoast SEO and write a custom meta title and then reload the frontend that the page title changes to the page name - site name.

Is this being changed through the vue app?

'Watch' not working with 'getItems' action?

Hi, I am trying to set up a search page and am trying to use v-model in a custom component, however, watching the v-model property is not updating 'getItems'. I see the changes getting reflected in the vue development tools in the postsRequest.params but i'm unable to fetch the updated items and the posts computed property remains unchanged.

I asked this question on stackoverflow and and a user has commented this:

you are watching searchAuthor so when it changes you are mutating the postsRequest object then calling the store action getItems (also the syntax is correct but i'm not sure what exactly it does... if you don't see the data change then it is the reason) so you need to understand what this API is doing to your store after you give it the data objects.

I'd appreciate if you could point me in the right direction.

My code:

<template>
  <main class="site-content">
    <div class="container">
        <div class="advanced-search">
            <input type="text" 
                name="searchTerm"
                placeholder="Search title..." 
                tabindex="1"
                v-model="searchTerm">
            <select v-model="searchAuthor">
                <option value="">All</option>
                <option 
                    v-for="author in authors"
                    :value="author.id"
                    :key="author.id">{{ author.name }}</option>
            </select>
            <select v-model="searchTopic">
                <option value="">All</option>
                <option 
                    v-for="topic in topics"
                    :value="topic.id"
                    :key="topic.id">{{ topic.name }}</option>
            </select>

        </div>
    
        <section v-if="posts">
            <post-item
                v-for="post in posts"
                :key="post.id"
                :post="post"
            />
        </section>
    </div>
  </main>
</template>

<script>
import PostItem from '@/components/template-parts/PostItem'

export default {
    name: 'Search',
    components: {
        PostItem,
    },
    data() {
        return {
            postsRequest: {
                type: 'quote',
                params: {
                    per_page: 5,
                    search: null,
                    authors: null,
                    tags: null
                },
                showLoading: true
            },
            authorsRequest: {
                type: 'authors',
                params: {
                    per_page: 100,
                },

            },
            topicsRequest: {
                type: 'tags',
                params: {
                    per_page: 100,
                },
            },
            searchTerm: '',
            searchAuthor: '',
            searchTopic: ''
        }
    },
    watch: {
        "searchAuthor": function() {
            this.postsRequest.params.search = null
            this.postsRequest.params.authors = this.searchAuthor
            this.postsRequest.params.tags = null
            this.getPosts()
        },
        "searchTopic": function() {
            this.postsRequest.params.search = null
            this.postsRequest.params.authors = null
            this.postsRequest.params.tags = this.searchTopic
            this.getPosts()
        },
        "searchTerm": function() {
            this.postsRequest.params.search = this.searchTerm
            this.postsRequest.params.authors = null
            this.postsRequest.params.tags = null
            this.getPosts()
        }
    },
    computed: {
        authors () {
            return this.$store.getters.requestedItems(this.authorsRequest)
        },
        topics () {
            return this.$store.getters.requestedItems(this.topicsRequest)
        },
        posts() {
            return this.$store.getters.requestedItems(this.postsRequest)
        }
    },
    methods: {
        getAuthors() {
            return this.$store.dispatch('getItems', this.authorsRequest)
        },
        getTopics() {
            return this.$store.dispatch('getItems', this.topicsRequest)
        },
        getPosts() {
            return this.$store.dispatch('getItems', this.postsRequest)
        },
    },
    created() {
        this.getAuthors()
        this.getTopics()
        this.getPosts()
    },
}
</script>

search

localhost:8080 list files

I am running WordPress in Nginx.
installed everything like it's said in the doc.

Enabled dev mode

// Enable For Production - Disable for Development
// wp_enqueue_script('vue_wordpress.js', get_template_directory_uri() . '/dist/vue-wordpress.js', array(), null, true);

// Enable For Development - Remove for Production
wp_enqueue_script( 'vue_wordpress.js', 'http://localhost:8080/vue-wordpress.js', array(), false, true );

then

npm run dev

http://localhost:8080/

Now when i visit http://localhost:8080/ i get directory list, but when i visit mysite.local i get plain wordpress without any vueJs component

Issue using polylang and vue-js

Hello i recently submited an issue , and tought it was resolved, but i was wrong!

So, I'm using polylang and vue js , i need to translate articles and pages from Portuguese to English. At first i thought there was a problem with my routes.js and i added:

{
    path: '/:slugs+',
    component: loaderPage('Page'),
    name: 'Page',
    props: route => ({ slug: route.params.slugs.split('/').filter(s => s).pop() })
  },
  {
    path: '/en/:slugs+',
    component: loaderPage('Page'),
    name: 'PageEn',
    props: route => ({ slug: route.params.slugs.split('/').filter(s => s).pop() })
  },

But i'm finding tons of bugs that i can get through, for example when switching to an english page, the vue program loads the "Single.vue" instead of the "Page.vue" ...The navbar does not change :(

But if i refresh the page or if i enter through an url the page and the navbar loads fine
The bugs usually ocurr while i browse in the program.
Furthermore the vue program also loads all of the articles , both the portuguese and the english :/
The poly lang plug in usually takes care of all the logic behind the language switch, but when used with vue it has lots of bugs!

This is more of a question than an issue! HOpe you could give me some help!
thanks in advance !

Which version of nodejs do you use?

Library/Caches/node-gyp/14.4.0/include/node/v8.h:3642:37: note: candidate function not viable: requires 3 arguments, but 2 were provided V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context, uint32_t index,

I am getting the following error on macOS Catalina but after searching I found out it might be because I'm not using NodeJS v12.18.1.
Can you confirm or add the nodejs version to the readme?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.