I've got two WordPress Taxonomies registered, vehicle-manufacturer and vehicle-model on a post type of vehicle.
Let's say I've created audi and e-tron as two terms.
The default archive url for e-tron will be http://example.com/vehicle-model/e-tron. What I want is this url to be rewritten to http://example.com/audi/e-tron, with an ACF Custom field to select the vehicle-manufacturer, in this case audi.
I've already written the filter to change this url when getting the term link, which works fine.
function ac_modify_vehicle_model_term_link( $link, $term, $taxonomy ) {
if ( $taxonomy !== 'vehicle-model' ) {
return $link;
}
$manufacturer_term = get_field('vehicle_parent_manufacturer', $term);
$new_link = home_url() . '/vehicle-model/' . $manufacturer_term->slug . '/' . $term->slug . '/';
return $new_link;
}
add_filter( 'term_link', 'ac_modify_vehicle_model_term_link', 10, 3 );
The issue comes with the rewrite, I've created a rewrite rule as follows:
function add_custom_rewrite_rule() {
add_rewrite_rule(
'^([^/]+)/([^/]+)/?',
'index.php?vehicle-model=$matches[2]',
'top'
);
}
add_action('add_custom_rewrite_rule', 'init');
This regex just checks the url is in /[value-1]/[value-2] format and then passes value-2 as the vehicle-model query parameter, which works as I'd like when going to http://example.com/audi/e-tron. The issue comes from the fact that this rewrite matches for every page whether or not either audi or e-tron matches a valid Taxonomy.
So for instance
http://example.com/whatever/e-tron brings back e-tron archive page.
http://example.com/vehicle/audi-e-tron-001 - is broken (due to matching)
I want to know if I can check that both the first part of the string [value-1] is a valid term for vehicle-manufacturer and [value-2] is a valid vehicle-model term, that way only valid pages will rewrite as expected.
I've already tried wrapping the rewrite rule in various checks, as well as various filters and actions to try and manipulate the query vars for specific terms but to not avail. I'm also aware that I could use one taxonomy and use the built in hierarchy structure to help with this, but I need to go down this route for other reasons.
Related
I'm trying to integrate a Query Expansion software with Wordpress, but the wordpress search engine is an AND searcher (returns those contents that contain all the words in your query, and therefore the more extensive is the query the fewer results returns).
For that reason when i use the query with the expansion features, the Searcher returns me less results.
I would like to modify the Search's behavior, and turn it into something more like an OR searcher.
Example:
For the query " iot, internet of things", I would want those posts which contents "iot", or "internet of things, or both of them.
I've reading through this document (https://codex.wordpress.org/Class_Reference/WP_Query) and i tried to use something like this:
add_action( 'template_redirect', 'hooks_setup' , 20 );
function hooks_setup() {
if (! is_home() ) //<= you can also use any conditional tag here
return;
add_action( '__before_loop' , 'set_my_query' );
add_action( '__after_loop' , 'set_my_query', 100 );
}
function set_my_query() {
global $wp_query, $wp_the_query;
switch ( current_filter() ) {
case '__before_loop':
//replace the current query by a custom query
//Note : the initial query is stored in another global named $wp_the_query
$wp_query = new WP_Query( array(
'post_type' => 'post',
'post_status' => 'publish',
//others parameters...
) );
break;
default:
//back to the initial WP query stored in $wp_the_query
$wp_query = $wp_the_query;
break;
}
}
But I don't know which parameters i need to set in wp_query. How can I achieve this?
To answer what parameters you need to set, you have to read through the same page you mentioned. Parameters for various items (post types or categories) are defined on this page and when you want to change it all you have to do is modify the parameters.
If you dont know what query you want to do I think its hard for people to help. If you are getting less results, you can open query a bit further or obtain results in 2 queries. Read through the page and you will find its common when people want to obtain different types of data and not everything is in the loop.
Also read through this to understand more about the loop and how to reset the query and do a new one then you can obtain two result sets and use them or combine them when and where you want.
Just to give you an example for string search in posts with s as parameter from the same page Prepending a term with a hyphen will exclude posts matching that term. Eg, 'pillow -sofa' will return posts containing 'pillow' but not 'sofa' (available since Version 4.4).
I have a WordPress site hosted on an Azure App Service (not a dedicated VM) and I need people to access the front page via a URL like: http://www.example.com/?tracking.id=12345
However, WordPress is re-writing the URL by replacing the dot in tracking.id with an underscore: http://www.example.com/?tracking_id=12345
How can I prevent WordPress from doing this?
what's interesting is that this only happens on the home page, query vars stay intact everywhere else. you might be able to figure out what's going on if you take a look at wp-includes/canonical.php (that's also where the redirect_canonical filter is located)
function prevent_underscores( $redirect_url, $requested_url ) {
if( isset( $_GET['tracking_id'] ) ) {
return $requested_url;
}
return $redirect_url;
}
add_filter( 'redirect_canonical', 'prevent_underscores', 10, 2 );
You may check whether you have chosen and set the permalinks_type in the setting tab of your WordPress site. You can refer to https://codex.wordpress.org/Using_Permalinks for details.
Moreover, you can leverage the 3rd part Wordpress Plugin, refer to https://wordpress.org/plugins/custom-permalinks/.
#vidja is very close and definitely on the right track with redirect_canonical.
I dug into this issue a bit further myself to figure out that this is a combination of issues between both PHP itself and this redirect logic in WordPress. If you have a look at the php global $_GET directly, you'll find that is where the query string params are being parsed "incorrectly". For instance:
// For a url like: /some/path/?tracking.id=123
var_dump($_GET);
// array(1) { ["tracking_id"]=> string(3) "123" }
If you continue to dig through the redirect_canonical code you'll eventually find the culprit to be a stack of function calls, ending with php's parse_str method:
// https://developer.wordpress.org/reference/functions/_remove_qs_args_if_not_in_url/
_remove_qs_args_if_not_in_url()
// https://developer.wordpress.org/reference/functions/remove_query_arg/
remove_query_arg()
// https://developer.wordpress.org/reference/functions/add_query_arg/
add_query_arg()
// https://developer.wordpress.org/reference/functions/wp_parse_str/
wp_parse_str()
// https://www.php.net/manual/en/function.parse-str.php
parse_str()
Testing out parse_str directly gives you the same result as looking at $_GET:
$arr = [];
parse_str('tracking.id=123', $arr);
var_dump( $arr );
// array(1) { ["tracking_id"]=> string(3) "123" }
All this to say that there is a slightly better way to setup your own filter so that you get a more robust result. For instance, the way that #vidja wrote his filter would result in pages not being properly redirected when you'd want them to be (and as a result, WordPress showing a 404 not found page). Say you had a page with a slug of /sample-page and you tried visiting your site through a url like: /sampl?tracking.id=123. Wordpress would want to redirect that to /sample-page/?tracking_id=123, but #vidja's code would instead return the original (bad) url since tracking_id is set in $_GET. So, a better way to handle this, in my opinion, would be to replace the specific query string param you care about inside the redirect url, that way Wordpress can do it's thing to redirect pages as it see's fit, but you can also maintain your tracking.id properly. Here is what that would look like:
add_filter( 'redirect_canonical', function ( $redirect_url, $requested_url ) {
return preg_replace( '/tracking_id=/', 'tracking.id=', $redirect_url );
}, 10, 2 );
You could even do something like the following if you had multiple query string parameters with period's that you needed to maintain:
add_filter( 'redirect_canonical', function ( $redirect_url, $requested_url ) {
$query_params = [
'tracking_id' => 'tracking.id',
'foo_bar' => 'foo.bar',
];
foreach ( $query_params as $search => $replace ) {
$redirect_url = preg_replace( '/'.$search.'=/', $replace.'=', $redirect_url );
}
return $redirect_url;
}, 10, 2 );
This is my first post here, so I apologize in advance for any mishaps.
I've been searching for hours trying to figure this one out, but I simply can't seem to understand why this is happening.
The site I'm setting up is a child site (not in a multisite sense, but as a separate site/domain with the same branding). Some of the posts on my site will originate from the parent/main site (but will be made as new posts through copy-paste), and I want the original article ID as part of the permalinks.
E.g. http://www.example.com/hello-world/12345/, where 12345 is the article ID of the article on the parent/main site.
To accomplish this, I've added a custom field to my posts where I can add the article ID of the original article with external_article_id as Field Name. I've then tried to manipulate the permalinks with the following code:
add_filter('post_link', 'append_custom_permalink', 10, 2);
function append_custom_permalink($url, $post) {
$newurl = $url;
if ($post->post_type == 'post') {
$custom = get_post_custom_values('external_article_id', $post->ID);
if (!empty($custom))
$newurl = $url . $custom[0] . '/';
}
return $newurl;
}
Whenever I output the permalink to the posts it appears exactly as I want it, both in the editor and on the site. However, when I either click a link or enter the address manually, I get redirected automatically to http://www.example.com/hello-world/12345/12345/. It duplicates the additional numerical slug, and also happens when I replace $custom[0] with a hard-coded numeric value. This applies to all posts, and my permalink structure (in the settings) is set to /%postname%/.
I even tried setting the permalink structure to /%postname%/%ext_article_id%/ and replace %ext_article_id% with $custom[0], but with the exact same outcome. I also tried using the same code on another WordPress site, except this time with pages instead of posts, also with the exact same outcome.
Ideally I would like to use something like add_query_arg($custom[0], '', get_permalink($post->ID));, but omit the question mark that comes along with it.
Could someone please explain to me why this is happening, and how I can circumvent this? Do I need to use some other filter, or how can I approach this?
Thank you in advance!
In order to make this work you also need to make WordPress aware of the rewrite_tag and specify an additional permalink structure via add_permastruct. The following code should do the trick:
function append_custom_permalink( $post_link, $post ) {
if( $post->post_type == 'post' ) {
$custom = get_post_custom_values( 'external_article_id', $post->ID );
if( ! empty($custom) ) {
$post_link = $post_link.$custom[0].'/';
}
}
return $post_link;
}
add_filter('post_link', 'append_custom_permalink', 10, 2);
function sof_30058470_posts_rewrite() {
add_rewrite_tag('%external_article_id%', '([^/]+)', 'external_article_id=');
add_permastruct('external_article_id', '/%year%/%monthnum%/%day%/%postname%/%external_article_id%/', false);
}
add_action('init', 'sof_30058470_posts_rewrite', 10, 0);
Make sure to re-save your permalink structure at Settings->Permalinks once you added the code. You may also need to refresh/clear your browser cache.
I have a WordPress site that has a standard Page called Places with URL
example.com/places/
And I have several child Pages called by cities
example.com/places/city-1
example.com/places/city-2
Now, I have a custom post type Place that should indicate a single place and should have permalink like
example.com/places/place-1
But then if I go to one of the previous links with city-1, city-2 I get 404 obviously because there is no place with that permalink.
Is there a way for WordPress to drop to previous permalink. So if there is no place with that name, look for a page with it.
You could probably use the the REFERER-value from the PHP server variable $_SERVER, but it´s not very reliable and can be altered.
I am using the plugin "Permalink Finder" in one of the pages I am maintaining and that works quite well for finding changed URL. You could give it a try and see if it works for you, too.
In case somebody ever having a similar problem, it can be done by using verbose page rules. This is an example I found at WordPress Stack Exchange
https://wordpress.stackexchange.com/questions/22438/how-to-make-pages-slug-have-priority-over-any-other-taxonomies-like-custom-post
add_action( 'init', 'wpse16902_init' );
function wpse16902_init() {
$GLOBALS['wp_rewrite']->use_verbose_page_rules = true;
}
add_filter( 'page_rewrite_rules', 'wpse16902_collect_page_rewrite_rules' );
function wpse16902_collect_page_rewrite_rules( $page_rewrite_rules )
{
$GLOBALS['wpse16902_page_rewrite_rules'] = $page_rewrite_rules;
return array();
}
add_filter( 'rewrite_rules_array', 'wspe16902_prepend_page_rewrite_rules' );
function wspe16902_prepend_page_rewrite_rules( $rewrite_rules )
{
return $GLOBALS['wpse16902_page_rewrite_rules'] + $rewrite_rules;
}
I am a bit confused about how WordPress's permalink works, especially beyond Wordpress's own usage. My permalinks are like:
%post_id%-%post_name%
But in single.php I want to put another link to page itself but with different query string. When it is clicked the permalink structure may look like:
%mystring%-%post_id%-%post_name%
I want to get the value from $_GET['action'], so:
$_GET['action'] = %mystring%
my plan is to interpret it like:
if('xx' == $_GET['action']){
//do xx stuff
} else if ('yy'==$_GET['action']){
//do yy stuff
} else {
//show the single post as a single.php always shows
}
that means, I want to parse the $_GET['action'] optionally. If I do not parse it even if it is available in query string, I want the page to be rendered correctly.
So to get this done, where should I actually work? Also how do I form the link for <a> tag? Usually we make link this way:
TEXT
but you already know, I need to add some text before the original permalink of post.
Thanks in advance.
Leave your permalink structure as it was and check out my answer on custom rewrite rules.
You could adapt the code like so;
function my_rewrite_rules($rules)
{
global $wp_rewrite;
// the key is a regular expression
// the value maps matches into a query string
$my_rule = array(
'(.+)/(.+)/?$' => 'index.php?pagename=matches[2]&my_action=$matches[1]'
);
return array_merge($my_rule, $rules);
}
add_filter('page_rewrite_rules', 'my_rewrite_rules');
function my_query_vars($vars)
{
// this value should match the rewrite rule query paramter above
// I recommend using something more unique than 'action', as you
// could collide with other plugins or WordPress core
$my_vars = array('my_action');
return array_merge($my_vars, $vars);
}
add_filter('query_vars', 'my_query_vars');
Now the page my_page should be available at http://example.com/whatever/my_page and http://example.com/my_page.
You can get the value of whatever using get_query_var('my_action').
Disclaimer
This may have undesired effects when viewing children pages or page attachments. You could get around this by passing an identifier in your rewrite, something to the effect of;
http://example.com/my_identifier/whatever/page
Note: You will need to edit the rewrite rule if you wish to do this. Every time you make changes to the code you will need to re-save your permalink structure to 'flush' the rules.