¿Cómo filtrar datos de entradas con AJAX en la página?

21 nov 2014, 15:34:36
Vistas: 19.9K
Votos: 3

He creado un custom post_type con "Work items" para introducir elementos de mi portafolio personal. Los "Work items" tienen taxonomías como "Gráficos", "Sitios web", etc.

Puedo mostrarlos todos en una plantilla archive-work.php pero quiero filtrarlos en la página con AJAX. Seguí este ejemplo: http://www.bobz.co/ajax-filter-posts-tag/

Me estoy encontrando con un problema:

  • La primera vez que se muestra la página, no se obtiene nada de las taxonomías de mi tipo de entrada personalizada. Si hago clic en uno de mis enlaces, entonces los datos se actualizan correctamente. El problema solo ocurre en la primera carga de la página. Lo que supongo es que el nonce no se verifica porque no se envía con POST por lo que falla.

¿Alguien puede decirme dónde he cometido un error?

functions.php

function ajax_filter_posts_scripts() {
  // Registrar script
  wp_register_script('afp_script', get_template_directory_uri() . 
      '/ajax-work-items.js', false, null, false);
  wp_enqueue_script('afp_script');

  wp_localize_script( 'afp_script', 'afp_vars', array(
        'afp_nonce' => wp_create_nonce( 'afp_nonce' ), // Crear nonce que luego usaremos para verificar la solicitud AJAX
        'afp_ajax_url' => admin_url( 'admin-ajax.php' ),
      )
  );
}
add_action('wp_enqueue_scripts', 'ajax_filter_posts_scripts', 100);

$result = array();

// Script para obtener entradas
function ajax_filter_get_posts( $work_item ) {

  // Verificar nonce
  if( !isset( $_POST['afp_nonce'] ) || 
      !wp_verify_nonce( $_POST['afp_nonce'], 'afp_nonce' ))
    die('Permiso denegado');

  $work_item = $_POST['stuff'];

  // Consulta WP
  $args = array(
    'stuff' => $work_item,
    'post_type' => 'work',
    'posts_per_page' => -1,
  );

  // Si la taxonomía no está establecida, eliminar la clave del array y obtener todas las entradas
  if( !$work_item ) {
    unset( $args['stuff'] );
  }

  $query = new WP_Query( $args );

  if ( $query->have_posts() ) : 
       while ( $query->have_posts() ) : 
       $query->the_post(); 

       $res = '<div class="col-lg-4">'.
                  '<a href="'.get_permalink().'">'.
                      '<article class="panel panel-default" id="post-'.get_the_id().'">'.
                          '<div class="panel-body">'.
                              get_the_post_thumbnail().
                              '<div class="panel-cover">'.
                                  '<h3>'.get_the_title().'</h3>'.
                                      get_the_content().
                              '</div>'.
                          '</div>'.      
                      '</article>'.
                  '</a>' .     
              '</div>';


       $result['response'][] = $res;
       $result['status'] = 'success';

   endwhile;
   else:
       $result['response'] = '<h2>No se encontraron entradas</h2>';
       $result['status']   = '404';
   endif;

   $result = json_encode($result);
   echo $result;

  die();
}

add_action('wp_ajax_filter_posts', 'ajax_filter_get_posts');
add_action('wp_ajax_nopriv_filter_posts', 'ajax_filter_get_posts');

//Obtener Filtros de Trabajo
function get_work_filters()
{
    $work_items = get_terms('stuff');
    $filters_html = false;
    $count = count( $work_items );

    if( $count > 0 ):
        foreach( $work_items as $work_item )
        {
            $work_item_id = $work_item->term_id;
            $work_item_name = $work_item->name;

            $filters_html .= '<a href="' . 
                get_term_link( $work_item ) . 
                '" class="btn work-filter" title="' . 
                $work_item->slug . '">' . $work_item->name . '</a> ';
        }
        echo $filters_html;
    endif;
}

ajax-work-items.js

$(document).ready(function(){

    // filtros de trabajo

    $('.work-filter').click( function(event) {

        // Prevenir acción predeterminada - abrir página de etiqueta
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }

        // Obtener slug de etiqueta del atributo título
        var stuff = $(this).attr('title');        

        data = {
            action: 'filter_posts', // función a ejecutar
            afp_nonce: afp_vars.afp_nonce, // wp_nonce
            post_type: "work", // etiqueta seleccionada
            stuff: stuff,
            };

        $.ajax({ 
            type: "post",
            dataType: "json",
            url: afp_vars.afp_ajax_url, 
            data: data, 
            success: function(data, textStatus, XMLHttpRequest) {
                console.log(data);
                // Restaurar visibilidad del div
                $('.work-results').fadeOut()
                    .queue(function(n) {
                            $(this).html(data.response);
                            n();
                }).fadeIn();
            },
            error: function( XMLHttpRequest, textStatus, errorThrown ) {
                /*console.log( MLHttpRequest );
                console.log( textStatus );
                console.log( errorThrown );*/
                $('.work-results').fadeOut()
                    .queue(function(n) {
                            $(this).html("No se encontraron elementos. ");
                            n();
                }).fadeIn();
            }
        });
    });

});

archive-work.php

<?php get_header(); ?>

<div id="workwrapper">  
    <div class="row-bg-page">
        <div class="container">
            <div class="jumbotron">
                <h1>Nuestro trabajo</h1>
                <p class="lead">Proporcionando profesional ...
                </p>
            </div>
        </div>
    </div>
    <div class="row-bg-white">
        <div class="container">

            <div id="work-filter" class="text-center">
                <?php get_work_filters(); ?>
            </div>
            <br />

            <div class="work-results">
                <?php ajax_filter_get_posts(""); ?>
            </div>

        </div>
    </div>

</div>

<?php get_footer(); ?>
0
Todas las respuestas a la pregunta 1
0

Como puedes intuir, eso es lo que está ocurriendo (al menos eso creo).

Deberías separar tu lógica AJAX de tu lógica de "primera carga". Puedes crear una función, por ejemplo my_get_posts, que será llamada dentro de archive-work.php y luego dentro de ajax_filter_get_posts puedes llamar a la función my_get_posts().

archive-work.php

    <div class="work-results">
                    <?php $res = my_get_posts();
                 echo $res['response'];
?>
                </div>

functions.php

    function ajax_filter_get_posts( $work_item ) {

      // Verificar nonce
      if( !isset( $_POST['afp_nonce'] ) || 
          !wp_verify_nonce( $_POST['afp_nonce'], 'afp_nonce' ))
        die('Permiso denegado');

         $work_item = $_POST['stuff'];
         $result = json_encode(my_get_posts($work_item, true));
         echo $result;

         die();

    }

function my_get_posts($work_item = '', $ajax = false){

    // WP Query
      $args = array(
        'stuff' => $work_item,
        'post_type' => 'work',
        'posts_per_page' => -1,
      );

      // Si la taxonomía no está definida, eliminar la clave del array y obtener todos los posts
      if( !$work_item ) {
        unset( $args['stuff'] );
      }

      $query = new WP_Query( $args );
      $html = '';
      $items = array();

      if ( $query->have_posts() ) : 
           while ( $query->have_posts() ) : 
           $query->the_post(); 

           $res = '<div class="col-lg-4">'.
                      '<a href="'.get_permalink().'">'.
                          '<article class="panel panel-default" id="post-'.get_the_id().'">'.
                              '<div class="panel-body">'.
                                  get_the_post_thumbnail().
                                  '<div class="panel-cover">'.
                                      '<h3>'.get_the_title().'</h3>'.
                                          get_the_content().
                                  '</div>'.
                              '</div>'.      
                          '</article>'.
                      '</a>' .     
                  '</div>';


           $ajax ? $items[] = $res : $html .= $res;


       endwhile;

       $result['response'] = $ajax ? $items : $html;
       $result['status'] = 'success';

       else:
           $result['response'] = '<h2>No se encontraron posts</h2>';
           $result['status']   = '404';
       endif;
wp_reset_postdata();
return $result;
}

Además, no creo que el siguiente código sea necesario ya que WordPress se encargará de ello:

// Si la taxonomía no está definida, eliminar la clave del array y obtener todos los posts
          if( !$work_item ) {
            unset( $args['stuff'] );
          }

El código es un borrador y podría mejorarse, pero captas la idea. No lo he probado pero debería funcionar.

EDITADO

No olvides llamar a wp_reset_postdata(); después de cada WP_Query personalizado para restaurar la variable global $post. Más información aquí: http://codex.wordpress.org/Function_Reference/wp_reset_postdata

21 nov 2014 16:48:59