Support

Account

Home Forums General Issues Filtering issues which remove images and filters on page

Solved

Filtering issues which remove images and filters on page

  • Hi there,

    I’ve setup an archive page using Advanced Custom Fields to populate it with a series of Custom Post Type data including images, title and link. The parent page uses another set of ACF-powered fields to populate a header image and the title/subtitle. ACF is also used to populate a series of filters/checkboxes.

    On visiting the standard page, the checkboxes are displayed correctly and some of the post data is displayed (titles and film certificate). However, the header image and the results are missing their image.

    When running a query via the URL, the checkboxes disappear but all of the images and other data are loaded correctly.

    Some example queries are below:
    https://apexcinemas.andrewcourtney.co.uk/films/?film_genre=Action
    https://apexcinemas.andrewcourtney.co.uk/films/?film_genre=Animation
    https://apexcinemas.andrewcourtney.co.uk/films/?film_genre=Animation,Action
    https://apexcinemas.andrewcourtney.co.uk/films/?film_genre=Thriller (no results but just to prove that the header image and filters are still removed)

    The code used within the functions.php to control the query behaviour is below, taken from the following ACF tutorial (which I’ve modified the “// Get original meta query” line for to comply with the PHP version I’m working with (7.3.12) to change “$meta_query” to an array ($meta_query[]).

    https://www.advancedcustomfields.com/resources/creating-wp-archive-custom-field-filter/

    I thought it was worth including the ACF settings I have applied to my custom fields:

    Header image
    Using “Image” ACF Type
    Uses “Image URL” Return Format
    Uses “get_field” to display content

    Film Poster
    Using “Image” ACF Type
    Uses “Image URL” Return Format
    Uses “the_field” to display content

    Film Certificate (unaffected)
    Uses “Button Group” Type
    Uses “Value” Return Value
    Series of if statements based on the “get_field” to determine the image that’s loaded

    Below is the entire page code for the archive page I have:

    <?php
    get_header();
    ?>
    <?php
    $films = new WP_Query(array(
        'post_type' => 'film',
    )); ?>
    <main class="genericpage genericpage--films">
        <section class="genericpage__header">
            <?php
            if (get_field('film_archive_page_header_image', 'option')) { ?>
                <img src="<?php echo wp_get_attachment_url(get_field('film_archive_page_header_image', 'option')) ?>" alt="<?php echo get_field('film_archive_page_header_title', 'option'); ?>" />
            <?php } else { ?>
                <picture>
                    <source srcset="<?php echo get_theme_file_uri('/images/generic_header_bg_desktop.png') ?>" media="(min-width: 768px)">
                    <source srcset="<?php echo get_theme_file_uri('/images/generic_header_bg_mobile.png') ?>" media="(max-width: 767px)">
                    <img src="<?php echo get_theme_file_uri('/images/generic_header_bg_mobile.png') ?>" alt="<?php echo get_field('film_archive_page_header_title', 'option') ?>" title="<?php echo get_field('film_archive_page_header_title', 'option') ?>" />
                </picture>
            <?php } ?>
            <div class="genericpage__header__text">
                <h1 class="section__heading"><?php if (get_field('film_archive_page_header_title', 'option')) { ?>
                        <?php echo get_field('film_archive_page_header_title', 'option') ?>
                    <?php } else {
                                                    echo "All Films";
                                                } ?></h1>
                <p><?php if (get_field('film_archive_page_header_subtitle', 'option')) { ?>
                        <?php echo get_field('film_archive_page_header_subtitle', 'option') ?>
                    <?php } else {
                        echo "All Films Showing At Apex Cinemas";
                    } ?></p>
            </div>
        </section>
        <section>
            <div id="search-filmgenre">
                <?php
    
                // Load field settings and values.
                $field = get_field_object('film_genre');
                $filmGenres = $field['choices'];
    
                // Display labels.
                if ($filmGenres) : ?>
                    <ul>
                        <?php foreach ($filmGenres as $value => $label) : ?>
                            <li><input type="checkbox" value="<?php echo $value; ?>" <?php if (in_array($value, $filmGenres)) : ?> unchecked <?php endif; ?> /><?php echo $label; ?> </li>
                        <?php endforeach; ?>
                    </ul>
                <?php endif; ?>
            </div>
        </section>
        <section class="filmblock filmblock--subcontainer">
            <?php
    
            while ($films->have_posts()) {
                $films->the_post();
            ?>
                <div class="filmblock filmblock--sub">
                    <a href="<?php the_permalink(); ?>">
                        <img src="<?php echo wp_get_attachment_url(get_field('film_poster')); ?>" alt="<?php the_title() ?>" title="<?php the_title() ?>" />
                        <div class="filmblock--sub__textcontainer">
                            <div class="filmblock--sub__textcontainer__title">
                                <h4 class="filmblock--sub__heading"><?php the_title(); ?></h4> <?php if (get_field('film_certificate') == "U") : ?>
                                    <img src="<?php echo get_theme_file_uri('/images/film-certificate_u.png') ?>" alt="Film age rating <?php get_field('film_certificate') ?>" title="Film age rating <?php get_field('film_certificate') ?>" class="genericpage__header__agerating" />
                                <?php elseif (get_field('film_certificate') == "PG") : ?>
                                    <img src="<?php echo get_theme_file_uri('/images/film-certificate_pg.png') ?>" alt="Film age rating <?php get_field('film_certificate') ?>" title="Film age rating <?php get_field('film_certificate') ?>" class="genericpage__header__agerating" />
                                <?php elseif (get_field('film_certificate') == "12") : ?>
                                    <img src="<?php echo get_theme_file_uri('/images/film-certificate_12.png') ?>" alt="Film age rating <?php get_field('film_certificate') ?>" title="Film age rating <?php get_field('film_certificate') ?>" class="genericpage__header__agerating" />
                                <?php elseif (get_field('film_certificate') == "15") : ?>
                                    <img src="<?php echo get_theme_file_uri('/images/film-certificate_15.png') ?>" alt="Film age rating <?php get_field('film_certificate') ?>" title="Film age rating <?php get_field('film_certificate') ?>" class="genericpage__header__agerating" />
                                <?php elseif (get_field('film_certificate') == "18") : ?>
                                    <img src="<?php echo get_theme_file_uri('/images/film-certificate_18.png') ?>" alt="Film age rating <?php get_field('film_certificate') ?>" title="Film age rating <?php get_field('film_certificate') ?>" class="genericpage__header__agerating" />
                                <?php elseif (get_field('film_certificate') == "TBC") : ?>
                                    <img src="<?php echo get_theme_file_uri('/images/film-certificate_tbc.png') ?>" alt="Film age rating <?php get_field('film_certificate') ?>" title="Film age rating <?php get_field('film_certificate') ?>" class="genericpage__header__agerating" />
                                <?php endif; ?>
                            </div>
                            <div>
                                <span><strong>Post ID:</strong> <?php the_ID(); ?></span><br />
                                <span><strong>Poster Image ID:</strong> <?php echo wp_get_attachment_url(get_field('film_poster')); ?></span><br />
                                <span><strong>Poster Image ID (WP Get Attachment):</strong> <?php echo wp_get_attachment_url(get_field('film_poster')); ?></span>
                            </div>
                            <!--<?php the_excerpt(); ?>-->
                            <span class="cta cta--primary">View More</span>
                        </div>
                    </a>
                </div>
            <?php } ?>
        </section>
        <section class="filmblock filmblock--pagination">
            <?php
    
            echo paginate_links();
    
            ?>
        </section>
    </main>
    <?php
    get_footer();
    ?>

    I am really running at a loss as to what to try to get this working – any thoughts please?

    Many thanks in advance

  • Does anyone have any suggestions please? Thanks in advance!

  • I think you need to check your code.

    For example:
    <img src="<?php echo wp_get_attachment_url(get_field('film_poster')); ?>" alt="<?php the_title() ?>" title="<?php the_title() ?>" />

    If you check the docs for wp_get_attachment_url()

    You will see it accepts an attachment ID but your ACF field is returning:

    Uses “Image URL” Return Format

    So this may explain why the images don’t work

    Checking your ‘results’ page, if you view the source, you can see:

        <section>
            <div id="search-filmgenre">
                        </div>
        </section>

    Looking at your code:

        <section>
            <div id="search-filmgenre">
                <?php
    
                // Load field settings and values.
                $field = get_field_object('film_genre');
                $filmGenres = $field['choices'];
    
                // Display labels.
                if ($filmGenres) : ?>
                    <ul>
                        <?php foreach ($filmGenres as $value => $label) : ?>
                            <li><input type="checkbox" value="<?php echo $value; ?>" <?php if (in_array($value, $filmGenres)) : ?> unchecked <?php endif; ?> /><?php echo $label; ?> </li>
                        <?php endforeach; ?>
                    </ul>
                <?php endif; ?>
            </div>
        </section>

    My thought is due to the URL, the code doesn’t trigger:
    $field = get_field_object('film_genre');

    So where have you assigned that ACF field to?

  • If you check the docs for wp_get_attachment_url()

    You will see it accepts an attachment ID but your ACF field is returning:

    Uses “Image URL” Return Format

    So this may explain why the images don’t work

    Ah I had no idea to be honest (haven’t been working with WordPress long). Presumably if I change the “film_poster” field to return the Image ID, I’ll need to change all instances where I’m using that field so that it uses wp_get_attachment_url?

    I find it strange that the standard page doesn’t load any of the images, while the query version of the same page pulls the images through correctly?

    So where have you assigned that ACF field to?

    The “film_genre” field is attached to the “Film” Field Group, which in turn only shows if the Post Type “is equal to” “Film”. The “Film” Post Type has a slug rewrite on it of “films”, hence the URL.

    Let me know if any other details would be helpful to find out what’s wrong.

  • If you check the docs for wp_get_attachment_url()

    You will see it accepts an attachment ID but your ACF field is returning:

    Uses “Image URL” Return Format

    So this may explain why the images don’t work`

    Ah I had no idea to be honest (haven’t been working with WordPress long). Presumably if I change the “film_poster” field to return the Image ID, I’ll need to change all instances where I’m using that field so that it uses wp_get_attachment_url?

    I find it strange that the standard page doesn’t load any of the images, while the query version of the same page pulls the images through correctly?

    So where have you assigned that ACF field to?

    The “film_genre” field is attached to the “Film” Field Group, which in turn only shows if the Post Type “is equal to” “Film”. The “Film” Post Type has a slug rewrite on it of “films”, hence the URL.

    Let me know if any other details would be helpful to find out what’s wrong.

  • If you check the docs for wp_get_attachment_url()
    
    You will see it accepts an attachment ID but your ACF field is returning:
    
    Uses “Image URL” Return Format
    
    So this may explain why the images don’t work

    Ah I had no idea to be honest (haven’t been working with WordPress long). Presumably if I change the “film_poster” field to return the Image ID, I’ll need to change all instances where I’m using that field so that it uses wp_get_attachment_url?

    I find it strange that the standard page doesn’t load any of the images, while the query version of the same page pulls the images through correctly?

    So where have you assigned that ACF field to?

    The “film_genre” field is attached to the “Film” Field Group, which in turn only shows if the Post Type “is equal to” “Film”. The “Film” Post Type has a slug rewrite on it of “films”, hence the URL.

    Let me know if any other details would be helpful to find out what’s wrong.

  • If I change the return format of “film_poster” to Image ID, presumably that will break all other instances of the image unless I set wp_get_attachment_url() on them?

    The ACF field is assigned to the “Film” Field Group which in turn is set to only appear when the Post Type equals “Film” (which has a slug rewrite set on it to change “film” to “films”).

    What I really don’t get is that the images appear when you run a query, whereas the standard page shows no images. And, when viewing the standard page, the filters are displayed. However if you run a query the numbers disappear.

    If you need any further details to look into this please let me know.

  • Sorry, not quite sure why my replies were duplicated so much – the forum only seemed to take one reply but posted multiple versions.

    Please refer to the latest reply directly above this one, posted November 20, 2021 at 9:25 pm.

    Many thanks!

  • Ok so I’ve managed to get my images pulling through even when filtering which was a simple fix of changing the Return Value of the “film_poster” field to Image ID. It now works when I’m viewing the standard /films page as well as if I send a query (e.g. /films/?film_genre=Action).

    However, I’m still having problems with the filters disappearing when the query is sent (e.g. apexcinemas.andrewcourtney.co.uk/films/?film_genre=Action) – any ideas?

    Below is the code I have running in the functions.php page, taken from the ACF tutorial I mentioned before 🙂

    // filter film genre
    add_action(‘pre_get_posts’, ‘my_pre_get_posts’);

    function my_pre_get_posts($query){
    // validate
    if(is_admin()){
    return;
    }

    // Get original meta query
    $meta_query[] = $query->get(‘meta_query’);

    // allow the url to alter the query
    // e.g. ?film_genre=comedy
    if(isset($_GET[‘film_genre’])){

    $film_genre = explode(‘,’, $_GET[‘film_genre’]);

    // Add our meta query to the original meta queries
    $meta_query[] = array(
    ‘key’ => ‘film_genre’,
    ‘value’ => $_GET[‘film_genre’],
    ‘compare’ => ‘IN’,
    );
    }

    // update the meta query arguments
    $query->set(‘meta_query’, $meta_query);

    // always return
    return;
    }

    Thanks in advance!

  • Glad the images are sorted.

    Ok, add this to your function file:

    <?php
    function which_template_is_loaded() {
    	global $template;
    	print_r( $template );
    }
     
    add_action( 'wp_footer', 'which_template_is_loaded' );

    Now go to the main films page, it will tell you the template, run the filter, is it the same template?
    As I say, I wonder if the results page isn’t the same page, so the filters don’t show. The reason being where you assigned the ACF filters to (if that makes sense)

  • Unfortunately it is returning the same template for both the standard and the results page – see the URL shown at the bottom.

    https://apexcinemas.andrewcourtney.co.uk/films/
    https://apexcinemas.andrewcourtney.co.uk/films/?film_genre=Action

    By the way, if it helps, below are the post type details I entered for “film”/”films” – may be useful?

    // Film Post Type
    register_post_type(‘film’, array(
    ‘show_in_rest’ => true,
    ‘supports’ => array(‘title’, ‘excerpt’),
    ‘rewrite’ => array(‘slug’ => ‘films’),
    ‘has_archive’ => true,
    ‘public’ => true,
    ‘labels’ => array(
    ‘name’ => ‘Films’,
    ‘add_new_item’ => “Add New Film”,
    ‘edit_item’ => “Edit Film”,
    ‘all_items’ => “View All Films”,
    ‘singular_name’ => ‘Film’
    ),
    ‘menu_icon’ => ‘dashicons-editor-video’
    ));

  • Ok, so one thing I think you need to do, is change your function (my_pre_get_posts).

    As a checkbox returns a serialised array, I believe you need to change the compare from IN to LIKE (worth double checking!):

    // append meta query
    $meta_query = [];
    $meta_query[] = array(
    	'key'       => 'film_genre',
    	'value'     => $_GET['film_genre'],
    	'compare'   => 'LIKE',
    );

    Now, the next point to consider is returning ACF fields. Usually, if you want to get a value, you can simply use get_field.
    If you want to get the value from a specific page/post you can add in the ID (more examples can be seen here).

    The issue I think you have is that you’ve assigned the ACF fields to a custom post type and output them on an archive template (archive-film.php).
    As such, for whatever reason, when you move to the result, it doesn’t show the ACF field.

    You then can’t specify an ID against the get_field as an archive doesn’t have an ID value.

    I’ve played around with code locally but can’t seem to get it working either – unless I’m missing something.

    If it were me, I think I’d approach it differently.

    I’d use the films custom post type
    I would then use the film genre as a taxonomy

    I’d create a page called films and have a dedicated template (page-films.php for example).

    It would be far easier to query and you could also look to use AJAX.

    Something like the below. page-films.php

    <?php
    /**
     * @package WordPress
     Template Name: Films
    **/
    get_header();
    ?>
    
    <div class="container-fluid" id="filters">
    	<div class="row">
    		<div class="col-12 py-0">
    			<nav class="navbar navbar-expand-md navbar-fixed-top navbar-light main-nav pt-5 pb-4">
    				<div class="container">
    					<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarFilters" aria-controls="navbarFilters" aria-expanded="false" aria-label="Toggle navigation">
    						<span class="navbar-toggler-icon"></span>
    					</button>
    					<div class="collapse navbar-collapse" id="navbarFilters">					
    					<?php if( $genres = get_terms( array( 'taxonomy' => 'genres' ) ) ) : ?>
    						<ul class="nav navbar-nav order-1 order-md-2">
    						<li class="nav-item active">
    							<a class="reset btn btn-red-outline mr-2 mb-4" href="#" sector="genre" genreid="">All</a>
    						</li>	                        
    						<?php
    						foreach( $genres as $genre ) : ?>
    
    						<li class="nav-item">
    							<a class="btn btn-red-outline mr-2 mb-4" href="#" genre="" genreid="<?php echo $genre->term_id; ?>"><?php echo $genre->name; ?></a>
    						</li>	
    
    						<?php endforeach;      
    						echo '</ul>';
    					endif;
    					?>	
    					</div><!-- /navbarFilters -->
    				</div>
    			</nav>
    		</div><!-- /col-12 -->		
    	</div><!-- /row -->
    </div><!-- /container -->
    
    <?php
    global $wp_query;
    $paged = get_query_var('paged') ? get_query_var('paged') : 1;
    $args = array(
    	'posts_per_page' => 12,
    	'post_type'		=> 'films',
    	'paged' 		=> $paged
    );
    $wp_query = new WP_Query($args); ?>
    <?php if ($wp_query->have_posts()) : ?>
    <section class="container py-0">
    
    	<div class="row" id="ajax_filter_films">
    	<p class="filter_status"></p>
    	<?php while ($wp_query->have_posts()) : $wp_query->the_post(); $col = 'col-md-4'; ?>
    		<?php include( locate_template( 'includes/loop.php', false, false ) ); ?>
    	<?php endwhile;  ?> 
    	</div><!-- /row -->
        
    	<div class="row pt-3 pb-5" id="pagination">
    		<div class="col-12 col-md-8 offset-md-2">
    			<div align="center"><?php wpbeginner_numeric_posts_nav(); ?></div>
    		</div><!-- /col-md-8 -->
    	</div><!-- /row -->	    
        
    </section><!-- /container -->     
    <?php endif; wp_reset_query(); ?>   
    
    <?php
    get_footer();

    loop.php would contain whatever you need, like the post title, image and any other info.

    Then in your footer (or enqueue it), add the javaScript:

    <script>
    //filter the films
    jQuery(function($){
    	$('#filters .btn').click(function(){
    		
    		var genre = jQuery(this).attr("genre");	
    		var genreid = jQuery(this).attr("genreid");	
    		
    		$.ajax({
    			type        : "POST",
    			data		: { action : 'get_film_posts', genre: genre, genreid: genreid }, 
    			dataType	: "html",
    			url			: '<?php echo admin_url('admin-ajax.php');?>', 
    
    			success     : function(data) {
    				//alert(this.data);
    				jQuery("#ajax_filter_films").html(data);
    				
    			},
    			error       : function(xhr, status, error) {
    				var err = eval("(" + xhr.responseText + ")");
    				alert(err.Message);
    			}
    		});
    		return false;
    	});
    });
    </script>

    Finally, in your functions file:

    <?php
    function get_film_posts() {
    	
    	$genre_id = $_POST['genreid'];
    	
    	$genre = $_POST['genre'];
    	
    	if( $sector ) {
    		$terms = get_terms( $genre ); 
    		$genre_id = wp_list_pluck( $terms, 'term_id' );
    	}
    	
    	$args = array(
    			'post_type' 		=> 'films',
    			'post_status'		=> 'publish',
    			'posts_per_page'	=> -1, // show all posts.
    			'order'				=> 'DESC',
    	);
    			
    	$args['tax_query'] = array(
    		'relation' 		=> 'OR', 
    
    		array(
    			'taxonomy'	=> 'genres',
    			'field'		=> 'term_id',
    			'terms'		=> $genre_id
    		),			
    		
    	);
    	
    	$query = new WP_Query( $args );
    	if( $query->have_posts() ) : 
    
    		while( $query->have_posts() ): $query->the_post(); $col = 'col-md-4';	
    			include( locate_template( 'includes/loop.php', false, false ) );
    		endwhile;  wp_reset_postdata();
    
    	endif;
    	
    	die();
    
    }
    // Fire AJAX action for both logged in and non-logged in users
    add_action('wp_ajax_get_film_posts', 'get_film_posts');
    add_action('wp_ajax_nopriv_get_film_posts', 'get_film_posts');

    That should then get you somewhere!

  • Typo in the above, in the functions part, change:

    if( $sector ) {
    		$terms = get_terms( $genre ); 
    		$genre_id = wp_list_pluck( $terms, 'term_id' );
    	}

    To:

    if( $genre ) {
    		$terms = get_terms( $genre ); 
    		$genre_id = wp_list_pluck( $terms, 'term_id' );
    	}
  • Wow ok I’ll give that a go – thanks!
    Just one question; as I have the single-film.php page template, I am displaying the film genre there too as a simple get_field. If I change the film_genre ACF to taxonomy will this part need to be redone?

    See the left column on the following page for an example:
    https://apexcinemas.andrewcourtney.co.uk/films/no-time-to-die/

  • You can just switch the code to something like:

    <?php $genres = get_the_terms( $post->ID, 'genres' ); 
    if( $genres ): ?>
    	<h2>Genres</h2>
    	<ul>
    	<?php foreach( $genres as $genre ): ?>
    	<li><?php echo $genre->name; ?></li>
    	<?php endforeach; ?> 
    	</ul>
    <?php endif; ?>	

    That will then output any genres associated to that film/post

  • Ok so I’ve thought about this a bit more and experimented with the taxonomy field type but quickly realised that I’d need a separate taxonomy from for example the default posts (e.g. tags or categories). I’m currently using the default posts for a blog part of the website so I don’t want to cross-pollinate between my custom post type and the default posts.

    I’ve tried looking into hiding the option on the default posts menu but all of the solutions result in errors in parts of the sidebar menu.

    Anyway – I resorted to going back to the tutorial Elliot created but I’m now getting an error with my foreach for some reason, no matter whether I’m viewing the standard view or the filtered view?

    https://apexcinemas.andrewcourtney.co.uk/films/
    https://apexcinemas.andrewcourtney.co.uk/films/?film_genre=Action

    Tutorial link again: https://www.advancedcustomfields.com/resources/creating-wp-archive-custom-field-filter/

    <div id=”search-filmgenre”>
    <?php

    $field = get_field_object(‘film_genre’);
    $values = explode(‘,’, $_GET[‘film_genre’]);
    $filmGenres = $field[‘choices’];

    ?>

      <?php foreach($filmGenres as $choice_value => $choice_label) : ?>

    • <input type=”checkbox” value=”<?php echo $choice_value; ?>” <?php if (in_array($choice_value, $values)) : ?>checked=”checked” <?php endif; ?> /><?php echo $choice_label; ?>
    • <?php endforeach; ?>

    </div>

    Any thoughts please? Thanks so much for your help so far.

  • Why don’t you create your own custom genre taxonomy? That leaves the existing categories for the blogs. Assuming I’ve understood

  • Yes that’s exactly what I meant but I couldn’t find how to create a custom taxonomy at the time.

    However, after a bit more research I found that I can install this plugin and create a custom taxonomy that way – would that be the best approach?

    https://en-ca.wordpress.org/plugins/custom-post-type-ui/

  • Ok, so the following is based on your code and my suggestion.

    Before doing anything, backup your site.

    You already have the code in your functions file to create the film custom post type.

    So now you can add the following to your functions file:

    
    ########################
    # Add Taxonmoies
    ########################
    
    function register_taxonomies() {
    
    	$taxonomies = array(
    		
    		array(
    			'slug'         => 'genres',
    			'single_name'  => 'Genre',
    			'plural_name'  => 'Genres',
    			'post_type'    => 'film',
    			'hierarchical' => true,
    		),							
    		
    	);
    
    	foreach( $taxonomies as $taxonomy ) {
    		$labels = array(
    			'name' => $taxonomy['plural_name'],
    			'singular_name' => $taxonomy['single_name'],
    			'search_items' =>  'Search ' . $taxonomy['plural_name'],
    			'all_items' => 'All ' . $taxonomy['plural_name'],
    			'parent_item' => 'Parent ' . $taxonomy['single_name'],
    			'parent_item_colon' => 'Parent ' . $taxonomy['single_name'] . ':',
    			'edit_item' => 'Edit ' . $taxonomy['single_name'],
    			'update_item' => 'Update ' . $taxonomy['single_name'],
    			'add_new_item' => 'Add New ' . $taxonomy['single_name'],
    			'new_item_name' => 'New ' . $taxonomy['single_name'] . ' Name',
    			'menu_name' => $taxonomy['plural_name']
    		);
    		
    		$rewrite = isset( $taxonomy['rewrite'] ) ? $taxonomy['rewrite'] : array( 'slug' => $taxonomy['slug'] );
    		$hierarchical = isset( $taxonomy['hierarchical'] ) ? $taxonomy['hierarchical'] : true;
    	
    		register_taxonomy( $taxonomy['slug'], $taxonomy['post_type'], array(
    			'hierarchical' => $hierarchical,
    			'labels' => $labels,
    			'show_ui' => true,
    			'show_admin_column' => true,
    			'query_var' => true,
    			'rewrite' => $rewrite,
    		));
    	}
    	
    }
    add_action( 'init', 'register_taxonomies' );
    
    ##########################
    # Ajax filter Films
    ##########################
    function filter_films() {
    	
    	$args = array(
    		'post_type'			=> 'film',
    		'posts_per_page'	=> -1,
    	);
    
    	if( isset( $_POST['genre'] ) )
    		$args['tax_query'] = array(
    			array(
    				'taxonomy' => 'genres',
    				'field' => 'id',
    				'terms' => $_POST['genre']
    			)
    		);
    		
    
    	$query = new WP_Query( $args );
    	if( $query->have_posts() ) :
    		while( $query->have_posts() ): $query->the_post();
    		?>
    		<h2><?php the_title(); ?></h2>
    		<?php
    		endwhile;
    		wp_reset_postdata();
    	else :
    		echo 'No films found matching your criteria.';
    	endif;
    	
    	die();
    
    }
    // Fire AJAX action for both logged in and non-logged in users
    add_action('wp_ajax_filter_films', 'filter_films');
    add_action('wp_ajax_nopriv_filter_films', 'filter_films');

    The first part creates the custom taxonomy for Genres.
    The second part handles the filtering which we’ll come to next.

    Create a page called films.
    Now create a template file called page-films.php, from here you can add the following code:

    <?php
    /**
     * @package WordPress
     Template Name: Films 
    **/
    get_header();
    ?>
    
    <div id="filters">
    <?php
    $genres = array(
    	'taxonomy'		=> 'genres',
    );
    $genres = get_categories( $genres );
    ?>
    <?php foreach($genres as $genre): ?>
    	<input type="checkbox" value="<?php echo $genre->term_id; ?>" class="form-check-input genre" />
    	<label class="form-check-label" for="<?php echo $genre->cat_name; ?>"><?php echo $genre->cat_name; ?></label>       
    <?php endforeach; ?>
    <a href="#" class="btn" id="reset_genre">Reset Genres</a>  
    </div><!-- /filters -->
    
     
    <div id="ajax_filter_films">	      
    <?php      
    $args = array(
    	'post_type'			=> 'film',
    	'posts_per_page'	=> -1,
    );
            
    $query = new WP_Query( $args );
    if( $query->have_posts() ) :
    	while( $query->have_posts() ): $query->the_post();
        ?>
    	<h2><?php the_title(); ?></h2>
    	<?php
    	endwhile;
    	wp_reset_postdata();
    else :
    	echo 'No films found matching your criteria.';
    endif;
    ?>  
    </div><!-- /ajax_filter_films -->
    
    <?php
    get_footer();

    You can assign the template films to the page, but due to naming conventions, should work. I always add it as a fallback.

    Now, in your footer you can add:

    
    <script type="text/javascript">
    //filter the films
    jQuery(function($){
        filter_data();
    
        function filter_data()
        {
            $('.filter_data').html('<div id="loading" style="" ></div>');
            var action = 'filter_films';		
    		
            var genre = get_filter('genre');	
    		
    		$.ajax({
    			type        : "POST",
    			data		: { action:action, genre:genre},
    			dataType	: "html",
    			url			: '<?php echo admin_url('admin-ajax.php');?>', 
    
    			success     : function(data) {
    				//alert(this.data);
    				jQuery("#ajax_filter_films").html(data);
    			},
    			error       : function(xhr, status, error) {
    				var err = eval("(" + xhr.responseText + ")");
    				alert(err.Message);
    			}
    		});
    		return false;
        }
    
        function get_filter(class_name)
        {
            var filter = [];
            $('.'+class_name+':checked').each(function(){
                filter.push($(this).val());
            });
            return filter;
        }
    
        $('.form-check-input').click(function(){
            filter_data();
        });
    	
    	$("#reset_genre").click(function(){
    		// get the current selected values
    		var genre = [];
    		$('.genre:checked').each(function(){
    			genre.push($(this).val());
    		});
    		
    		// loop through and remove the selected checkobox
    		var i;
    		for (i = 0; i < genre.length; i++) {
    			$(".genre:checkbox[value="+genre[i]+"]").parent().removeClass('selected'); //remove the highlighted lable
    			$(".genre:checkbox[value="+genre[i]+"]").prop("checked", false); //uncheck the hidden checkbox
    		}		
    		
    		// reset the array
    		genre = []; 
    		console.log(genre); //debug
    	
    		// update the filter
    	 	filter_data();			  
    	});				
    	
    });
    </script>

    I’d probably flush the permalinks!

    You can now go to films within wp-admin and you should see a menu option called Genres.
    Add the ones you need
    Edit your films and assign one/multiples.
    Go to the films page on the front end (its basic but gives you the idea).
    You should now see all the films you’ve added plus a bunch of checkboxes.

    Tick one or many and the results should filter!

    The code is completely tested and works with a fresh WP install and the Twentytwentyone theme.

  • Sorry it’s been a few days Jarvis – thank you so much for the clear explanation and putting this together. It definitely gives me a solid foundation to build on!

    A couple of questions I had was that while testing the setup, I noticed that it would never display the message “No films found matching your criteria.” it would seem, as only the genres that are assigned to films are shown on the form – i.e. it doesn’t display ALL genres by default, regardless of whether there are films assigned or not? Just an observation though as really you wouldn’t want someone to select an option if no results were available.

    Also, on the single film page I had the genre being displayed via a simple “get_field” for the ACF “film_genre” contents, but also a “You May Also Like” section based entirely on films with the same genre – again, using the “film_genre” contents as a basis.

    <!– START “You may also like” –>
    <?php

    $filmGenre = get_field(‘film_genre’);
    // args
    $args = array(
    ‘numberposts’ => -1, // Displays ALL post
    ‘post_type’ => ‘film’, // Change to reflect the name of your custom post type
    ‘meta_key’ => ‘film_genre’, // Change to reflect the name of your custom field
    ‘meta_value’ => $filmGenre, // Change to reflect the name of the value in your custom field
    ‘post__not_in’ => array($post->ID) // Exclude current post ID
    );
    // get results
    $the_query = new WP_Query($args);
    // The Loop
    ?>
    <?php if ($the_query->have_posts()) : ?>
    <div class=”genericpage–film__details genericpage–film__details–ymal”>

    <h2>You may also like</h2>
    <!– START – You May Also Like Slider –>
    <div class=”section__slider-container text-center”>
    <div class=”filmpanels swiper swiper-container swiper–section swiper–section–filmsymal”>
    <div class=”swiper-wrapper”>
    <?php while ($the_query->have_posts()) : $the_query->the_post() ?>
    <div class=”swiper-slide”>
    ” title=””>
    ” alt=”<?php the_title() ?>” title=”<?php the_title() ?>” class=”swiper__imgbg” />
    <p><?php the_title() ?></p>

    </div>
    <?php endwhile; ?>
    </div>
    <div class=”swiper-button-prev”></div>
    <div class=”swiper-button-next”></div>
    </div>
    </div>
    <!– END – You May Also Like Slider –>
    </div>
    <?php endif; ?>
    <?php wp_reset_query(); // Restore global post data stomped by the_post().
    ?>
    <!– END – “You may also like” –>

    Thanks again; plenty for me to think about!

  • Sorry, not sure what happened with my code there – I think the forum misinterpreted my a tag and changed it to a link!

    <!-- START "You may also like" -->
                    <?php
    
                    $filmGenre = get_field('film_genre');
                    // args
                    $args = array(
                        'numberposts'     => -1,                    // Displays ALL post
                        'post_type'     => 'film',    // Change to reflect the name of your custom post type
                        'meta_key'        => 'film_genre',      // Change to reflect the name of your custom field
                        'meta_value'    => $filmGenre,           // Change to reflect the name of the value in your custom field
                        'post__not_in' => array($post->ID) // Exclude current post ID
                    );
                    // get results
                    $the_query = new WP_Query($args);
                    // The Loop
                    ?>
                    <?php if ($the_query->have_posts()) : ?>
                        <div class="genericpage--film__details genericpage--film__details--ymal">
                            <a name="ymal"></a>
                            <h2>You may also like</h2>
                            <!-- START - You May Also Like Slider -->
                            <div class="section__slider-container text-center">
                                <div class="filmpanels swiper swiper-container swiper--section swiper--section--filmsymal">
                                    <div class="swiper-wrapper">
                                        <?php while ($the_query->have_posts()) : $the_query->the_post() ?>
                                            <div class="swiper-slide">
                                                <a href="<?php the_permalink(); ?>" title="">
                                                    <img src="<?php echo wp_get_attachment_url(get_field('film_poster')); ?>" alt="<?php the_title() ?>" title="<?php the_title() ?>" class="swiper__imgbg" />
                                                    <p><?php the_title() ?></p>
                                                </a>
                                            </div>
                                        <?php endwhile; ?>
                                    </div>
                                    <div class="swiper-button-prev"></div>
                                    <div class="swiper-button-next"></div>
                                </div>
                            </div>
                            <!-- END - You May Also Like Slider -->
                        </div>
                    <?php endif; ?>
                    <?php wp_reset_query();  // Restore global post data stomped by the_post().
                    ?>
                    <!-- END - "You may also like" -->
  • The checkboxes on the film page will only be shown if a film is assigned, so it prevents someone clicking filters and having no results.
    The code is in place as fallback OR in case you wish to adjust this behaviour.

    With regards to the similar/related films on the single film page, it depends on whether a film is assigned to one or many categories?

    Basically, you get the genres associated to the film you’re on, you can then run a query on the film post type and loop the results, something like:

    <?php
    $genres = get_the_terms( $post->ID, 'genres' ); 
    $genre = $genres[0];
    
    // print object from first genre
    #print_r($genre);
    
    // or get the genre name
    #echo $genre->name.' '.$genre->term_id;	
    	
    global $wp_query;
    $paged = get_query_var('paged') ? get_query_var('paged') : 1;
    
    $args = array( 
    	'posts_per_page'	=> 3,
    	'post_type'			=> 'film',
    	'paged'				=> $paged,
    	'fields'			=> 'ids',
    	'post__not_in'		=> array( $post->ID )
    );
    if($genre):
    $args['tax_query'] = array (
    	'relation' => 'OR', 
    
    	array(
    		'taxonomy'	=> 'genres',
    		'field'		=> 'term_id',
    		'terms'		=> $genre->term_id
    	), 
    );
    endif;
    
    $wp_query = new WP_Query($args);
    if ($wp_query->have_posts()) :
    ?>	
    
    <h3>Similar Films</h3>
    <ul>
    	<?php while ($wp_query->have_posts()) : $wp_query->the_post(); ?>
    	<li><?php the_title(); ?></li>
    <?php endwhile;  ?>                       
    </ul>
    <?php endif; wp_reset_query(); ?>

    So basically, it you have multiples, it gets the first taxonomy only. You can of course adjust this but should help you out

  • Ah excellent – thank you so much for your help! Very much appreciated!

  • Hi Jarvis,

    I’ve now started to flesh out the design of the page a bit more by introducing what I had before the filters were put in place which used ACFs to show content such as an image, the relevant film certificate as well as a short writeup and “view more” CTA.

    However, after putting the relevant code within the while loop, I’ve found that within a split second it is replaced by text-only examples.

    Please could you advise?

    Many thanks!

  • Just as an example, I’ve deployed my changes to the following page:

    https://apexcinemas.andrewcourtney.co.uk/films/

Viewing 25 posts - 1 through 25 (of 28 total)

You must be logged in to reply to this topic.