Support » Developing with WordPress » How do I create a numerical range for a link on to a custom taxonomy?

  • I am working on creating a music book for my band. I have created one custom taxonomy for both tempo and time signature. One part is a number. I would like to have that number shown on the post and then when you click on the link it shows all posts within that range i.e. 104-130. I also am putting time signatures in there so I would also want it to match the time signature (4/4 or 6/8 for example) so just probably an if then kind of thing maybe?

    Thanks ahead of time for your help!

    Here is what I have right now from my taxonomy (borrowed most of it from the new Twenty_seventeen which is the theme I’m building off of):

    <?php
    /* translators: used between list items, there is a space after the comma */
    $separate_meta = __( ‘, ‘, ‘twentyseventeen’ );

    // Get Categories for posts.
    $categories_list = get_the_category_list( $separate_meta );

    // Get Tags for posts.
    $tags_list = get_the_tag_list( ”, $separate_meta );

    echo ‘<div class=”entry-footer”>’;
    echo ‘<span class=”cat-tags-links”>’;

    echo ‘<span class=”tags-links”>’ . twentyseventeen_get_svg( array( ‘icon’ => ‘hashtag’ ) ) . ‘<span class=”screen-reader-text”>’ . __( ‘Tags’, ‘twentyseventeen’ ) . ‘</span>’ . $tags_list . ‘</span>’;
    echo ‘<span class=”cat-links”>’ . twentyseventeen_get_svg( array( ‘icon’ => ‘folder-open’ ) ) . ‘<span class=”screen-reader-text”>’ . __( ‘Categories’, ‘twentyseventeen’ ) . ‘</span>’ . $categories_list . ‘</span>’;

    echo ‘</span>’;

    echo ‘</div> <!– .entry-footer –>’;

    ?>

    The page I need help with: [log in to see the link]

Viewing 8 replies - 1 through 8 (of 8 total)
  • Moderator bcworkz

    (@bcworkz)

    How are you determining the range of tempos to query for? Doesn’t music typically have a single tempo? I know there can be tempo changes where a piece can have a limited number of different tempos, but isn’t a single tempo sort of the norm?

    In any case, when dealing with numeric ranges, it’s best to store the minimums and maximums as separate values. It’s difficult to query for a value within a range represented by single string like “110-130”. Where tempo is > 110 and < 130 works much better.

    In the case of time signatures, I imagine simply matching a string value will be enough. You wouldn’t need to query within a range like between “4/4” and “6/4” would you?

    When you make links, it could be something like example.com/music/?min=110&max=130&time=4/4 . The /music page could have custom template code that grabs those URL parameters and forms a query based on them, then displays the results of that query.

    All of the songs I am using (except for one and I’ll figure out a way to deal with that) have a single tempo. But what I want to be able to do is look up songs with a similar tempo by clicking on a link on the top of the song. That was when I am playing and I want to play a similar song it is within easy grasp.
    So where would I define that query? Is that in functions.php?

    Here’s what I have for displaying them on the page so far since they are custom taxonomies I can’t use the get_tags_list I assume.

    <?php $terms = get_the_terms( $post->ID , ‘tempo’ );
    foreach ( $terms as $term ) {
    $term_link = get_term_link( $term, ‘tempo’ );
    if( is_wp_error( $term_link ) )
    continue;
    echo ‘<span class=”tags-links”>’ . ‘‘ . $term->name . ‘‘ . ‘</span>’;
    }
    ?>
    <?php $terms = get_the_terms( $post->ID , ‘time_signature’ );
    foreach ( $terms as $term ) {
    $term_link = get_term_link( $term, ‘time_signature’ );
    if( is_wp_error( $term_link ) )
    continue;
    echo ‘ ‘ .'<span class=”tags-links”>’ . ‘‘ . $term->name . ‘‘ . ‘</span>’;
    }
    ?>

    How can I modify the link to do that range and require the same time_signature term as well?

    Moderator bcworkz

    (@bcworkz)

    get_tags_list() isn’t a standard WP function AFAIK. It may or may not work on your site, IDK. Anyway, get_terms() will work for any taxonomy term query, but you will need extra code to generate the desired output.

    BTW, when posting code, please delimit your code with backticks or use the ‘code’ button in the edit box. When you fail to do this, the forum’s parser corrupts your code, making it difficult to use or test.

    Building a link that passes all the necessary data is fairly simple, but getting WP to recognize and use the data in a query gets a little involved. Your goal is presumably to query for custom post types (music? or are songs handled as regular posts?) having certain taxonomy terms. Your base link should then be for the custom post type, which normally will list all such posts regardless of terms assigned. example.com/music/

    Add to this link your desired term criteria. example.com/music/?min=110&max=130&time=4/4 How you determine the min and max tempo is up to you. You could take the current song’s tempo, then add and subtract 10 bpm, 20 bpm, whatever. Or get a percentage difference like plus or minus 10%.

    I previously mentioned a custom page, and now I’m going with a default template listing whose query is modified. Either way works, and the concept of specifying criteria is the same. Where the criteria is applied changes slightly.

    If you hook the “query_vars” filter and add min, max, and time to the list, the URL parameters will be available as WP_Query object query_vars. Hook the pre_get_posts” action to get these values and construct the required query arguments. Be sure the query is for a limited set of songs by checking $query->is_main_query() and that the custom query vars have values assigned.

    I just realized that taxonomy terms are a very poor way to manage a range of values. Taxonomy queries only confirm if a particular term exists or not. It cannot decide if terms are within a numeric range. To do a range query, you should assign a post meta or custom field (same thing, different labels) value for song tempo. Then meta_query can be used to restrict songs to within a particular value range.

    I hope you haven’t gotten to far along in assigning tempo taxonomy terms and switching to post meta would not be too onerous. If there is a huge amount of data to change, a custom one time script could be written to assign meta values based on tempo terms assigned.

    Once the song’s data schema is sorted, setting tax_query and meta_query criteria for the music query could look something like this:

    $query->set('tax_query', array(
    	array(
    		'taxonomy' => 'time_signature',
    		'field'    => 'slug',
    		'terms'    => $query->get('time'),
    	),
    ));
    $query->set('meta_query', array(
    	array(
    		'key'     => 'tempo',
    		'value'   => array( $query->get('min'), $query->get(max')),
    		'type'    => 'numeric',
    		'compare' => 'BETWEEN',
    	),
    ));

    The array in an array bit seems a bit strange, but it is correct. It makes more sense when you have complex queries involving different taxonomies and meta keys, each with their unique criteria and relationships.

    Awe ok! I guess I assumed it was a standard function since it was in a stock theme but it must be theme specific in TwentySeventeen.
    Oh I’m still a newbie on the forums. I’ll make sure and do that from now one so it doesn’t mess up the code!
    Right now I am putting the code directly in the content.php file in my theme for posts. There is probably a better way to do this? If so let me know?
    No big deal on transitioning to meta data. I haven’t gotten too far along on putting songs in for that reason.
    Here is what I have so far encompassing the whole header. I tried inputting the code you shared as well as incorporating “$query_vars” in the link:
    However, it is crashing so I know I’ve done something wrong! 🙂

    		<?php //Tempo Link
    	 		$query->set('tax_query', array(
    			array(
    			  	 'taxonomy' => 'time_signature',
    		   		 'field'    => 'slug',
    				 'terms'    => $query->get('time'),
    				),
    			));
    		$query->set('meta_query', array(
    			array(
    				'key'     => 'tempo',
    				'value'   => array( $query->get('80'), $query->get('120')),
    				'type'    => 'numeric',
    				'compare' => 'BETWEEN',
    				),
    			));
    		//Get Meta Data for Tempos
    		global $post;
    					$meta = get_post_meta($post->ID,'tempo-tempo_1', true); // Use myinfo-box1, myinfo-box2, myinfo-box3 for respective fields
    					if($meta != '') {
    					echo '<span><img src="/wp-content/themes/worshipbook/assets/images/metronome.svg" width="15" height="18"></span>' . '<span style="margin-left:30px"><a href=" ' . $query_vars . ' ">' . $meta . '</a></span>';
    					}else { ; 
    					} 
    					echo '</span>';
    		//Get Time Signatures			
    	     $terms = get_the_terms( $post->ID , 'time_signature' ); 
                        foreach ( $terms as $term ) {
                            $term_link = get_term_link( $term, 'time_signature' );
                            if( is_wp_error( $term_link ) )
                            continue;
                        echo '<span class="enty-tempo-timesignature">';
                        echo '<span><img src="/wp-content/themes/worshipbook/assets/images/G-clef.svg" width="10" height="18"></span>' . '<span style="margin-left:30px"><a href="' . $term_link . '">' . $term->name . '</a></span>';
                        echo '</span>';
                        } 
    
                echo '</span>';
                echo '</div>';
    	?>
    Moderator bcworkz

    (@bcworkz)

    No worries about code formatting. It used to be well documented on the new topic form. It’s now buried two levels down in docs that no one reads. Welcome to the forums! 🙂

    Creating the link portion is appropriate for content.php if where you want to have the link appear is covered by that template. The code altering the destination query that lists related songs goes on functions.php. This is for the scheme where we use default theme templates. The other scheme where the songs are listed on a single page would require a custom page template be created.

    When you need to customize your theme like this, it’s strongly recommended that you create a child theme, otherwise your custom work will be overwritten when the theme updates.

    The code I suggested for modifying the query is incomplete, it’s intended to go into a callback function for a hook into the “pre_get_posts” action. If action hooks are new to you, you should read up on them in the Plugin Handbook. Code mentioned for plugins can be implemented in child themes equally effectively.

    A pre_get_posts callback needs to check several conditions to ensure the query being altered is the one desired and not something else. Two things most callbacks need to check is ! is_admin() and $query->is_main_query(). Assuming you’ve added the query vars min, max, and time to the whitelist through the “query_vars” filter hook, your pre_get_posts callback can also check for the presence of values in these query vars. This will uniquely identify the query you wish to alter.

    Once those checks are confirmed, the code I posted previously will correctly alter the query to only return songs with the requested properties.

    I’ve thrown a lot of new information at you. The code is a lot simpler than the explanation, try not to feel overwhelmed. Focus on one small aspect at a time, it will eventually all come together. The entire concept of filter and action hooks is very important for modifying how WP works to meet specific needs. It’s well worth the time spent to fully grasp how they work. You may think that once you have song queries working, your coding is done. That has not been my experience. Once I found out how WP can be customized, it was hard to stop tweaking things to my liking 🙂

    Ok I’ll give it a try! That makes more sense that it is a whole other page. So will it be like an archive page? What page template would you suggest starting with to customize and insert this query?

    Moderator bcworkz

    (@bcworkz)

    Any one of several schemes can work when coded correctly. The single song page could have a list of related songs. A separate page can list the related songs. The normal listing of all songs can be filtered to only return related songs. I started out suggesting a separate page based on a custom page template, but then thought better of it and suggested filtering the normal listing. So staying with this latest concept, yes, it’s exactly like an archive page. Depending on your theme, it’s quite likely that archive.php will be the template used.

    To some extent, it doesn’t matter what template is used, WP decides what to use based on the query. You don’t need to edit any template to alter the query. You’ll be altering the query before code even gets to the template stage.

    I’m assuming your songs are stored as a custom post type “music”, so a listing of all songs is had by requesting something like example.com/music/. The list is then displayed by your theme’s archive.php template. By using the “pre_get_posts” action, you can filter the music query by adding URL parameters such as example.com/music/?min=110&max=130&time=4/4. The archive.php template is still used, but now the list of songs will be much shorter.

    The code to filter the music query goes on functions.php, not on any template. I think this is the best approach because only one query is needed since you are altering the query before it’s run. In the other schemes, one query is run to get the page, then a custom query on the page is run to get the music. By using “pre_get_posts” action, no templates need to be edited, so the required code could be accomplished as a plugin if you wanted to. This can be useful for framework based themes that take up the one child theme allotment, leaving only plugins for your own custom code.

    But if you prefer to do a custom query right on a template, that will work too. To stay with filtering the music query scheme, all you need to know to do this was linked to in my previous post.

Viewing 8 replies - 1 through 8 (of 8 total)
  • The topic ‘How do I create a numerical range for a link on to a custom taxonomy?’ is closed to new replies.