一梦七年。
一派青春撞了南墙,一生热爱回头太难。
文章 20
标签 29
分类 11
基于wordpress的headless CMS构建Vue单页应用

基于wordpress的headless CMS构建Vue单页应用

基于wordpress的headless CMS构建Vue单页应用

特别说明:本文翻译自Build a Vue.js SPA on Top of Headless WordPress,如需更多了解,请前往原文阅读。

难以置信,我又要开始写关于wordpress的东西了。

开个玩笑,事实上,在我最后一次使用wordpress的rest api时,我还觉得它非常的酷。

看到如此庞大的网络产业向现代趋势和新范式开放,还真是让人耳目一新。所以,我想知道如果把我最喜欢的前端框架Vue和wordpress结合起来会不会很有趣呢?

事实证明,这当然是非常有趣的。

在本文中,我将对这个技术栈进行更深入的讲解。本教程将涵盖以下几个方面:

  1. 在wordpress中使用自定义字段来创建模型。
  2. 将WP REST API构建成自定义端点。
  3. 创建一个Vue单页面应用。
  4. 将这个应用进行托管。

首先,明确一下使用wordpress作为一个headless CMS。

Monolithic CMS vs Headless CMS

在用一个具体的wordpress例子进行深入研究前,先确保我们对Headless CMS的理解是一致的。

一直到几年前,我们还习惯于使用传统的CMSs,它们管理前端和后端以及前端和后端之间所有的东西,包括前端的页面、后端的数据、角色权限等等。然而,由于前端的现代化的兴起,也引发了这一重大的转变。前端现代化产生的生态圈中,根本没有多余的位置存放这些老旧、单一的CMSs,替代它们的将会是静态站点生成器、以API为中心的微服务和无服务架构。

但是,这并不意味着想wordpress这样的东西就该退出历史舞台了,这只是说明它们需要谋求变革,它们不应该在管理网站的所有东西,因为现在有很多工具在某些方面做的更好。

所以,为什么不用wordpress来做它真正擅长的东西呢?而这正是自wordpress4.7发布的WP REST API支持的。它允许在wordpress后台注入的内容被用于前端应用,不论涉及到什么技术。

这将是一场游戏的变革。

我敢肯定,如果你是一个只有一点点wordpress经验的开发者,你应该已经注意到这场变革带来的新的机遇了。

顺便说一下,开发人员多年来一直抱怨的问题,WordPress的主要缺点:开发很不自由,而且模板定制很麻烦。但是如果只使用WordPress作为后台来开发应用,那这些问题不仅可以抛之脑后了,还会在开发速度上得到一个大的提升:

  • 开发人员可以在模块化的自由地使用他们喜欢的工具,这将使得项目具有高可扩展性,而且,这样也会带来更好的性能。
  • 不再需要去处理WP的模板,将它插入到你喜欢的前端,而无需担心覆盖基于php的模板,因为从头开始构建强大的用户界面要容易得多,然后就可以使用WordPress的数据了。

为什么会选择在wordpress中使用Vue呢?

vuejs-wordpress

在过去,把wordpress和JS框架结合在一起以供我们在应用程序中使用WordPress也许会给你带来很大的困难,但是,想想多设备应用程序、物联网、先进的网络应用程序和其他现代实践。

除了我已经在我的第一个WP headless demo中使用了React这一事实外,我还有很多理由向那些寻找合适前端框架的人推荐Vue.js。

你可能听到人们讨论Vue最多的是它的模块化、速度和高性能。我想说这些都是绝对正确的,你可以放心,我不是在这里胡说,在Snipcart,甚至使用它来支持我们最新版本的购物车。

而且,这种新兴技术的构建工具一天比一天成熟。就像JavaScript生态系统一样,Vue的生态圈也在不断扩大。现在几乎任何类型的前端项目都有基于它的工具。以下是你应该关注的主要问题:

  • Nuxt: 一个引人注目的静态站点生成、单页应用程序(SPA)开发和服务器端渲染的框架。在本教程中,我们使用它在headless CMS的基础上构建了一个静态站点。

  • Gridsome: 相当于 Vue中的Gatsby(基于React的开源框架)。由GraphQL支持从任何来源获取数据,包括headless CMS。它可以生成渐进式Web应用程序(PWA)。

  • VuePress: 一个极简的基于Vue的静态网站生成器,拥有完整的学习文档和博客。

SEO是个问题吗?

SEO是最需要被优化的,以传统的方式使用WordPress的一个好处是你不用太担心SEO。因此,当我们听说JS框架在seo方面不是很好时,我可以理解为什么人们不愿意使用它。

但是让我们彻底澄清一下。实际上,如果你处理得当,你可以用Vue取得很好的SEO结果。使用Nuxt.js进行服务器端呈现是一种方法,但是您也可以使用简单的预渲染服务,就像我们在这里所做的一样。

然后,更好的性能和用户体验实际上将会提高你的SEO效果。

教程: Headless WordPress 绑定到一个vue单页应用

主要内容:

我们的团队正在扩张,但是这其中也包含了在一些成员居住的城市扩张。所以假设我们很难在按比例计算时去记住每个成员的位置,我将创建一个应用程序,用来跟踪每个成员的位置,并在交互式地图上标记出他们的位置坐标。

我将向你展示如何制作一个响应式的Vue单页应用来实现这个功能。后端部分非常类似我之前的一篇wordpress与React结合使用的文章中提到的,但这次,我将以不同的方式在vue单页应用中使用这些数据。

预备条件:

  • 一个正在运行的wordpress实例

  • vue基础

  • 一个免费的MapBox账号

1、在wordpress中创建自定义字段模板

让我们直接进入WordPress管理页面。我将使用ACF (Advanced Custom Fields)插件来演示如何创建自定义字段模板。这个插件允许你添加自定义字段到原生WordPress实体中,比如post。它经过了较为完整的测试,非常稳定,并且在向页面添加自定义数据时可以快速启动。您可以使用WordPress仪表板中的Plugins选项卡轻松地安装它。下面就是你需要下载的这个插件:

ACF

对于这个例子,您将需要四个字段:两个坐标、一个名称和一个图像。下面是它在仪表板上的样子:

ACF-Custom-Fields

现在你可以添加自定义数据到你的WordPress文章中,让我们使用它们来创建标记来显示团队成员的居住位置。以下是新创建的帖子列表:

ACF-Custom-Fields

2、构建自定义端点

现在你已经拥有了你想要的数据,你还需要将它向公众开放,以便可以通过REST API来访问到这些数据。

为此,还需要构建一个自定义端点。打开WordPress文件夹并打开functions.php文件,这是你将注册新端点的地方。将下面的几行代码添加达到文件末尾:

function  markers_endpoint( $request_data ) {
    $args = array(
        'post_type' => 'post',
        'posts_per_page'=>-1, 
        'numberposts'=>-1
    );

    $posts = get_posts($args);
    foreach ($posts as $key => $post) {
        $posts[$key]->acf = get_fields($post->ID);
    }
    return  $posts;
}

add_action( 'rest_api_init', function () {
    register_rest_route( 'markers/v1', '/post/', array(
        'methods' => 'GET',
        'callback' => 'markers_endpoint'
    ));
});

add_action方法创建自定义端点,并通过rest_api_init钩子注册它。调用端点后,将执行回调,并在acf字段下返回你的自定义字段。

以下将是你在GET请求后得到的返回结果:

[
    {
        "ID": 19,
        "post_author": "1",
        "post_date": "2019-03-14 15:48:40",
        "post_date_gmt": "2019-03-14 19:48:40",
        "post_content": "",
        "post_title": "Chuck",
        "post_excerpt": "",
        "post_status": "publish",
        "comment_status": "open",
        "ping_status": "open",
        "post_password": "",
        "post_name": "chuck",
        "to_ping": "",
        "pinged": "",
        "post_modified": "2019-03-14 15:48:41",
        "post_modified_gmt": "2019-03-14 19:48:41",
        "post_content_filtered": "",
        "post_parent": 0,
        "guid": "http:\/\/localhost\/wordpress\/?p=19",
        "menu_order": 0,
        "post_type": "post",
        "post_mime_type": "",
        "comment_count": "0",
        "filter": "raw",
        "acf": {
            "Name": "Chuck",
            "image": "http:\/\/localhost\/wordpress\/wp-content\/uploads\/2019\/03\/charles-snipcart.png",
            "longitude": "49.8951",
            "Latitude": "97.1384"
        }
    }, ...
]
3、创建Vue单页应用

让我们即刻将这些新出炉的数据用起来。

首先构建一个vue项目,如果你还不知道如何构建vue项目或者不知道如何使用相关插件,请先移步到这里了解如何构建vue项目这里了解如何构建vue项目。以下内容我们将假设你已经会使用vue并对相关的类容有一定的了解。

接着,创建你的项目:vue create markers。

首先要做的是在App组件中请求API并获取数据。为此,只需向组件添加以下声明:

<template>
  <div id="app">

    <div class="badge-container">
      <div v-for="badge in markers" :key="badge.name">
        <Badge :name="badge.name" :image="badge.image" />
      </div>
    </div>
    <Map v-if="markers.length > 0" :markers="markers" />

  </div>
</template>
<script>
import Badge from './components/Badge.vue'
import Map from './components/Map.vue'
export default {
  name: 'app',
  data(){
    return {
      markers: []
    }
  },
  components: {
    Badge,
    Map
  },
  mounted(){
    fetch('https://wordpress-vue.herokuapp.com/index.php/wp-json/markers/v1/post')
      .then((r) => r.json())
      .then((res) => this.markers = res.map(x => x.acf));
  }
}

有了数据之后,让我们创建第一个组件(在components文件夹中),命名为Badge。代码如下:

<template>
  <div class="badge" :id="name">
    <img :src=img width=500/>
    <h2>{{ name }}</h2>
  </div>
</template>

<script>
export default {
  name: 'Badge',
  props: {
    Name: String,
    Image: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

让我们回到应用程序组件,导入Badge组件,并在组件对象中注册它:

components: {
    Badge
}

接着,我们再创建一个新 组件Map.vue。在这里,我将使用Mapbox来显示地图。他们有免费的版本,整洁和完整的文档…我不能要求更多了。一旦您创建了一个帐户,您将能够直接访问仪表板主页地址:https://account.mapbox.com/

首先,在你的index.html文件中直接引入Mapbox的JS和CSS:

<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.1/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.1/mapbox-gl.css' rel='stylesheet' />

然后像下面这样定义Map组件:

<template>
  <div>
      <div id='map' class='map'> </div>
  </div>
</template>

<script>

export default {
  name: 'Map',
  mounted(){

    window.mapboxgl.accessToken = "{YOUR_MAPBOX_ACCESS_TOKEN}";    

    var map = new window.mapboxgl.Map({
        container: 'map',
        style: 'mapbox://styles/mapbox/dark-v9',
        center: [-81.4608, 48.4758], 
        zoom: 4
    });

    map.on('load', (() => {

        this.markers.forEach(function(marker) {
            var el = document.createElement('div');
            el.className = 'marker';

            new window.mapboxgl.Marker(el)
                .setLngLat([parseFloat(marker.latitude), parseFloat(marker.longitude)])
                .addTo(map);
        });

        this.markers.forEach((x) => {
            document.getElementById(x.name)
                .addEventListener('click', () => {
                    map.flyTo({
                        center: [parseFloat(x.latitude), parseFloat(x.longitude)],
                        zoom: 9
                    })
                ;}
            )
        })

    }).bind(this));
  },
  props: {
   markers: Array
  }
}
</script>

<style>
.marker {
  background-image: url('./../assets/mapbox-icon.png');
  background-size: cover;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  cursor: pointer;
}
</style>

正如你所看到的,Map组件的props只需要接受一个markers属性,这个属性是一个包含所有信息的数组。你需要将自己的accessToken绑定上,然后给map对象绑定load事件,这样就能确保在map对象加载完毕后才开始读取并展现markers数组中的数据。

接着用css做一个定位的标记,并把它添加到map中。最后你要做的就是给每一个Badge绑定点击事件,以实现点击对应的Badge时,地图能定位到对应的位置。

到这里我们就完成了整个应用的功能,你可以在wordpress后台添加或删除你的自定义字段,你的应用会自动加载你修改的数据。

总结:

通过将wordpress作为一个headless CMs,你只需要专注于你的前端界面的开发,而不需要单独去维护一个服务器,你的数据可以保存在wordpress中,你也可以通过wordpress的控制面板对你的数据进行操作,这种方式能让你快速开发出一个全新的网站。如果你对此感兴趣,你还可以了解到更多wordpress的东西,甚至你不需要自己去写php的代码了,很多插件都可以解决本例中php代码的部分。