WordPress ejemplo paginador con VueJS y WP REST API

En el siguiente ejemplo vamos a realizar un paginador en Javascript para WordPress a través de WP REST API, solucionando el problema de obtener más artículos desde el punto de vista del Front-End. De este modo evitaremos el uso de PHP y los navegantes disfrutarán de resultados rápidos.

Para una elaboración rápida se usarnán algunas librerías externas, totalmente opcionales, vinculadas en los ejemplos por medio de CDNs:

Quiero agradecer a Valentina Rubane Evseeva por la base del código, sin su aportación no hubiera sido posible el artículo.

Demo

{{ post.title.rendered }}
... esperando recibir mas entradas ...

HTML

Dividimos el documento en la sección donde irán apareciendo los artículos, el lugar que mostrará el cargador y el botón para cargar la siguiente página.

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Paginador WP REST API</title>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- Bucle de contenido de entrada que se quiere rendirizar -->
        <div v-for="post in posts">
            <a :href="post.link">
                {{ post.title.rendered }}
            </a>
        </div>
        <!-- Fin Bucle -->

        <!-- Loading -->
        <div v-if="loading">
            ... esperando recibir mas entradas ...
        </div>
        <!-- Fin Loading -->

        <!-- Ver mas entradas-->
        <button role="button" @click.prevent="getMorePosts" v-if="isMorePages">
            Más entradas
        </button>
        <!-- Fin ver mas entradas-->
    </div>
</body>

</html>

Javascript

En los comentarios puede ver que hace cada sección, pero en resumidas se realiza una petición y se calcula que elementos del array recibido quiero incluir.

document.addEventListener('DOMContentLoaded', () => {

    // Constantes de WP REST API ENDPOINTS
    const URL_ENDPOINT_POSTS = '/wp-json/wp/v2/posts?per_page=';
    const URL_ENDPOINT_OFFSET = '&offset=';
    const HEADER_TOTAL_POSTS = 'x-wp-total';

    new Vue({
        el: '#app',
        data: {
            // Numero de entradas por "pagina"
            NUM_RESULTS: 5,
            // Numero de primeras entradas que debemos ignorar, ya que WP permite mostrar como maximo 100 entradas en una llamada
            numOffset: 0,
            // Numero de pagina que necesitaremos para hacer calculo
            pag: 1,
            // Numero total de entradas que necesitaremos para hacer calculo
            totalPosts: 0,
            posts: [],
            loading: false
        },
        mounted() {
            // obtenemos primeras entradas al entrar en la pagina
            axios
                // Aqui realmente no necesitamos poner numero de offset
                .get(this.getEndPoint)
                .then(response => {
                    this.posts = response.data;
                    // obtenemos el numero total de entradas, el dato que recibimos es un integro
                    this.totalPosts = response.headers[HEADER_TOTAL_POSTS];
                });
        },
        computed: {
            isMorePages: function() {
                return this.pag * this.NUM_RESULTS / this.totalPosts < 1;
            },
            getEndPoint: function() {
                return `${URL_ENDPOINT_POSTS}${this.NUM_RESULTS}${URL_ENDPOINT_OFFSET}${this.numOffset}`;
            }
        },
        methods: {
            // Optenemos mas entradas y las añadimos a las entradas que hemos obtenido al entrar en la pagina
            getMorePosts: function() {
                // sumamos 1 a pag con cada click
                this.pag += 1;
                // sumamos numero de resultados que hemos establicido y cuya suma ignaremos con cada click
                this.numOffset += this.NUM_RESULTS;
                this.loading = true;
                axios.get(this.getEndPoint)
                    .then(response => {
                        // sumamos nuevas entradas a las que hemos obtenido anteriormente
                        this.posts = this.posts.concat(response.data);
                    })
                    .finally(() =>
                        this.loading = false
                    );
            }
        }
    });
});

Ejemplo completo

Todo unido quedaría de la siguiente manera.

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Paginador WP REST API</title>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- Bucle de contenido de entrada que se quiere rendirizar -->
        <div v-for="post in posts">
            <a :href="post.link">
                {{ post.title.rendered }}
            </a>
        </div>
        <!-- Fin Bucle -->

        <!-- Loading -->
        <div v-if="loading">
            ... esperando recibir mas entradas ...
        </div>
        <!-- Fin Loading -->

        <!-- Ver mas entradas-->
        <button role="button" @click.prevent="getMorePosts" v-if="isMorePages">
            Más entradas
        </button>
        <!-- Fin ver mas entradas-->
    </div>
    <script>
      document.addEventListener('DOMContentLoaded', () => {

          // Constantes de WP REST API ENDPOINTS
          const URL_ENDPOINT_POSTS = '/wp-json/wp/v2/posts?per_page=';
          const URL_ENDPOINT_OFFSET = '&offset=';
          const HEADER_TOTAL_POSTS = 'x-wp-total';

          new Vue({
              el: '#app',
              data: {
                  // Numero de entradas por "pagina"
                  NUM_RESULTS: 5,
                  // Numero de primeras entradas que debemos ignorar, ya que WP permite mostrar como maximo 100 entradas en una llamada
                  numOffset: 0,
                  // Numero de pagina que necesitaremos para hacer calculo
                  pag: 1,
                  // Numero total de entradas que necesitaremos para hacer calculo
                  totalPosts: 0,
                  posts: [],
                  loading: false
              },
              mounted() {
                  // obtenemos primeras entradas al entrar en la pagina
                  axios
                      // Aqui realmente no necesitamos poner numero de offset
                      .get(this.getEndPoint)
                      .then(response => {
                          this.posts = response.data;
                          // obtenemos el numero total de entradas, el dato que recibimos es un integro
                          this.totalPosts = response.headers[HEADER_TOTAL_POSTS];
                      });
              },
              computed: {
                  isMorePages: function() {
                      return this.pag * this.NUM_RESULTS / this.totalPosts < 1;
                  },
                  getEndPoint: function() {
                      return `${URL_ENDPOINT_POSTS}${this.NUM_RESULTS}${URL_ENDPOINT_OFFSET}${this.numOffset}`;
                  }
              },
              methods: {
                  // Optenemos mas entradas y las añadimos a las entradas que hemos obtenido al entrar en la pagina
                  getMorePosts: function() {
                      // sumamos 1 a pag con cada click
                      this.pag += 1;
                      // sumamos numero de resultados que hemos establicido y cuya suma ignaremos con cada click
                      this.numOffset += this.NUM_RESULTS;
                      this.loading = true;
                      axios.get(this.getEndPoint)
                          .then(response => {
                              // sumamos nuevas entradas a las que hemos obtenido anteriormente
                              this.posts = this.posts.concat(response.data);
                          })
                          .finally(() =>
                              this.loading = false
                          );
                  }
              }
          });
      });
    </script>
</body>

</html>
Versión escritorio