Skip to content
Advertisement

Alphabetical filtering of custom post type in WordPress results

I’m working on a custom post type archive and I want to add an A-Z filtering menu. I managed to pretty much get it working following this thread (Create alphabetical Pagination in wordpress) but I dont understand how my initial page (/exposants) can show all the results.

<div class="exposant__filter" id="exposants">
        <a href="/exposants/#exposants"><?php _e('Tout', 'festival'); ?></a>

    <?php 
        $posts = get_posts(array(
            'numberposts' => -1,
            'post_type' => 'exposant',
            'orderby' => 'title',
            'order' => 'ASC',
        )); 
        
        $firstLetters = array();
        foreach($posts as $post) {
            $title = $post->post_title;
            $startingLetter = substr($title, 0, 1);
            $dupeFirstLetters[] = $startingLetter;
            $firstLetters = array_unique($dupeFirstLetters);
            sort($firstLetters);
        }
        foreach($firstLetters as $letter) {
            echo "<a href="?lettre=$letter">$letter</a>";
        }
        if(!empty($_GET['lettre'])) {
                $letter = $_GET['lettre'];
        }
        else {
            $letter = $firstLetters[0];
        } ?>
    </div>      

    <?php
    $exposantsArchive = new WP_Query(array(
        'posts_per_page' => -1,
        'post_type' => 'exposant',
        'orderby' => 'title',
        'order' => 'ASC',
    )); ?>

    <div class="row row--2col u-m-top--8">

        <?php   
        while($exposantsArchive->have_posts()) {
            $exposantsArchive->the_post(); 
            
            $first_letter = strtoupper(substr(apply_filters('the_title',$post->post_title),0,1));
            
            $logo = get_field('logo');
            
            if($first_letter == strtoupper($letter)) { ?>
            <div class="exposant__thumb col--padding-right">
                <div class="exposant__logo">
                    <img src="<?php echo $logo['url'] ?>" alt="<?php echo $logo['alt'] ?>">
                </div>
                <div class="exposant__thumb-content">
                    <h2 class="heading--as-h4 heading--no-margin"><?php the_title(); ?></h2>
                    <?php 
                    $related = get_field('pieces_liees');
                    if($related) {
                        echo '<p class="exposant__categories">';
                        foreach ($related as $k=>$category) { 
                            if($k) echo '/';
                            ?>
                            <a href="<?php echo get_the_permalink($category); ?>"><?php echo get_the_title($category); ?></a>
                        <?php }
                     }
                ?></p>
                    <p class="exposant-thumb__excerpt"><?php echo wp_trim_words( get_field('description'), 16, '...' ); ?></p>
                    <a href="<?php the_permalink(); ?>" class="btn"><?php _e('Plus de détails', 'festival'); ?></a>
                </div>
            </div>

            <?php
        }
    } 
        wp_reset_postdata() ?>
    </div>

I imagine I’d have to replace the else {$letter = $firstLetters[0];} but I have no idea with what.

Thanks in advance for your precious support.

EDIT!

Here is the solution that ended up working flawlessly!

So in functions.php

<?php
add_filter( 'posts_where', 'tomtom_posts_where', 10, 2 );
function tomtom_posts_where( $args, $wp_query_obj )
{
    global $wpdb;
    $starts_with = $wp_query_obj->get( 'starts_with' );
    if ( $starts_with ) {
        $args .= ' AND ' . $wpdb->posts . '.post_title LIKE '' . esc_sql( $wpdb->esc_like( $starts_with ) ) . '%'';
    }
    return $args;
}

And here is the page

<?php

    /**
     * Outputs an alphabetic paginator.
     *
     * @return void
     */
    function tomtom_output_alphabetic_paginator() {
            $posts = get_posts( array(
                    'numberposts' => -1,
                    'post_type'   => 'exposant',
                    'orderby'     => 'title',
                    'order'       => 'ASC',
            ) ); 
                    
            $firstLetters = array();
            foreach ( $posts as $post ) {
                    $title              = $post->post_title;
                    $startingLetter     = substr( $title, 0, 1 );
                    $dupeFirstLetters[] = $startingLetter;
            }

            $firstLetters = array_unique( $dupeFirstLetters );
            sort( $firstLetters );

            echo "<a href="/exposants/#exposants">" . __('Tout', 'festival') . "</a>";
            foreach ( $firstLetters as $letter ) {
                    echo "<a href="?lettre={$letter}#exposants">{$letter}</a>";
            }
    }

    /**
     * Gets an array of exposant custom post types.
     *
     * @return array
     */
    function tomtom_get_exposants() {
            $args = array(
                    'posts_per_page' => -1,
                    'post_type' => 'exposant',
                    'orderby' => 'title',
                    'order' => 'ASC',
            );
            if ( !empty( $_GET['lettre'] ) ) {
                    $args['starts_with'] = $_GET['lettre'];
            }
            $wp_query = new WP_Query( $args );
            return $wp_query->get_posts();
    }       

    /**
     * Outputs links related to exposant custom post type object.
     *
     * @return void
     */
    function tomtom_output_related( $related ) {
            foreach ( $related as $k => $category ) { 
                    if ( $k ) {
                            echo ' / ';
                    }
                    echo "<a href="" . get_the_permalink( $category ) . "">" . get_the_title( $category ) . "</a>";
            }
    }

    ?>
    <div class="exposant__filter" id="exposants">   
            <?php tomtom_output_alphabetic_paginator(); ?>
    </div>

    <?php $exposantsArchive = tomtom_get_exposants(); ?>
    <div class="row row--2col u-m-top--8">
    <?php foreach ( $exposantsArchive as $exposant ): ?>
            <?php $logo = get_field('logo', $exposant->ID); ?>
            <?php $related = get_field('pieces_liees', $exposant->ID); ?>
            <?php $description = get_field('description', $exposant->ID); ?>

            <div class="exposant__thumb col--padding-right">
                    <div class="exposant__logo">
                            <img src="<?php echo $logo['url'] ?>" alt="<?php echo $logo['alt'] ?>">
                    </div>
                    <div class="exposant__thumb-content">
                            <h2 class="heading--as-h4 heading--no-margin"><?php echo $exposant->post_title; ?></h2>
                            <?php if ( $related ): ?>
                            <p class="exposant__categories">
                                    <?php tomtom_output_related( $related ); ?>
                            </p>
                            <?php endif; ?>
                            <p class="exposant-thumb__excerpt"><?php echo wp_trim_words( $description, 20, '...' ); ?></p>
                            <a href="<?php get_permalink( $exposant->ID ); ?>" class="btn"><?php _e( 'Plus de détails', 'festival' ); ?></a>
                    </div>
            </div>
    <?php endforeach; ?>
    </div>

Advertisement

Answer

If I understand the problem correctly, here’s an slightly optimized version of your code. I’ve taken the liberty of decoupling your php and your html as much as I could for clarity.

It’s not tested, it may take a few tweaks, but overall I hope this does the trick!

In your functions.php file, add this, which will allow you to filter your database queries by first letter:

add_filter( 'posts_where', 'tomtom_posts_where', 10, 2 );
function tomtom_posts_where( $args, $wp_query_obj )
{
    global $wpdb;
    $starts_with = $wp_query->get( 'starts_with' )
    if ( $starts_with ) {
        $args .= ' AND ' . $wpdb->posts . '.post_title LIKE '' . esc_sql( $wpdb->esc_like( $starts_with ) ) . '%'';
    }
    return $where;
}

Then:

<?php

/**
 * Outputs an alphabetic paginator.
 *
 * @return void
 */
function tomtom_output_alphabetic_paginator() {
    $posts = get_posts( array(
        'numberposts' => -1,
        'post_type'   => 'exposant',
        'orderby'     => 'title',
        'order'       => 'ASC',
    ) ); 
        
    $firstLetters = array();
    foreach ( $posts as $post ) {
        $title              = $post->post_title;
        $startingLetter     = substr( $title, 0, 1 );
        $dupeFirstLetters[] = $startingLetter;
    }

    $firstLetters = array_unique( $dupeFirstLetters );
    sort( $firstLetters );

    echo "<a href="/exposants/#exposants">" . __('Tout', 'festival') . "</a>";
    foreach ( $firstLetters as $letter ) {
        echo "<a href="?lettre={$letter}">{$letter}</a>";
    }
}

/**
 * Gets an array of exposant custom post types.
 *
 * @return array
 */
function tomtom_get_exposants() {
    $args = array(
        'posts_per_page' => -1,
        'post_type' => 'exposant',
        'orderby' => 'title',
        'order' => 'ASC',
    );
    if ( ! empty( $_GET['lettre'] ) ) {
        $args['starts_with'] = $_GET['lettre'];
    }
    return new WP_Query( $args );
}

/**
 * Adds fields to an exposant custom post type object.
 *
 * @param WP_Post $exposant Exposant custom post type.
 * @return void
 */
function tomtom_hydrate_exposant( &$exposant ) {
    $exposant->logo        = get_field( 'logo', $exposant->ID );
    $exposant->related     = get_field( 'pieces_liees', $exposant->ID );
    $exposant->description = get_field( 'description', $exposant->ID );
}

/**
 * Outputs links related to exposant custom post type object.
 *
 * @return void
 */
function tomtom_output_related( $exposant ) {
    if ( ! isset( $exposant->related ) ) {
        tomtom_hydrate_exposant( $exposant );
    }
    foreach ( $exposant->related as $k => $category ) { 
        if ( $k ) {
            echo '/';
        }
        echo "<a href="" . get_the_permalink( $category ) . "">" . get_the_title( $category ) . "</a>";
    }
}

?>
<div class="exposant__filter" id="exposants">   
    <?php tomtom_output_alphabetic_paginator(); ?>
</div>

<?php $exposantsArchive = tomtom_get_exposants(); ?>
<div class="row row--2col u-m-top--8">
<?php foreach ( $exposantsArchive as $exposant ): ?>
    <?php tomtom_hydrate_exposant( $exposant ); ?>
    
    <div class="exposant__thumb col--padding-right">
        <div class="exposant__logo">
            <img src="<?php echo $exposant->logo['url'] ?>" alt="<?php echo $exposant->logo['alt'] ?>">
        </div>
        <div class="exposant__thumb-content">
            <h2 class="heading--as-h4 heading--no-margin"><?php echo $exposant->post_title; ?></h2>
            <?php if ( $exposant->related ): ?>
            <p class="exposant__categories">
                <?php tomtom_output_related( $exposant->related ); ?>
            </p>
            <?php endif; ?>
            <p class="exposant-thumb__excerpt"><?php echo wp_trim_words( $exposant->description, 16, '...' ); ?></p>
            <a href="<?php get_permalink( $exposant->ID ); ?>" class="btn"><?php _e( 'Plus de détails', 'festival' ); ?></a>
        </div>
    </div>
<?php endforeach; ?>
</div>
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement