Wordpress URL Routing, Multiple permalinks with different templates - php

This question is based on an unanswered question in Wordpress Development which has not gotten a solid answer.
I have a wordpress website which lists hotels. the url for a single hotel looks like:
/hotels/the-marriot-hotel
I also have a custom taxonomy for Locations, which allows me to browse the hotels in various locations, which works fine, the urls are like:
/Locations/Liverpool
For URL's like /hotels/* I would like to use a custom template, which I have done already and works fine.
The Problem
I also want to be able to drilldown the Locations taxonomy creating a breadcrumb type URL and also use a different template for the hotel page.
For Example, if a user is browsing /Locations/Liverpool and clicks the Marriot Hotel I would like it to click through to /Locations/Liverpool/the-marriot-hotel instead of /hotels/the-marriot-hotel and also use a slightly different template, which can also load a different sidebar and recommend other hotels in the area specific to the location slug in the URL
So basically I want two routes to a single post and a different template used based on the route used.
How would I go about implementing this?
What have I tried?
I've tried adding a new page and using a rewrite rule to point to it to be the locations hotel page.
I've tried adding a slug on the end of the /Locations/{location-slug} url and reading this in the page template and loading the hotel post instead of the list it doesn't seem to be working but also feels like a terrible hack anyway
An idea that I've had is to add a rewrite to the hotels/{slug} page and using code to detect the URL used and switch templates dynamically but I'm not sure this is the best approach

I have managed to get this working using the second method mentioned above (adding a rewrite to the locations landing page and checking for a query_var).
I will post the code below that I used but although this works and seems to be working very well, It does not feel like the best way of doing it. If someone know of a better way of doing this please post the answer.
I used this online post for reference.
Note: The listing page shows the list of hotels in the taxonomy in a side column down the side and shows the currently selected or a random one in the main content area. Which will explain how I am using the loop below.
function prefix_locations_rewrite_rule() {
add_rewrite_rule( 'Locations/([^/]+)/([^/]+)', 'index.php?locations=$matches[1]&hotel=$matches[2]', 'top' );
}
function prefix_register_query_var( $vars ) {
$vars[] = 'hotel';
return $vars;
}
function prefix_url_rewrite_templates() {
if ( get_query_var( 'hotel' ) && is_singular( 'hotel' ) ) {
add_filter( 'template_include', function() {
return get_template_directory() . '/taxonomy-locations.php';
});
}
}
add_action( 'template_redirect', 'prefix_url_rewrite_templates' );
add_filter( 'query_vars', 'prefix_register_query_var' );
add_action( 'init', 'prefix_locations_rewrite_rule' );
In my template file for the hotels landing page:
$hotelSlug = get_query_var( 'hotel', false);
if ( have_posts() ) {
while (have_posts()) : the_post();
if ($post->post_name == $hotelSlug) {
break;
}
endwhile;
}
This bit of code will iterate over the posts and if the hotel slug matches the query var it will break there so that the current post is the one we wanted.
We could just use a query here but as I already have a list of posts within the taxonomy I thought I'd just iterate over it. Below this I check to see if a specific hotel has been selected otherwise I show a random one from the list.
I am still to add additional logic and error handling to this code, I hope it helps someone with a similar issue

Related

Sort posts alphabetically on a specific page in Wordpress

EDIT: Found my old code, that worked, and got it fixed that way. Also gonna use a plugin to add custom functions, to avoid it dissaperaing again with next theme update (Thanks Heba). And the code:
function foo_modify_query_order( $query ) {
if (get_the_ID()==80) { $query->set( 'orderby', 'title' ); $query->set( 'order', 'ASC' ); } } add_action( 'pre_get_posts', 'foo_modify_query_order' );
So, it should be a simple task, but I have no idea why it's not working by now. I have tried everything, every Google link is purple, so now I hope someone can tell me what it is, I'm doing wrong.
I should start by mentioning that it's a Divi theme, but I did get it to work a few months ago, but forgot how, and I can't recreate it now.
I'm just trying to sort the main query alphabetically (A-Z), but only on a page called recipes. The site have all the recipes as posts, together with their blog posts, but the blog posts are sorted by date and showed on a separate page, which works fine.
But weird stuff are happening, when I try and alter it. If I use this code, it actually works, but the blog page also get sorted alphabetically, which it shouldn't.
function foo_modify_query_order( $query ) {
if (is_archive()) {
$query->set( 'orderby', 'title' );
$query->set( 'order', 'ASC' );
}
}
add_action( 'pre_get_posts', 'foo_modify_query_order' );
Which doesn't make sense to me, since it's posts? Out of all the ways I've tried, it only sorts if I use is_archive().
If I try to make it check for a specific page first, like && is_page('recipes') I get an error.
If I just add if (is_page('recipes')){ echo 'Recipes'; } it works, but if I try to add the sorting inside, I get nothing.
So partially working, but I can't combine the two. Is it a Divi issue or am I doing it wrong? Hope anyone can help, I've tried so many different things now. Cheers :)
I would recommend creating a child theme where you will create a new page template to be used in the 'recipes' page.
First, use Child Theme Configurator plugin to set a new child theme, don't forget to select Copy Menus, Widgets and other Customizer Settings from the Parent Theme to the Child Theme option to keep your settings:
After that, from files tab in the child theme configurator, copy the page template used for blog (or the page template used in 'recipes' page).
After that, change the file name, and the name written in the top of the page template file after Template Name, to recipes ordered alphabetically or any name you would prefer like next:
/*
* Template Name: recipes ordered alphabetically
*/
You can add these args to the query:
$args['orderby'] = 'title';
$args['order'] = 'ASC';
And change 'recipes' page template to the new created one.
For more detailed answer, Please insert the code used in the page template.

Archive.php Category.php or Taxonomy.php - Which is correct for my situation?

I'm using Genesis framework and I have this page (http://staging.seedcreativeacademy.co.uk/short-courses/) showing the categories of my custom post type short_courses. I have changed the category name to course_type, by creating a new custom taxonomy.
This is how I want it to work so far (styling needs sorting out admittedly!) Im also using CPT UI plugin.
Now, when I click through to a category, is displays each 'Course in a nice masonry block as you will see here: http://staging.seedcreativeacademy.co.uk/course_type/digital-marketing/
However, I dont want this pages to look like this and I've tried adding custom template for the following:
Archive-short_courses.php & taxonomy-short_courses.php
Archive-course_type.php & taxonomy-course_type.php
But it doesnt seem to alter the layout at all...
Once I pass this hurdle I will want to alter the single.php page for these short courses, but I thought I would start with this first.
Im not sure if genesis blocks this and sets a site wide default? I know if sets a site wide default for the archive settings but I cant find anything about a template, plus i dont know if I shoujld be searching for tutorials on archive.php pages, category.php pager or taxonomy.php pages...
Can someone help me clarify things please?
course_type is a term name, not taxonomy name.
So, these are correct for your case:
category-course_type.php (category-{slug}.php is correct format. So check if course_type is correct slug of that category)
single-short_courses.php
Just in case, try reload permalinks via Settings->permalinks->save after making these changes.
Looks like your theme or some plugin is adding masnory class to body tag, which then is styled by your child theme. You need to filter that class out of your body tag and then might styling goes to non-masonary styling.
Add following code to your taxonomy-course_type.php file, and also make sure you have genesis(); call as the last thing in the template.
add_filter('body_class', 'remove_body_class', 20, 2);
function remove_body_class($wp_classes)
{
foreach($wp_classes as $key => $value)
{
if ($value == 'masonry') unset($wp_classes[$key]);
}
return $wp_classes;
}
Above could should be in custom taxonomy template, which also have genesis(); as last line.

wordpress functions.php - use different page template for each post category

I want to hook into the save_post function, find out what category the post is in, and then assign a different page template for posts in each category. I've tried about 30 different versions of this with no luck. Will someone please help point me in the right direction?
add_action( 'save_post', 'assign_custom_template' );
function assign_custom_template($post_id) {
$category = get_the_category($post_id);
$cat_id = $category->cat_ID;
if( $cat_id == 1 ) {
update_post_meta($post_id, "_wp_page_template", "template1.php");
}
if( $cat_id == 2 ) {
update_post_meta($post_id, "_wp_page_template", "template2.php");
}
}
You just need to create category-1.php which rendered as template1.php and category-2.php which rendered as template2.php in your theme root.
See template hierarchy for more info.
I tried to emulate the official WP hierarchy scheme among my posts & custom post types, but it just wasn't happening. I ended up using Custom Post Types so that I could assign templates to both the "list" pages and the "individual" pages. And then I wrote some javascript that looks for the post-type string in the URL, and if it's detected, it adds the current_page_parent/ancestor classes to the appropriate menu items. Not perfect or totally future-proof, but it gets the job done.
If someone comes up with a better solution, please post it!

Wordpress Rewrite URL from API NOT the database

I am building a site using WP and the Prosperent API. I have built out product category pages where the user can see all the "Backpacks" and even sub categories. I now want to build product detail pages. Because the data comes from an API, and not stored in my database I don't have an easy want to have pretty links.
On the category pages, I am linking each product like this:
$pageLink = esc_url( add_query_arg( array (
'gearID' => $value['catalogId'],
'gearTitle' => $value['keyword']
),
'http://www.example.com/products/g/' ) );
Which looks like this:
http://www.example.com/products/g/?gearID=65198586171ee0ea97f3e39935468f4d&gearTitle=The%20North%20Face%20Inferno%20Sleeping%20Bag:%20-20%20Degree%20Down%20Asphalt%20Grey/Caution%20Orange,%20Long
I AM Successfully capturing the "gearID" & gearTitle query variables, This allows me to display the product on the product detail page template. This is working great. But the URL has my query strings in it.
I have tried several different variations, but this is my code for the rewrite:
add_filter( 'query_vars', 'add_query_vars_filter' )
function custom_rewrite_basic() {
$gearID = get_query_var( 'gearID', false );
add_rewrite_rule('^products/g/([0-9]+)/?', 'index.php/products/g/?gearID=$matches[1]', 'top');
flush_rewrite_rules();
}
add_action('init', 'custom_rewrite_basic');
You can see in the code I have a get_query_var for the gearID, I attempted to insert where $match[1] is placed and didn't work. Perhaps I need to store data in DB so WP knows what to rewrite? Can't do it on the fly?
Ultimately, I want it to look like this:
http://www.cascadegear.com/products/g/The%20North%20Face%20Inferno%20Sleeping%20Bag:%20-20%20Degree%20Down%20Asphalt%20Grey/Caution%20Orange,%20Lon

Remove author and date on some posts with conditional tag

I want to remove the Author and Date on posts assigned to a specific category for a site that I'm just started. I thought the following addition to my custom theme's function.PHP file would do the trick. The name of the category is "Funds" and for all other posts not assigned this category I want the Author and Date information to remain.
if (is_category('Funds')) {
remove_action('genesis_before_post_content', 'genesis_post_info');
}
This code appears to have no affect on the site, and all posts continue to have the author and date information appear.
Any ideas?
Try this but replace "Testimonials" with "Funds". Note I have also customised the return from the post info to not show authors etc for any post category. The below code will effectively remove the post date from any posts with the category "Testimonials" and all but post date from any other post category.
/** Customize the post info function */
add_filter( 'genesis_post_info', 'post_info_filter' );
function post_info_filter($post_info) {
if (!is_category('Testimonials')) {
$post_info = '[post_date]'; // removed by [post_author_posts_link] at [post_time] [post_comments] [post_edit]
return $post_info;
}}
The above code is placed in your child themes functions.php
If you put that code as-is into your theme's functions.php file it'll run too early; the "query" will not have run and thus WordPress won't yet know your category. You need to run your code from a hook that runs after the query.
Assuming that 'genesis_post_info' is in fact the hook you need then this code will probably work for you (I don't have Genesis to test to be sure.) And yes, you can put this code into your theme's functions.php file since it delays running the remove until after the_posts hook:
add_filter('init','yoursite_the_posts');
function yoursite_the_posts($posts) {// 'the_posts' runs immediately after the query
if ($wp_the_query === $wp_query && // If first query on a page load
is_category('Funds')) { // And if this is the Funds category
remove_action('genesis_before_post_content', 'genesis_post_info');
return $posts; // Gotta return the posts, they are expected
}
Let me know if this works or if not what problems you run into.
Better Alternate? Custom Post Types for your "Funds"
Have you considered using Custom Post Types for your Funds instead of shoehorning them into Posts? I'm guessing you'll get a lot better results if you do.
If you do use a Custom Post Type then these might help you theme them:
Create a Widget Area in the Navigation Bar for the Genesis Theme Framework?
Using Custom Templates for Custom Post Types with the Genesis Theme Framework?
Hope this helps.
-Mike
First the answers above helped me very much, but then I realized that the interpreation of the question might be a little off. So my answer is really the solution 'I' was looking for but depending on the original intent of the question might also be what Hamish was looking for as well.
The issue seems to be whether or not to remove the Author and date on posts "In a Category" as opposed to on posts listed in the archive listing of a category.
For example, I wanted (something slightly different) to remove just the date (not the author) but I wanted the date removed on the single post view of that post whenever it happened to be in a category called case studies. So I used
/** Customize the post info function */
add_filter( 'genesis_post_info', 'post_info_filter' );
function post_info_filter($post_info) {
if ( in_category('case-studies') ) {
$post_info = 'By [post_author] [post_edit]'; // removed by [post_author_posts_link] at [post_time] [post_comments] [post_edit]
return $post_info;
}
else {
$post_info = '[post_date] By [post_author] [post_edit]'; // removed by [post_author_posts_link] at [post_time] [post_comments] [post_edit]
return $post_info;
}
Note I'm using in_category not is_category :)
It might be possible that Hamish actually wants a hybrid where both the archive listing of all the posts on the category page do not display authors and dates AND the individual posts that happen to be in the category in question do not display the author and date.
In that case my code above would need to be more complex to handle both conditions.
Simple Edits Conflict
If you are running the Genesis Simple Edits plugin, that plugin will also trump (run) after the function above. I haven't yet figured out how/when to hook into this after Simple Edits myself.... (update For starters I simply commented out the post info section of this plugin for now, so that I could keep my post_meta and footers running via simple edits)
Oh and here is the Studio Press tutorial via Brian Gardner on this (little too simplistic for this situation but probably got Hamish started)
http://www.briangardner.com/code/customize-post-info/

Categories