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:
- VueJS para el renderizado y gestión de eventos.
- Axios a la hora de realizar una petición GET por AJAX.
Quiero agradecer a Valentina Rubane Evseeva por la base del código, sin su aportación no hubiera sido posible el artículo.
Demo
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>
{{ comments.length }} comentarios