$10
WordPress: Custom rewrite rules
I'm trying to create custom rewrite rules for some Custom Post Types that I'm using on a site. The site is multilingual so each CPT require a language setting in order to be displayed correctly when browsing the site (I chose not to create two individual posts in order to save time for the client when publishing - the posts have lots of options).
The goal is to make the following rewrites:
fastigheter-spanien/X -> property/X&lang=sv
fastigheter-usa/X -> property/X&lang=sv
properties-spain/X -> property/X&lang=en
properties-usa/X -> property/X&lang=en
Where X is the slug for the CPT. Basically I just want to add a language setting and hide the ugly "property" in the url, either by modifying .htaccess or adding rewrite rules in functions.php. I've tried both on my own but just can't manage to solve it.
Thanks in advance.
WordPress version 3.0
Staffan Estberg | 07/31/10 at 12:19pm
| Edit
(4) Possible Answers Submitted...
-

Last edited:
07/31/10
12:30pmDeepak Thomas says:Try adding this to the top of your .htaccess
<IfModule mod_rewrite.c>
RewriteRule ^fastigheter-spanien/([^\&]+) property/$1&lang=sv [NC,L]
RewriteRule ^fastigheter-usa/([^\&]+) property/$1&lang=sv [NC,L]
RewriteRule ^properties-spain/([^\&]+) property/$1&lang=en [NC,L]
RewriteRule ^properties-usa/([^\&]+) property/$1&lang=en [NC,L]
</IfModule>Previous versions of this answer: 07/31/10 at 12:27pm | 07/31/10 at 12:30pm
- 07/31/10 12:32pm
Staffan Estberg says:You mean before the # BEGIN WordPress? That didn't work. I also tried including the rules within WordPress' IfModule but it didn't help.
- 07/31/10 12:35pm
Deepak Thomas says:I'd edited the code after posting it. Did you try the one that's presently visible?
RewriteRule ^fastigheter-spanien/([^\&]+) property/$1&lang=sv [NC,L]
RewriteRule ^fastigheter-usa/([^\&]+) property/$1&lang=sv [NC,L]
RewriteRule ^properties-spain/([^\&]+) property/$1&lang=en [NC,L]
RewriteRule ^properties-usa/([^\&]+) property/$1&lang=en [NC,L]
- 07/31/10 12:39pm
Staffan Estberg says:Yes, but where exactly should I put it?
- 07/31/10 12:32pm
-

Last edited:
07/31/10
12:43pmRashad Aliyev says:For advanced ReWrite rules you can use this plugin.
http://wordpress.org/extend/plugins/wp-htaccess-control/screenshots/- 07/31/10 3:07pm
Staffan Estberg says:I'd rather not use a plug-in for such a small change. But thanks for the tip.
- 07/31/10 3:07pm
-

Last edited:
07/31/10
2:21pmNaif Amoodi says:You don't need to edit the .htaccess file for this. You can do it using the API provided by WordPress. The following should basically do what you are after. Add to following to your functions.php file and make appropriate modifications because I have only used the details that were provided:
add_action('init', 'your_init');
add_filter('rewrite_rules_array', 'your_rewrite_rules_array');
add_filter('query_vars', 'your_query_vars');
function your_init() {
global $wp_rewrite;
$wp_rewrite->flush_rules();
}
function your_rewrite_rules_array($rewrite_rules) {
global $wp_rewrite;
$custom['(fastigheter-spanien)/(.+)/?$'] = 'index.php?property=$matches[2]&language=sv';
$custom['(fastigheter-usa)/(.+)/?$'] = 'index.php?property=$matches[2]&language=sv';
$custom['(properties-spain)/(.+)/?$'] = 'index.php?property=$matches[2]&language=en';
$custom['(properties-usa)/(.+)/?$'] = 'index.php?property=$matches[2]&language=en';
return $custom + $rewrite_rules;
}
function your_query_vars($query) {
array_push($query, 'language');
return $query;
}
After making the changes, make sure you visit the permalinks section in the WordPress administration panel so that the rewrite flush can take effect. And once you are able to get things to work, comment out the line
because you don't want your rewrite rules getting flushed every time the site is accessed.add_action('init', 'your_init');- 07/31/10 2:37pm
Staffan Estberg says:Nice! I think the actual rewrite is working but it shows the "property" url. I'd like to keep the "properties-spain" (or one of the others) url.
- 07/31/10 2:49pm
Naif Amoodi says:It probably isn't working then. If you try accessing the URL, /fastigheter-spanien/somename/, WP shouldn't perform a redirect. The URL should stay intact. Try doing the following one at a time. And once you perform every step, make sure to access the permalinks page from the admin panel to make sure WP registers the rewrite changes.
1. Try replacing
witharray_push($query, 'language');array_push($query, 'property', 'language');
2. If that doesn't help, try removing references to /?
Remember not to comment out the line I asked you to until what you are trying to do works. Everytime you make a change, that line needs to be called and you need to access the permalinks section from the administration panel. - 07/31/10 3:01pm
Staffan Estberg says:Sorry but it still doesn't work. This is driving me nuts.
- 07/31/10 3:59pm
Naif Amoodi says:Lets try removing canonical urls. Add the following to your functions.php file:
if(!empty(get_query_var('language'))) remove_action('template_redirect', 'redirect_canonical');
I believe that should do the trick. The conditional statement there checks if it's our 'custom url'. And no need of using array_push($query, 'property', 'language'); if array_push($query, 'language'); works
- 07/31/10 2:37pm
-

Last edited:
07/31/10
6:54pmMike Schinkel says:@Staffan: You can use mod_rewrite/.htaccess if you want but I prefer to keep things within WordPress if possible. I put the full code you would drop into your theme's functions.php file here:
http://gist.github.com/502421
To explain, first step is to use an "init" hook is to run the following five lines of code. The 2nd and 3rd lines of code add "lang" both as a query var and a rewrite tag so that WordPress is aware of it and can process it. Then next two lines tell WordPress about your two new URL formats (this code assumes your "property" post type has been set and has a query_var of "property":
global $wp,$wp_rewrite;
$wp->add_query_var('lang');
$wp_rewrite->add_rewrite_tag('%lang%','([^/]+)','lang=');
$wp_rewrite->add_permastruct('fastigheter', 'fastigheter-%lang%/%property%');
$wp_rewrite->add_permastruct('properties', 'properties-%lang%/%property%');
After this you'll need to run the following line of code, but you need only do it once otherwise it will make your pages load slow:
$wp_rewrite->flush_rules(false);
An alternate to running flush_rules() then commenting it out would be to just update your permalinks once after adding the six lines above here:
http://example.com/wp-admin/options-permalink.php
(replace example.com with your domain)
Next you need to snag the value of "lang" which will come in as "spanien", "spain" or "usa" and convert it to "sv", "sv" or "en", respectively using a "request" hook:
add_filter('request', 'my_request');
function my_request($request) {
if (isset($request['lang']))
switch ($request['lang']) {
case 'spanien':
case 'spain':
$request['lang'] = 'sv';
break;
case 'usa':
default:
$request['lang'] = 'en';
}
return $request;
}
Finally I added the function get_property_lang() to make it easy to grab the value of "lang" in your theme or plugin. Since this "lang" query var is not actually a real query var from the perspective of the web server you won't see it in $_GET['lang'] but instead in $wp_query->query_vars['lang']. (I could have stuffed in into $_GET but that's not a great idea as some plugins may expect it to be what came in the URL from the browser. Besides, the better WordPress devs use "query_vars" anyway):
function get_property_lang() {
global $wp_query;
return (isset($wp_query->query_vars['lang']) ? $wp_query->query_vars['lang'] : '');
}
Hope this helps, let me know.
P.S. VERY IMPORTANT: The first time try this it won't work because the rewrite rules won't be active yet. If it doesn't appear to work be sure the rules are flushed by saving your permalinks or running the flush_rules() again.Previous versions of this answer: 07/31/10 at 4:00pm | 07/31/10 at 4:02pm | 07/31/10 at 4:04pm | 07/31/10 at 4:05pm
- 07/31/10 4:19pm
Staffan Estberg says:Wow, thank you for that detailed answer! I'm beginning to feel embarrassed for tossing out a lousy $10 for all the help I've received.
Something's fishy because it's not working. The way I interpret your code it has to. I don't know if it takes time for the rewrite rules to become active but I've tried updating the permalinks several times as well as running the flush included in the functions. Still get to "property/x" when trying to use one of the language urls. - 07/31/10 4:23pm
Mike Schinkel says:Are you saying you the code I provided does a redirect back to the /property/%property% url, or that it doesn't work at all.
Have you made sure to clear out all the code the other people provided; it might cause conflicts. - 07/31/10 4:30pm
Staffan Estberg says:Well I'm not sure whether it's working (and doing a redirect back, which would be weird) or not. I only use your code at the moment, and I've double checked in the .htaccess where I made some changes earlier.
- 07/31/10 4:33pm
Staffan Estberg says:Note that I'm using WPML, if this could affect rewrites in any way.
- 07/31/10 4:40pm
Mike Schinkel says:I have no idea if WPML affects it. Can you disable to set what it does?
- 07/31/10 4:40pm
Mike Schinkel says:Also, are you on Windows? Mac? Other?
- 07/31/10 4:45pm
Mike Schinkel says:I just installed WPML and added Spanish, and it seems to work.
- 07/31/10 4:46pm
Staffan Estberg says:Mac. Using Firefox and Chrome. Could check with Safari but it shouldn't be a browser issue.
- 07/31/10 4:46pm
Mike Schinkel says:Where did you put my code? In functions.php? Can you post your file to a gist so I can see it?
- 07/31/10 4:49pm
Mike Schinkel says:@Steffan: On Mac there is unfortunately no good free HTTP sniffer, but you can get a 14 day trial of HTTPScoop. It will let you see what is going on at the HTTP level (on Windows there is the excellent and free Fiddler.)
- 07/31/10 4:51pm
Staffan Estberg says:http://gist.github.com/502599
I created my theme based on Twentyten and have not removed any of the functions from that theme. But I've looked through that code and there are no rewrites or any other possible conflicts that I can see. - 07/31/10 5:04pm
Mike Schinkel says:Awesome, I'm testing on TwentyTen. I took your functions.php verbatim and used it instead of mine and everything still works. Let's walk through it. I created a "property" called "Test" and I can load it with any of these URLs (replace "example.com" with your domain):
http://example.com/fastigheter-spanien/test/
http://example.com/fastigheter-usa/test/
http://example.com/properties-spain/test/
http://example.com/properties-usa/test/
http://example.com/property/test/
I've created a theme file "single-property.php" which is just a copy of "single.php" and I've added the following like just below the "<div id="content" role="main">":
<font size="7">[<?php echo get_property_lang(); ?>]</font>
When I use one of the first four URLs is displays them as I expected.
BTW, you don't need to duplicate the call to "register_post_type('property',...)" that I added so that I could test it since you already have it.
So, when you try those first 4 URLs do they redirect to the 5th or give you page not found?
What other plugins are you using? - 07/31/10 5:17pm
Staffan Estberg says:Thanks for looking into that. I tried your test urls and I end up with a 404, which sounds better to me then an "ignored" redirect.
As for other plug-ins, the only one besides WPML is Simple Fields, a little admin manager for adding custom fields to custom post types. - 07/31/10 5:40pm
Mike Schinkel says:So I added Simple Fields and it is still working perfectly for me.
Is your site online where I can see it not working? (maybe I can discover something from seeing it.) - 07/31/10 5:43pm
Staffan Estberg says:Check your messages, I sent you the URL there.
- 07/31/10 6:17pm
Mike Schinkel says:Let's try a different approach. Try this functions.php instead:
http://gist.github.com/502677
Note the code below includes killing the "my_request" function I previously provided you as well as it's add_filter() call and adding this new hook:
add_action('icl_set_current_language', 'my_icl_set_current_language');
function my_icl_set_current_language($lang) {
$selector = preg_replace('#^(.+)-(spanien|spain|usa)/(.*)$#','$2',$_SERVER['REQUEST_URI']);
switch ($selector) {
case 'spanien':
case 'spain':
$lang = 'sv';
break;
case 'usa':
$lang = 'en';
break;
}
return $lang;
}
Let me know if is works. - 07/31/10 6:35pm
Mike Schinkel says:Ugh! This is looking like it is a problem with WPML. At first glance at least, they've made some code decisions that are not so good. They have a hook called 'icl_set_current_language' which looks like what you need to call but you can only call it from a plugin because it is itself called from the 'plugins_loaded' hook. Seesh!
Let's go offline to discuss since you've already sent me a direct message about it.
- 07/31/10 4:19pm
This question has expired.
Current status of this question: Completed




