I will post the entire plugin code below.. here is the problem that I am having with it. I am using the values that are imported to custom fields in a custom post type to construct the URLs. On the edit post page it shows the permalink as I wish it to be..




The permalink however is 404.. although if I remove the hyphens in the city name and search..


than the url works..

So I imagine the plugin is missing something with respects to fields with spaces.. strange that it shows properly in the permalink field within the post editor though.. any help will be much appreciated..

Plugin Name: Custom Fields Permalink 2
Plugin URI: http://athlan.pl/wordpress-custom-fields-permalink-plugin
Description: Plugin allows to use post's custom fields values in permalink structure by adding %field_fieldname%, for posts, pages and custom post types.
Author: Piotr Pelczar
Version: 2.0
Author URI: http://athlan.pl/

class CustomFieldsPermalink {

    const PARAM_CUSTOMFIELD_KEY = 'custom_field_key';
    const PARAM_CUSTOMFIELD_VALUE = 'custom_field_value';

    public static $checkCustomFieldValue = false;

    public static function linkPost($permalink, $post, $leavename) {
        return self::linkRewriteFields($permalink, $post);

    public static function linkPostType($permalink, $post, $leavename, $sample) {
        return self::linkRewriteFields($permalink, $post);

    protected static function linkRewriteFields($permalink, $post) {
        $replaceCallback = function($matches) use (&$post) {
            return CustomFieldsPermalink::linkRewriteFieldsExtract($post, $matches[2]);

        return preg_replace_callback('#(%field_(.*?)%)#', $replaceCallback, $permalink);

    public static function linkRewriteFieldsExtract($post, $fieldName) {
        $postMeta = get_post_meta($post->ID);

            return '';

        $value = implode('', $postMeta[$fieldName]);

        $value = sanitize_title($value);

        return $value;

    public static function registerExtraQueryVars($value) {
        array_push($value, self::PARAM_CUSTOMFIELD_KEY, self::PARAM_CUSTOMFIELD_VALUE);
        return $value;

    public static function processRequest($value) {
        // additional parameters added to Wordpress
        // Main Loop query
        if(array_key_exists(self::PARAM_CUSTOMFIELD_KEY, $value)) {
            $value['meta_key'] = $value[self::PARAM_CUSTOMFIELD_KEY];

            // remove temporary injected parameter

            // do not check field's value for this moment
            if(true === self::$checkCustomFieldValue) {
                if(array_key_exists(self::PARAM_CUSTOMFIELD_VALUE, $value)) {
                    $value['meta_value'] = $value[self::PARAM_CUSTOMFIELD_VALUE];

                    // remove temporary injected parameter

        return $value;

    public static function rewriteRulesArrayFilter($rules) {
        $keys = array_keys($rules);
        $tmp = $rules;
        $rules = array();

        for($i = 0, $j = sizeof($keys); $i < $j; ++$i) {
            $key = $keys[$i];

            if (preg_match('/%field_([^%]*?)%/', $key)) {
                $keyNew = preg_replace(
                    // you can simply add next group to the url, because WordPress
                    // detect them automatically and add next $matches indiceis
                $rules[$keyNew] = preg_replace(
                    sprintf('%s=$1&%s=', self::PARAM_CUSTOMFIELD_KEY, self::PARAM_CUSTOMFIELD_VALUE),
                    // here on the end will be pasted $matches[$i] from $keyNew, so we can
                    // grab it it the future in self::PARAM_CUSTOMFIELD_VALUE parameter
            else {
                $rules[$key] = $tmp[$key];

        return $rules;

add_filter('pre_post_link', array('CustomFieldsPermalink', 'linkPost'), 100, 3);
add_filter('post_type_link', array('CustomFieldsPermalink', 'linkPostType'), 100, 4);
add_filter('rewrite_rules_array', array('CustomFieldsPermalink', 'rewriteRulesArrayFilter'));
add_filter('query_vars', array('CustomFieldsPermalink', 'registerExtraQueryVars'), 10, 1);
add_filter('request', array('CustomFieldsPermalink', 'processRequest'), 10, 1);

I THOUGHT I FIGURED OUT A SOLUTION.. BUT... I thought that using the hex code for hyphen (%2D) in permalink settings was a solution.. but it turns out this only works in the chrome browser.. not in IE or Edge.. so I am still without a solution unfortunately :(

  • Ok... I figured out when I use backslash (/) to separate the custom fields it works properly.. but not when I use a hyphen.. maybe that helps? Commented Jul 16, 2017 at 17:14
  • I understand now that underscores are considered 'word joiners' while hyphens are considered 'word separators'.. so I really need to get the hyphens to work instead of underscores. Can anyone see how to get the provided code to inserts hyphens between words?? Commented Jul 16, 2017 at 17:20
  • alright.. I believe if I include a pre_replace in there somewhere to convert spaces (%20) to hyphens I should be good.. anyone know how to do it or where to put it? Hope someone can help :) Commented Jul 16, 2017 at 22:15
  • Your suggestion of using underscores instead of hyphens ultimately led me to the solution. I found that using the hex code for hyphen (%2D) worked as well. Thanks for getting the wheels turning :) Commented Jul 17, 2017 at 1:27

2 Answers 2


Use a underscore instead of a hyphen. You can see others are having the same issue. The underscore exchange fixes the problem.

Using underscores instead of hyphens in the permalink

  • Use an underscore where? And just for that portion of the URL? Also the field value just has a space. Lastly, every other source says hyphens are preferable over underscores especially with respects to SEO.. no? Commented Jul 15, 2017 at 0:02


It took me a while to get to this.. but the suggestion that the use of underscores as separators in the plugin instead of hyphens finally got me thinking. So, I decided to try using the hex code for hyphen (%2D) as a separator within the permalink settings and low and behold, it worked.

So, if there are any others looking for a solution to this problem, simply use %2D instead of - when separating custom field values on the permalink setting field.

TURNS OUT THIS ONLY WORKS IN CHROME.. doesn't work in firefox or edge :(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.