it-swarm.com.ru

Как создать расширенный фильтр поиска?

Это на самом деле не технический вопрос, а скорее введение в тему, о которой я хочу поговорить.

Так что я впервые создаю пользовательскую страницу расширенного поиска, в которой мне нужно получать сообщения в соответствии с пользовательским типом сообщения, пользовательскими таксономиями, годами и порядком.

Проблема в том, что я действительно не знаю, как сниматься здесь. Я искал учебники или фрагменты в Интернете, но все, что я нашел, не может работать с выпадающими списками (почему? Я не знаю), все учебники, которые я нашел, посвящены использованию флажков.

Итак, какие рекомендации или код функции вы, ребята, можете мне рассказать?.

Заранее спасибо.

Это HTML-код, который я хочу использовать:

<!-- Post Type -->
<div class="col-md-3">
    <div class="form-group">
        <label for="post_type">Post Type</label>
        <select class="form-control">
            <option>Any</option>
            <option>Post</option>
            <option>Portfolio</option>
            <option>Snippet</option>
        </select>
    </div>
</div>

<!-- Taxonomy -->
<div class="col-md-3">
    <div class="form-group">
        <label for="post_type">Taxonomy</label>
        <select class="form-control" multiple>
            <option>Any</option>
            <option>category</option>
            <option>portfolio_categories</option>
            <option>snippets_categories</option>
        </select>
    </div>
</div>

<!-- Year -->
<div class="col-md-3">
    <div class="form-group">
        <label for="post_type">Year</label>
        <select class="form-control">
            <option>Any</option>
            <option>2018</option>
            <option>2017</option>
            <option>2016</option>
            <option>2015</option>
            <option>2014</option>
        </select>
    </div>
</div>

<!-- Orderby -->
<div class="col-md-3">
    <div class="form-group">
        <label for="post_type">Order by</label>
        <select class="form-control" multiple>
            <option>Any</option>
            <option>Author</option>
            <option>Popularity (# of Comments)</option>
            <option>Views post_views_count</option>
            <option>Year</option>
            <option>ASC</option>
            <option>DESC</option>
        </select>
    </div>
</div>

<!-- Search Button -->
<div class="col-md-12">
    <input type="submit" class="btn btn-primary" id="buscar_btn" value="Search">
    <noscript>&lt;b&gt;Your browser does not support Javascript, this making it unable to display the posts.&lt;/b&gt;</noscript>
    <div id="resultados"><div class="cargando_medio"></div></div>
</div>

Вот функция для настраиваемого поля post_view_count:

// Function to display number of views.
function getPostViews($postID){
    $count_key = 'post_views_count';
    $count = get_post_meta($postID, $count_key, true);
    if($count==''){
        delete_post_meta($postID, $count_key);
        add_post_meta($postID, $count_key, '0');
        return "0 Views";
    }
    return $count.' Views';
}

// Function to count views.
function setPostViews($postID) {
    $count_key = 'post_views_count';
    $count = get_post_meta($postID, $count_key, true);
    if($count==''){
        $count = 0;
        delete_post_meta($postID, $count_key);
        add_post_meta($postID, $count_key, '0');
    }else{
        $count++;
        update_post_meta($postID, $count_key, $count);
    }
}


// Add it to a column in WP-Admin
function posts_column_views($defaults){
    $defaults['post_views'] = __('Views');
    return $defaults;
}
add_filter('manage_posts_columns', 'posts_column_views');
function posts_custom_column_views($column_name, $id){
    if($column_name === 'post_views'){
        echo getPostViews(get_the_ID());
    }
}
add_action('manage_posts_custom_column', 'posts_custom_column_views',5,2);

Функция не очень хорошая, на самом деле не очень хорошая, но она работает. Возможно, мне придется изменить это позже, особенно потому, что я хочу, чтобы он считал просмотры по IP-адресу и за день; в настоящее время он делает это путем подсчета просмотров за каждый ОБНОВЛЕНИЕ, которое я делаю на текущей странице/посте.

 enter image description here 

1
Kirasiris

Попробуй это:

PHP

add_action( 'wp_ajax_my_adv_search', 'ajax_my_adv_search' );
add_action( 'wp_ajax_nopriv_my_adv_search', 'ajax_my_adv_search' );
function ajax_my_adv_search() {
    if ( ! check_ajax_referer( 'my-adv-search', 'q_nonce', false ) ) {
        echo 'session_expired';
        wp_die();
    }

    $post_type = isset( $_POST['q_post_type'] ) ? $_POST['q_post_type'] : '';
    $taxonomy = isset( $_POST['q_taxonomy'] ) ? $_POST['q_taxonomy'] : [];
    $year = isset( $_POST['q_year'] ) ? $_POST['q_year'] : '';
    $orderby = isset( $_POST['q_orderby'] ) ? $_POST['q_orderby'] : [];
    $order = isset( $_POST['q_order'] ) ? $_POST['q_order'] : '';

    // Note that if $post_type is 'any', all post statuses will be included. In
    // that case, you may want to set specific post statuses below.
    $post_status = '';

    $taxonomy = array_filter( (array) $taxonomy );
    if ( ! in_array( 'any', $taxonomy ) ) {
        $taxonomy = array_unique( array_map( 'trim', $taxonomy ) );

        add_filter( 'posts_join', function( $c ) use ( $taxonomy ) {
            if ( ! empty( $taxonomy ) ) {
                global $wpdb;
                // 1 below is one/number and not the lowercase of L
                $c .= " INNER JOIN {$wpdb->term_relationships} AS ctr1 ON ctr1.object_id = {$wpdb->posts}.ID" .
                    " INNER JOIN {$wpdb->term_taxonomy} AS ctt1 ON ctt1.term_taxonomy_id = ctr1.term_taxonomy_id";
            }
            return $c;
        } );

        add_filter( 'posts_where', function( $c ) use ( $taxonomy ) {
            if ( ! empty( $taxonomy ) ) {
                $tax_list = array_map( 'esc_sql', $taxonomy );
                $tax_list = "'" . implode( "', '", $tax_list ) . "'";

                // 1 below is one/number and not the lowercase of L
                $c .= " AND ( ctt1.taxonomy IN ($tax_list) )";
            }
            return $c;
        } );
    }

    if ( ! is_numeric( $year ) ) {
        $year = '';
    }

    $orderby = array_filter( (array) $orderby );
    if ( in_array( 'any', $orderby ) ) {
        // Don't sort by post date.
        $orderby2 = false;
    } else {
        $orderby = array_unique( array_map( 'trim', $orderby ) );

        // TRUE if we're sorting by year.
        $ob_year = false;

        foreach ( $orderby as $i => $s ) {
            // Sort posts by year.
            if ( 'year' === $s ) {
                $ob_year = true;
                unset( $orderby[ $i ] );
            }

            // Sort posts by views count. Note that this would only return
            // posts that have the custom field 'post_views_count'.
            if ( 'views_count' === $s ) {
                $meta_key = 'post_views_count';
                $orderby2 = 'meta_value_num';
                unset( $orderby[ $i ] );
            }
        }

        add_filter( 'posts_orderby', function( $c, $q ) use ( $ob_year ) {
            if ( $ob_year ) {
                global $wpdb;

                // Use the value parsed by WP_Query.
                $order = $q->get( 'order' );

                $c .= $c ? ', ' : '';
                $c .= "YEAR({$wpdb->posts}.post_date) $order";
            }
            return $c;
        }, 10, 2 );

        $ok = isset( $orderby2 );
        if ( ! $ok && empty( $orderby ) ) {
            // Don't sort by post date.
            $orderby2 = false;
        } elseif ( ! $ok ) {
            // Pass to WP_Query as a string.
            $orderby2 = implode( ' ', $orderby );
        }
    }

    $q = new WP_Query( [
        'post_status' => $post_status,
        'post_type'   => $post_type,
        'year'        => $year,
        'meta_key'    => isset( $meta_key ) ? $meta_key : '',
        'orderby'     => $orderby2,
        'order'       => $order,
    ] );

    if ( $q->have_posts() ) {
        echo '<ul>';
        while ( $q->have_posts() ) {
            $q->the_post();

            echo '<li>';
                the_title(); echo '; ID: '; the_ID();
            echo '</li>';
        }
        echo '</ul>';
    } else {
        echo '<p>No posts found.</p>';
    }

    wp_die();
}

HTML

Взгляните на "форму" ниже и убедитесь, что вы установили правильный ID в соответствующем элементе/меню select. Вам также необходимо добавить поля 'order' в столбец "Order by" и nonce поле перед кнопкой отправки/поиска.

<div id="my-adv-search">
<!-- Post Type -->
<div class="col-md-3">
    <div class="form-group">
        <label for="q_post_type">Post Type</label>
        <select class="form-control" id="q_post_type">
            <option value="any" selected>Any</option>
            ...
        </select>
    </div>
</div>

<!-- Taxonomy -->
<div class="col-md-3">
    <div class="form-group">
        <label for="q_taxonomy">Taxonomy</label>
        <select class="form-control" multiple id="q_taxonomy">
            <option value="any" selected>Any</option>
            ...
        </select>
    </div>
</div>

<!-- Year -->
<div class="col-md-3">
    <div class="form-group">
        <label for="q_year">Year</label>
        <select class="form-control" id="q_year">
            <option value="any" selected>Any</option>
            ...
        </select>
    </div>
</div>

<!-- Orderby -->
<div class="col-md-3">
    <div class="form-group">
        <label for="q_orderby">Order by</label>
        <select class="form-control" multiple id="q_orderby">
            <option value="any" selected>Any</option>
            <?php
            foreach ( [
              'author'        => 'Author',
              'comment_count' => 'Popularity (# of Comments)',
              'year'          => 'Year',
              'views_count'   => 'Views',
            ] as $value => $label ) {
              printf( '<option value="%s">%s</option>',
                esc_attr( $value ), esc_html( $label ) );
            }
            ?>
        </select>
    </div>
    <label class="radio-inline">
      <input type="radio" name="order" id="q_order-asc" value="ASC" />
      ASC
    </label>
    <label class="radio-inline">
      <input type="radio" name="order" id="q_order-desc" value="DESC" checked />
      DESC
    </label>
</div>

<!-- Nonce field. -->
<?php wp_nonce_field( 'my-adv-search', 'q_nonce' ); ?>

<!-- Search Button -->
<div class="col-md-12">
    <input type="submit" class="btn btn-primary" id="buscar_btn" value="Search">
    <noscript>&lt;b&gt;Your browser does not support Javascript, this making it unable to display the posts.&lt;/b&gt;</noscript>
    <div id="resultados"><div class="cargando_medio"></div></div>
</div>
</div><!-- End #my-adv-search -->

JS/jQuery/AJAX

Ниже приведен пример сценария JS/jQuery, который выполняет поиск AJAX.

jQuery( function( $ ){
    var ajaxurl = '/path/to/wp-admin/admin-ajax.php';

    function searchPosts( btn ) {
        var _btn_text = btn.value,
            q_order;

        btn.disabled = true;
        btn.value = 'Searching..';

        q_order = $( '#q_order-asc' ).is( ':checked' ) ?
            'ASC' : 'DESC';

        return $.post( ajaxurl, {
            action: 'my_adv_search',
            q_nonce: $( '#q_nonce' ).val(),
            q_post_type: $( '#q_post_type' ).val(),
            q_taxonomy: $( '#q_taxonomy' ).val(),
            q_year: $( '#q_year' ).val(),
            q_orderby: $( '#q_orderby' ).val(),
            q_order: q_order,
        } ).done( function( s ){
            if ( 'session_expired' === s ) {
                location.reload();
                return;
            }

            $( '#resultados' ).html( s );
        } ).always( function(){
            btn.value = _btn_text;
            btn.disabled = false;
        } );
    }

    $( '#buscar_btn', '#my-adv-search' ).on( 'click', function( e ){
        e.preventDefault();

        // Run AJAX search.
        searchPosts( this );

        // Remove button focus.
        this.blur();
    } );
} );

Заметки

  • В функции ajax_my_adv_search() PHP я не использовал tax_query с вызовом WP_Query, потому что мы запрашиваем посты, находящиеся в одном из указанных ключей таксономии (например, category для стандартной категории Post и post_tags для стандартной Post теги), а не в срок внутри таксономии. Поэтому я использовал хуки posts_join и posts_where в WP_Query, чтобы получить правильные результаты для такого рода запросов.

  • В функции ajax_my_adv_search() PHP я также использовал хук posts_orderby в WP_Query, потому что sorting posts/results by year по умолчанию недоступен в классе WP_Query.

3
Sally CJ