WPML URL override on archive page

Last week I ran into an issue with WPML URLs on post type archive page. When the permalink is set to %post_name%, we can access the archive page following //site_url/post_type_slug. And the posts can be filtered by taxonomy using //site_url/post_type_slug?taxonomy_name=taxonomy parameter in the URL. With WPML language switcher things become a bit tricky.

The issue

When I tried to change the language on the archive page while the taxonomy filter was present in the URL, WPML tend to take me to the taxonomy archive page instead. Let’s say for example my URL was http://ashiqur.com/books/?genre=fiction and when I tried to change to a different language (e.g. French) the URL became http://ashiqur.com/fr/le-genre/la-fiction while I expected it to be http://ashiqur.com/livres/?le-genre=la-fiction. Here livresla-genre and la-fiction is French translation of booksgenre and fiction respectively.

This wouldn’t be an issue for most cases. But in this particular case, I wanted to display only the detail of each genre along with some other info on their archive page and then show the books of each genre on the books archive page using the URL parameter.

Solution using WPML filter

The filter icl_ls_languages to the rescue! I added this filter to catch the language switcher and modify the URL before sent out to the output. Here is the final code I used:

Inside the foreach loop of languages I checked if this is a post_type_archive using is_post_type_archive() function. We can use is_search(), is_archive() or any similar function based on our need. Used the get_queried_object() function to get the current taxonomy and get_post_type() to fetch current post type. I checked whether $archived_taxonomy->slug is set to make sure we are filtering by a taxonomy and the WPML’s language switcher is going to redirect me to a different URL. So, next step is to generate the right URL and replace the WPML generated one with that.

Now that we have the taxonomy ID, we can get the counterpart of that in other language using wpml_object_id filter. Problem is, when we pass that ID to get_term() function, WPML takes over and adjusts the ID to our active language. So, we’ll get the taxonomy that I already have! Here comes the use of the global variable $icl_adjust_id_url_filter_off. I backed up the existing value of that variable (generally false), set it to true and then called the get_term() function like this:

//Backup the global variable
$orig_flag_value = $icl_adjust_id_url_filter_off;
//Set the global variable to true
$icl_adjust_id_url_filter_off = true;
//Fetch the translated counterpart of the term
$translated_term = get_term( apply_filters( 'wpml_object_id', $archived_taxonomy->term_id, $archived_taxonomy->taxonomy, false, $lang_code ), $archived_taxonomy->taxonomy );
//Reset the global variable to it's old value
$icl_adjust_id_url_filter_off = $orig_flag_value;

Now that I have the translated taxonomy name and slug, I replaced the query string of current URL using the desired taxonomy slugs. Then replaced the language URL to the post type (books in this case) archive page instead of taxonomy archive page and appended the new query string.

That it! Now the taxonomy archive works fine on its own and the post type archive works fine with query strings. %DRUMROLLS%!!

Email Obfuscation – WordPress Shortcode

Recently I was working on a WordPress website and was into a situation where I wanted to protect the email address from spam bots but also didn’t want the legitimate users to go through the trouble of filling out captcha and click an extra link. WordPress do have a nice function called antispambot which does it alright. But not up to my satisfaction. This function converts the email address to special characters which is quite intelligent but let’s face it. Robots are going to take over the world soon. They are becoming more smart every day. It is quite possible that some bots (at least their coder) knows how WordPress does it and a simple decode will reveal the email address for them. Recaptcha also have a feature to protect emails from bots. But this is quite tedious. User have to leave the website just to see the email address. Also the Recaptcha’s popup window looks really awful on mobile devices.

So, I created a shortcode that will hide the email address by default and reveal it to users using JavaScript. At least bots are not smart enough to use JavaScript (yet!). As a very limited number of users will use browsers with JavaScript disable, they can do the extra work and get the email address through recaptcha validation. Let’s see the code.

function my_hide_email_shortcode( $atts , $content = null ) {
    $a = shortcode_atts( array(
        'email' => '',
    ), $atts );
    if ( ! is_email( $a['email']) ) {
    $email_parts = explode('@', $a['email']);
    $email_head = $email_parts[0];
    $email_tail = $email_parts[1];
    $obfuscated_email_link = get_options('recaptcha_email_link');  //It's wise to set the link from admin side instead of hard coding.
    wp_register_script( 'email-obfusc', get_stylesheet_directory_uri() . '/library/js/email_obfusc.js', array( 'jquery' ), '', true );
    wp_localize_script( 'email-obfusc', 'email', array('content' => antispambot( $content )) );
    wp_enqueue_script( 'email-obfusc' );
    return '<span class="mail_hide" data-mail-h="'.strrev($email_head).'" data-mail-t="'.strrev($email_tail).'"><a class="obfocused-email" href="'.$obfuscated_email_link.'" target="_blank"> ' . (strlen($content) > 0 ? antispambot( $content ) : __('View email address', 'mytextdomain')) . '</a></span>';
add_shortcode( 'hide_email', 'my_hide_email_shortcode' );

If we use the shortcode like [hide_email email="[email protected]"]See the Email[/hide_email] the email address will first be broken into parts, reversed and stored as data variable of the wrapper. Later I’ve revealed the email address to users using JavaScript. If JavaScript is not available, user will be sent to recaptcha link to retrieve the email address. Here is the JavaScript code.

    var mail_head = jQuery('.mail_hide').first().attr('data-mail-h').split('').reverse().join('');
    var mail_tail = jQuery('.mail_hide').first().attr('data-mail-t').split('').reverse().join('');
    var oldhtml = '';
    var mail = mail_head+'@'+mail_tail;
    var mail_content = email.content;
    if(mail_content.length < 3) {
        mail_content = mail_head + '@' + mail_tail;
    jQuery('.choobs_mail_hide').first().html('<a class="obfocused-email" href="mailto:'+mail+'">'+mail_content+'</a>');
    jQuery('.obfocused-email').on('mouseover', function(e){
        oldhtml = jQuery(this).html();
        jQuery(this).attr('href', 'mailto:'+mail);
    }).on('mouseleave', function(e) {

This script fetches the parts of email address, reverses them again and the joins to form the actual email address. I’ve added an effect to reveal the email address when user mouse over the content text. But if there was no content and shortcode was used only like [hide_email email="[email protected]"] the email will be revealed by default.

Go away spam bots!!

Shortcode for Contact Form 7

Shortcodes are widely used feature of WordPress. Many plugin and theme developers use this interesting feature to easily push custom contents inside posts or pages. But what if we could add a custom field within a Contact Form 7 (wpcf7) form? That’s exactly what I tried to do couple of days back and it was really exciting.

In case you don’t know what is wpcf7 or shortcode, please have a look at WordPress codex. Here I’ll explain how I have added the shortcode to the wpcf7 form and later fetched their values.

I have worked with WordPress 3.9.2 and Contact Form 7 v 3.8.1 to test these features.

There is the method wpcf7_add_shortcode which adds shortcode directly into contact form 7. Well while this function has its virtues, there are some disadvantages. Most of the time we cannot use the function right away because that will give us the “undefined function” error. We have to add a wrapper action to make sure that the wpcf7 plugin is loaded. Continue reading