Skip to content

WPML: icl_object_id() and custom post types

Digressing from my usual grounds, I moonlighted a bit on a Wordpress project in September. One of the project's goals was to make the entire website bi-lingual: French and German (or the way around?). And once multi-lingual is an object, WPML is the plugin to use (as far as Wordpress is concerned).

WMPL in a nutshell

WPML is a commercial plugin — and as far as I am concerned: it's money well spend.

In case there's not a lot customization going, WPML works out of the box. For those digging a little deeper, WPML includes all these extra features and functions which are supposed to make life easier, but in reality, it doesn't always work out that way.

One example is rewriting queries to only show posts in the currently selected language. It only seems to work so far, or every once in a while. WPML's documentation is out-dated (or sometimes wrong), their forum is semi-useful (hint: you have to login to see anything useful) and so on. These last issues are especially sour for a commercial product.


One of the core features to make your theme work is the icl_object_id() function. It's supposed to take an ID (and a type) as an argument and should return the ID of the translation in the currently selected language. But add custom post types (a pretty useful plugin: custom post types UI) and it gets a little confusing.

It took me a while to find my way around it, so here's a small snippet to make icl_object_id() work with any post type.

Use case

There's an image.php in my theme (which is based on TwentyEleven), but we don't want a page dedicated to a single image.

Telling contributors of the website not to link to it only goes that far: the solution is to redirect the user to the article. Now add custom post types and a multi-lingual experience: Problem?

Not so much!

This is what we started off with:


Hint, hint: Ugh... an extra SQL-query to get the permalink.

The above works if you don't use WPML. ;-)

Then we advanced to this:

/* image.php */
$parent = $post->post_parent; // this is the parent the image belongs to
if (defined('ICL_LANGUAGE_CODE')) { // this is to not break code in case WPML is turned off, etc.
    $_type  = get_post_type($parent);
    $parent = icl_object_id($parent, $_type, true, ICL_LANGUAGE_CODE);

Hint, hint: Add one query for the post type, and who knows how many more in icl_object_id(). Finish off with the one for the permalink.

Step by step!

  1. $parent is what the current post is associated with. E.g. this is an image, attached to a certain post. The post is its parent.
  2. Then I get the post type ($_type) — if you don't run custom post types, this is likely post. But it could be anything.
  3. icl_object_id() takes four arguments:
    • $parent: the current id
    • $_type: the type of object (e.g. post, category, post_tag, … or your custom post type)
    • true: failover to return the original if nothing was found
    • ICL_LANGUAGE_CODE: this is a constant introduce by WPML, it contains the current language (de, en, fr, ...)


That's all!

Iterating over a table (with Zend_Db_Table and Zend_Paginator)

So frequently, I need to run small data migrations or transformations. Especially on the way to Doctrine, there's a lot to clean-up in a database which has been used and evolved over five years or so.

The other day, I wanted to run some transformations on the data located a history column in a pretty simple table — here's what it looks like:

mysql> SHOW FIELDS FROM data;
| Field       | Type             | Null | Key | Default             | Extra          |
| id          | int(11)          | NO   | PRI | NULL                | auto_increment | 
| first       | varchar(255)     | YES  | MUL | NULL                |                | 
| last        | varchar(255)     | YES  | MUL | NULL                |                | 
| email       | varchar(255)     | YES  | MUL | NULL                |                | 
| history     | varchar(255)     | YES  | MUL | NULL                |                | 
| rec_datemod | datetime         | YES  |     | NULL                |                | 
| rec_dateadd | datetime         | NO   | MUL | 0000-00-00 00:00:00 |                | 
12 rows in set (0.02 sec)

Building a class to interface the table is simple:

class Data extends Zend_Db_Table_Abstract
    protected $_primary = 'id';
    protected $_name = 'data';

Now it should be easy to iterate across it, find data and save — wrong!

Steve Jobs

I found myself pondering today when I tried to figure out what I want to say or write about Steve Jobs passing away. Because whatever I wanted to share seemed not appropriate and just not good enough.

I watched his Standford speech (again) and while I think this speech did not have the edge and finesse his usual Apple-related appearances did, it contains so much wisdom and enlightenment. Fundamentals which do not just apply to young people but everyone else as well.

I could still go on to talk about how he revolutionized music, phones and computers. How his diet saved a lot animals. But I just feel that wouldn't do him justice.

Today I just regret never seeing Steve Jobs speak in person.

Twitter bootstrap + Zend_Form = ♥

I dig Twitter's bootstrap library because as a developer, it helps me produce good looking forms without a lot of effort. Especially when administration interfaces are concerned, you I can only go so far — my first constraint is not being a great designer (to confirm, check out this blog) and two: I don't like working with ugly interfaces.

To cut to the chase...


It's a decorator library for Zend_Form. Among the Twitter Bootstrap style, it also supports simple <div> and <table> styles — all courtesy of the awesome Michael Scholl. The code is MIT licensed: it should suit your budget just fine. ;-)


(Side-note: We got a PEAR channel.)

$ pear channel-discover
$ pear install easybib/Easybib_Form_Decorator-alpha


See the docs folder on github.


Questions, comments and feedback are always appreciated — pull requests are most welcome.