WordPress

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%!!

Showing countdown timer in email

Last day I received an email newsletter which contained a countdown timer in it. It was quite interesting because most of the times emails are static and we are unable to show any dynamic data. Then again, there is the GIF image format which can show animated images. From investigating the source I figured that they are doing exactly that. They are using the service from a third party provider to create “countdown” GIF images.

So, I thought why not make one for myself. And I came up with a class to accept target time (end time of countdown) and some other parameters which will return an animated GIF image resource. We can then embed that image in the email and the email body will show a nice little countdown timer. More about the class and usage is available on GitHub.

Demo: A 15 minute timer

15 minutes

Fork the class from GitHub: https://github.com/ashiqur-rony/gif-timer

There is a catch though. As the timer creates a frame for each step (one frame per second in the above demo), this method is really resource hungry.

একটি প্রেমের কবিতা

আমি একটি প্রেমের কবিতা লিখতে চেয়েছিলাম,
কবিতাটা নিজে থেকেই হতাশা আর
আক্ষেপের কথা বলতে থাকে।
ঝকঝকে সাদা অফসেটে
আমি ভালবাসার কথা লিখতে চেয়েছিলাম,
কিন্তু কাগজটা হয়ে যায় ক্ষোভে নীল
ঘাস মেঘ ফুল আকাশ সবই রক্তাক্ত লাল।

আমি একটা কবিতা লিখতে চেয়েছিলাম,
কবিতায় প্রকৃতি থাকবে
বৃষ্টি নদী পাখি আর তারারা থাকবে
কিন্তু কবিতার শব্দগুলো অজান্তেই এলোমেলো
তোমায় নিয়ে কবিতাটা শুধুই অন্যরকম হয়ে যায়।
কবিতাটা অভিজিৎ বলে চিৎকার করে ওঠে
প্রতিধ্বনি হয় – অনন্ত ওয়াশিকুর।

আমি শুধুই ভালবাসি বলতে চেয়েছিলাম
শব্দের ছন্দে প্রকৃতি মিশিয়ে প্রিয়তমার স্তুতি।
কিন্তু প্রেম আজ ভীত স্থবির
ভালবাসা কুন্ঠিত বিবর্তনের উল্টো স্রোতে,
কবিতা তাই আজ নিজেই সোচ্চার,
প্রতিবাদী হয়ে
আমার অক্ষমতার লজ্জা ঢাকে।

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']) ) {
        return;
    }
    $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.

jQuery(document).ready(function(){
    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).html(mail);
        jQuery(this).attr('href', 'mailto:'+mail);
    }).on('mouseleave', function(e) {
        jQuery(this).html(oldhtml);
    });
});

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!!

Shimmi

লক্ষী মেয়েটা কে শুভকামনা

জীবনে দিন দিন ব্যস্ততা বাড়তে থাকে আর সম্পর্কগুলো ফিকে হয়ে যায়। স্বার্থপরের মত সবকিছুই হয়ে যায় আমিময়।  গভীর বন্ধুত্বগুলো শুধুই “কিরে কেমন আছিস” -এ সীমাবদ্ধ হয়ে পড়ে। মাঝে মাঝে অলস সময়ে স্মৃতিগুলো শুধু একটু জ্বালা যন্ত্রণা করে। তারপরে আবারও আমি আমি আমি।

ঢাকা বিশ্ববিদ্যালয়ের সময়টুকু সত্যিই অসাধারণ ছিল। আর তার কারণ অসাধারণ কিছু বন্ধু। সেই কাছের বন্ধুদের একজনকেই আজকের এই লেখাটুকু।

আমরা ক্লাস শুরুর ২-৩ দিন পরে পিচ্চি একটা মেয়ে ক্লাসে এসে হাজির। কোনও একটা উদ্ভট কারণে আমাদের ক্লাসে ছেলে এবং মেয়েরা আলাদা সারিতে বসত প্রথম দিন থেকেই (এর জন্য সম্ভবত রুবীর বোরখা দায়ী)। সে যাই হোক, আলাদা বসলেও কিভাবে কিভাবে যেন ক্লাসের এক মাথা থেকে আরেক মাথায় সব ইনফরমেশনগুলো পাস হয়ে যেত। মেয়েটা ক্লাসে আসার কয়েক মিনিটের মধ্যেই জানতে পারলাম সে খেলোয়াড় হিসেবে আমাদের ডিপার্টমেন্টে জয়েন করেছে। আর সে কারণেই ২-৩ দিন দেরি। স্বভাবতই ক্লাসের সবচেয়ে শেষ রোল নাম্বারটা তাকে এসাইন করা হলো – ৬৬। আমার রোল নাম্বার ছিল ৩৩। বেশ মজাই লাগলো। প্রথম দিন ভাবছিলাম মাথার পেছনে ছোট্ট পনিটেইল করা এই পিচ্চি মেয়েটা কি খেলতে পারে! কয়েকদিন পরেই আবিষ্কার করলাম এই মেয়েটা তুখোড় দাবাড়ু। সিম্মি জয়েন করেই কিভাবে যেন কাশফিয়ার সাথে ভিড়ে গেল। সিম্মির নামের উচ্চারণ কিন্তু শিম্মি কিন্তু বিশ্ববিদ্যালয়ে পড়ার পুরোটা সময় ভুল বানানে আর ভুল উচ্চারণে ওর নাম সিম্মি বলে খেপাতাম।

কিছুদিন পরেই আবিষ্কার করলাম এই মেয়েটা শুধু দাবায় না, লেখাপড়ায়ও তুখোড়। আমাদের সময় যখন হারিকেন দিয়ে খুঁজেও ২-১ জন এ+ পাওয়া যেত না সেই সময় এই মেয়েটা ইংরেজীতে এ+ পেয়েছিল! ফার্স্ট ইয়ার ফাইনালে সিম্মির কল্যানেই কিভাবে যেন মোটামুটি ভাল রেজাল্ট করে ফেললাম।

সিম্মির একটা নিক নেম ছিল আমাদের বন্ধুদের মধ্যে – “লক্ষী মেয়ে”। প্রতিদিনই ক্লাস শেষ হওয়ার সাথে সাথেই যখন আমরা আড্ডাবাজী বা ২৯ খেলতে বসতাম সিম্মি বলতো – “বাসায় যাব”। লক্ষী মেয়ে নামের কারণ এটাই। বিশ্ববিদ্যালয়ে সেকেন্ড ইয়ারে উঠার পরে সবার মধ্যেই একটা প্রেম প্রেম ভাব আসে। তখন প্রেম করাটা মোটামুটি রুটিন ব্যপার। দেখা গেল আমাদের বন্ধুদের গ্রুপের সবাই প্রেম করে ফেলেছে শুধু আমি, সিম্মি আর অতুল বাকি। অতুল বেচারা একটু মুখচোরা হওয়ায় বাকিরা আমাকে আর সিম্মিকে বেশ খেপানোর চেষ্টা করতো। আর “লক্ষী মেয়ে” সিম্মি যে কোনও উপায়ে এই ক্ষেপানো থেকে বাঁচার উপায় খুঁজতো। একদিন দুপুরে মেডিকেল থেকে লাঞ্চ করে রিকশায় ফিরছি এমন সময় ঝুম বৃষ্টি। রিকশায় হুড তুলে বসলে সবাই আবার ক্ষেপাবে এই যুক্তিতে দুইজন রিকশায় হুড খুলে বৃষ্টি বিলাস করতে করতে কাক ভেজা হয়ে ক্লাসে ফিরলাম! একমাত্র লেখাপড়া ছাড়া আর সব বিষয়েই সিম্মির যুক্তিগুলো এরকম অদ্ভুতই ছিল। এমন অদ্ভুত মেয়েটা কিভাবে যে এত ভাল দাবা খেলে সেটা আমার মাথায় ঢুকে না।

মাঝে মাঝেই ক্লাস শেষ হওয়ার সাথে সাথে সিম্মি দৌড় দিত দাবা ফেডারেশনে খেলার জন্য। কোনও কোনও দিন আমি যেতাম খেলা দেখতে। দুঃখের বিষয় যেদিনই আমি যেতাম সেদিনই ও হেরে যেত! আমি গেলেই সম্ভবত “কুফা” লেগে যেত। এই কারণে কিছুদিন পর থেকে সিম্মির খেলা থাকলে আমি দাবা ফেডারেশনের আশে পাশে যাওয়াই বন্ধ করে দিলাম। লক্ষী মেয়েটা বেশ সেলিব্রিটি খেলোয়াড় হয়ে গেছে। আর আমিময় আমার বেশ গর্ব লাগছে মেয়েটাকে আমার বন্ধু বলতে পেরে। অনেক শুভকামনা তোর জন্য।