Как фильтровать данные постов с помощью AJAX на странице?

21 нояб. 2014 г., 15:34:36
Просмотры: 19.9K
Голосов: 3

Я создал пользовательский тип записи "Work items" для размещения элементов моего портфолио. У "Work items" есть такие таксономии как "Graphics", "Websites" и т.д.

Я могу отображать их все в шаблоне archive-work.php, но хочу фильтровать их на странице с помощью AJAX. Я следовал этому примеру: http://www.bobz.co/ajax-filter-posts-tag/

У меня возникла проблема:

  • При первой загрузке страницы ничего не загружается из таксономий моего пользовательского типа записей. Если я нажимаю на одну из ссылок, данные успешно обновляются. Проблема только при первой загрузке страницы. Я предполагаю, что nonce не проверяется, потому что он не отправляется с POST-запросом, поэтому происходит сбой.

Кто-нибудь может сказать, где я допустил ошибку?

functions.php

function ajax_filter_posts_scripts() {
  // Подключаем скрипт
  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' ), // Создаем nonce, который позже будем использовать для проверки AJAX-запроса
        'afp_ajax_url' => admin_url( 'admin-ajax.php' ),
      )
  );
}
add_action('wp_enqueue_scripts', 'ajax_filter_posts_scripts', 100);

$result = array();

// Скрипт для получения записей
function ajax_filter_get_posts( $work_item ) {

  // Проверяем nonce
  if( !isset( $_POST['afp_nonce'] ) || 
      !wp_verify_nonce( $_POST['afp_nonce'], 'afp_nonce' ))
    die('Доступ запрещен');

  $work_item = $_POST['stuff'];

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

  // Если таксономия не установлена, удаляем ключ из массива и получаем все записи
  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>Записи не найдены</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');

//Получаем фильтры работ
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(){

    // фильтры работ

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

        // Предотвращаем действие по умолчанию - открытие страницы тега
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }

        // Получаем слаг тега из атрибута title
        var stuff = $(this).attr('title');        

        data = {
            action: 'filter_posts', // функция для выполнения
            afp_nonce: afp_vars.afp_nonce, // wp_nonce
            post_type: "work", // выбранный тег
            stuff: stuff,
            };

        $.ajax({ 
            type: "post",
            dataType: "json",
            url: afp_vars.afp_ajax_url, 
            data: data, 
            success: function(data, textStatus, XMLHttpRequest) {
                console.log(data);
                // Восстанавливаем видимость 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("Элементы не найдены. ");
                            n();
                }).fadeIn();
            }
        });
    });

});

archive-work.php

<?php get_header(); ?>

<div id="workwrapper">  
    <div class="row-bg-page">
        <div class="container">
            <div class="jumbotron">
                <h1>Наши работы</h1>
                <p class="lead">Предоставляем профессиональные ...
                </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
Все ответы на вопрос 1
0

Как вы догадываетесь, именно это и происходит (по крайней мере, я так думаю).

Вам следует разделить логику AJAX от логики "первой загрузки". Вы можете создать функцию, например, my_get_posts, которая будет вызываться внутри archive-work.php, а затем внутри ajax_filter_get_posts вы можете вызвать функцию 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 ) {

      // Проверка nonce
      if( !isset( $_POST['afp_nonce'] ) || 
          !wp_verify_nonce( $_POST['afp_nonce'], 'afp_nonce' ))
        die('Permission denied');

         $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,
      );

      // Если таксономия не установлена, удаляем ключ из массива и получаем все записи
      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>Записи не найдены</h2>';
           $result['status']   = '404';
       endif;
wp_reset_postdata();
return $result;
}

Также я не думаю, что следующий код необходим, так как WordPress позаботится об этом.

// Если таксономия не установлена, удаляем ключ из массива и получаем все записи
          if( !$work_item ) {
            unset( $args['stuff'] );
          }

Код является черновиком и может быть улучшен, но вы поняли идею. Я его не тестировал, но он должен работать.

РЕДАКТИРОВАНИЕ

Не забудьте вызвать wp_reset_postdata(); после каждого пользовательского WP_Query, чтобы восстановить глобальную переменную $post. Подробнее здесь: http://codex.wordpress.org/Function_Reference/wp_reset_postdata

21 нояб. 2014 г. 16:48:59