0

I am trying to get from this kind of url:

domain.com/page/classes/?language=english&need=pro

To this:

domain.com/class/english-pro

MORE INFORMATIONS

Both variables have been added as query_vars. classes is the current page and page is the parent page.


WHAT I'VE TRIED

Here is the rewrite rule I've tried but it's not working.

function custom_rewrite() {
    add_rewrite_rule( 'class/([^/]+)-([^/]+)$', 'index.php?language=$matches[1]&need=$matches[2]', 'top' );
}
add_action( 'init', 'custom_rewrite' );

For some reasons I can't get my head around the regex expressions... Thanks for your help!


UPDATE 1

With a bit of searching this what I came up with:

function custom_rewrite() {
  add_rewrite_tag( '%_language%', '([a-zA-Z\d\-_+]+)' );
  add_rewrite_tag( '%_need%', '([a-zA-Z\d\-_+]+)' );
  add_rewrite_rule( 'class/([a-zA-Z\d\-_+]+)-([a-zA-Z\d\-_+]+)?', 'index.php?_language=$matches[1]&_need=$matches[2]', 'top' );
}
add_action( 'init', 'custom_rewrite' );

But it's still not working.


UPDATE 2

I've made some changes so that it gets easier to do the redirect. Here is how it works:

  • I've got two selects in a form whith which people can choose a language and a need. Both are declared query variables.
  • When the form validates it loads this url: domain.com/page/classes/?_language=english&_need=pro.
  • The result's page loads informations from a custom post type named with the following structure language-need. I get the informations by using a query_posts that build the name from the query variables.

Now what I want is simple : to redirect the defaut url (domain.com/page/classes/?language=english&need=pro) to this new url (domain.com/class/english-pro) while still loading the same informations**.


UPDATE 3

I've tried @jgraup solution below (without the prefix__pre_post_link function as I've simplified my url to not need it) but it's not working (my custom post type is using the same settings

if ( ! class_exists( 'PrefixClassesRewrites' ) ) {

  class PrefixClassesRewrites {

    const POST_TYPE_SLUG = 'lang';

    function __invoke() {
      add_action( 'init', array ( $this, 'prefix__init' ) );
      add_action( 'pre_get_posts', array ( $this, 'prefix__pre_get_posts' ) );
    }

    public function prefix__init() {
      // custom query params that we check for later
      add_rewrite_tag( '%_language%', '([a-zA-Z\d\-_+]+)' );
      add_rewrite_tag( '%_need%', '([a-zA-Z\d\-_+]+)' );
      add_rewrite_tag( '%_page_class%', '_page_class' );

      // rewrite rule to transform the URL into params
      add_rewrite_rule( 'class/([a-zA-Z\d\-_+]+)-([a-zA-Z\d\-_+]+)?', 'index.php?_language=$matches[1]&_need=$matches[2]&_page_class=1', 'top' );

      flush_rewrite_rules(); // <-- for testing only | removed once the rewrite rules are in place
    }

    public function prefix__pre_get_posts( $query ) {

      if ( isset( $query->query_vars[ '_page_class' ] ) ) {

        // Convert the variables to a custom post type name.
        $name = implode( '-', array (
          $query->query_vars[ '_langue' ],
          $query->query_vars[ '_besoin' ],
        ) );

        // Add the name and post_type to the query.
        $query->query_vars[ 'name' ]      = $name;
        $query->query_vars[ 'post_type' ] = array ( static::POST_TYPE_SLUG );

        // Nothing else to do here.
        return;
      }
    }

  }

  $prefixClassesRewrites = new PrefixClassesRewrites();
  $prefixClassesRewrites(); // kick off the process
}

The thing is that nothing has changed, my url is not being rewritten. By the way, is the rewriting tule supposed to be in y htaccess when it's working?

  • You need to use add_rewrite_rule to make your custom query args come through. See codex.wordpress.org/Rewrite_API/add_rewrite_rule But it's just simply specifying that language is a thing. If it messes up your query then I found _language doesn't. Just don't expect to use a $_GET for these rewrites. – jgraup Nov 30 '16 at 19:02
  • Just to clarify, you're looking for matches on an actual URL like /domain.com/page/class-5-6? Where language=5 and need=6 – jgraup Nov 30 '16 at 19:05
  • I'm looking for a way to get this url /domain.com/page/class-post_name-term_slug where language=5 (5 being the post_id) and need=6 (6 being the term_id). – Pipo Nov 30 '16 at 19:07
  • Alright, I've changed everything so that I have the correct terms in my query variables, it's gonna be easier. Now I just need to get that rewrite_rule to work. I'll update my question. – Pipo Dec 1 '16 at 17:04
  • There are a few examples at wordpress.stackexchange.com/a/215163/84219 that show rewrites. – jgraup Dec 2 '16 at 3:49
1
+50

Hope this will work out for as it did for me.

add_filter('rewrite_rules_array', 'insert_custom_rules');

add_filter('query_vars', 'insert_custom_vars');


function insert_custom_vars($vars){        

    $vars[] = 'main_page';       

    return $vars;

}

function insert_custom_rules($rules) {

    $newrules = array();

    $newrules=array(
        'page-name/(.+)/?' => 'index.php?pagename=page-name&main_page=$matches[1]'
    );

    return $newrules + $rules;
}

So, with the help of get_query_var() function, we can get value from url and use accordingly. In this way, we can get pretty URLs.

Note: If you have more than one rule, write the ones having more variables first and then those having less. Please specify static content between variables in case of multiple.

  • Thanks for your answer @Varun Kumar but this is not working for me (my url is not redirected to anything). – Pipo Dec 7 '16 at 19:44
  • Please mention the url, you are hitting – Varun Kumar Dec 8 '16 at 7:00
  • the rewrite I've tried is the following: 'class/([^/]+)-([^/]+)/?' => 'index.php?_language=$matches[1]&_need=$matches[2]'. But it's not rewriting to anything... – Pipo Dec 8 '16 at 9:16
  • I've check with the Rewrite plugin and when I test for my url domain.com/page/classes/?language=english&need=pro it does not match the rewrite rule. – Pipo Dec 8 '16 at 10:01
  • It's good to hear from you that your issue has been resolved. :-) – Varun Kumar Dec 8 '16 at 11:23
0

There are a lot of assumptions here but maybe you can clear those up. This assumes you made a CPT that could look like:

domain.com/page/class/english-pro

And converts it to

domain.com/page/class-english-pro

Either way. The URL is taking the params and modifying the query to show a page. CPT was added in here so this example could work for anyone out of the box. And the permalink rewrite was added to adjust, well, the permalink.

I'm not going to say this is the answer but there are some things in here that might help you.

<?php

if ( ! class_exists( 'PrefixClassesRewrites' ) ) {

    class PrefixClassesRewrites {

        const POST_TYPE_SLUG = 'classes';

        function __invoke() {
            add_action( 'init', array ( $this, 'prefix__init' ) );
            add_action( 'init', array ( $this, 'prefix__init_cpt' ), 0 );
            add_action( 'pre_get_posts', array ( $this, 'prefix__pre_get_posts' ) );
            add_filter( 'post_type_link', array ( $this, 'prefix__pre_post_link' ), 3 );
            add_filter( 'post_link', array ( $this, 'prefix__pre_post_link' ), 3 );
        }

        /**
         * Register the custom post type.
         */
        public function prefix__init_cpt() {
            $rewrite = array (
                'slug'       => 'page/class', // get's closer but will end with / not -
                'with_front' => false,
                'pages'      => true,
                'feeds'      => true,
            );

            register_post_type( static::POST_TYPE_SLUG, array (
                'label'               => __( 'Classes Post Type', 'text_domain' ),
                'description'         => __( 'Classes Post Type Description', 'text_domain' ),
                'rewrite'             => $rewrite,
                'hierarchical'        => false,
                'public'              => true,
                'show_ui'             => true,
                'show_in_menu'        => true,
                'menu_position'       => 5,
                'show_in_admin_bar'   => true,
                'show_in_nav_menus'   => true,
                'can_export'          => true,
                'has_archive'         => true,
                'exclude_from_search' => false,
                'publicly_queryable'  => true,
                'capability_type'     => 'page',
            ) );
        }

        /**
         * Add the rewrite rule and allow custom query params
         */
        public function prefix__init() {
            // custom query params that we check for later
            add_rewrite_tag( '%_page_class%', '_page_class' );
            add_rewrite_tag( '%_language%', '([a-zA-Z\d\-_+]+)' );
            add_rewrite_tag( '%_need%', '([a-zA-Z\d\-_+]+)' );

            // rewrite rule to transform the URL into params
            add_rewrite_rule( 'page/class-([a-zA-Z\d\-_+]+)-([a-zA-Z\d\-_+]+)?', 'index.php?_page_class=1&_language=$matches[1]&_need=$matches[2]', 'top' );

            flush_rewrite_rules(); // <-- for testing only | removed once the rewrite rules are in place
        }

        /**
         *  Modify the query to convert our params to a custom post type pagename
         *
         * @param $query
         */
        public function prefix__pre_get_posts( $query ) {

            // Check for our custom query param. Really just a flag to do this
            if ( isset( $query->query_vars[ '_page_class' ] ) ) {

                // Convert the variables to a custom post type name.
                $name = implode( '-', array (
                    $query->query_vars[ '_language' ],
                    $query->query_vars[ '_need' ],
                ) );

                // Add the name and post_type to the query.
                $query->query_vars[ 'name' ]      = $name;
                $query->query_vars[ 'post_type' ] = array ( static::POST_TYPE_SLUG );

                // Nothing else to do here.
                return;
            }
        }

        /**
         * Rewrite the permalink to match our setup.
         *
         * @param string       $permalink
         * @param null|WP_Post $post
         * @param bool         $leavename
         *
         * @return string
         */
        public function prefix__pre_post_link( $permalink = '', $post = null, $leavename = false ) {
            return str_replace( '/page/class/', '/page/class-', $permalink );
        }
    }

    $prefixClassesRewrites = new PrefixClassesRewrites();
    $prefixClassesRewrites(); // kick off the process
}
  • Thanks @jgraup for your complete answer! It's not working for me but at least I've learn some things. By the way, why is the POST_TYPE_SLUG in an array? I've updated my question with my new code if you don't mind having a look. – Pipo Dec 7 '16 at 19:47
0

Alright, I've changed my way of thinking about this issue and as I don't really know where the problem comes from I have opted for another solution.

I am using a wp_safe_redirect to the url of the corresponding custom post type.

For those interested in the solution, my form action is the permalink of a page created just for this (let's call it class).

On this class page I have the following safe redirect:

// getting my variables from the url
$language = get_query_var( '_language' );
$need = get_query_var( '_need' );

// redirecting to the corresponding custom post type url
if( isset( $language ) && isset( $need ) ) {
  wp_safe_redirect( esc_url( home_url('/') ) .'class/'. $language .'-'. $need .'/', 301 );
  exit;
} else {
  // if variables are not defined 
  // redirect to home (or whatever page you want)
  wp_safe_redirect( esc_url( home_url('/') ) );
  exit;
}

Now everything works great!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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