Wordpress and disqus and post loops

Monday, January 9. 2012
Comments

First off — I don't have too much experience with disqus on Wordpress but when I looked at the code(-quality), disqus is one of the best plugins for Wordpress to date. I looked only very briefly, but I found it to be very clean, well documented and well architected. Good job, disqus!

In case you happen to dive into Wordpress plugins in 2012, you will see that this is unfortunately not a given. Even (or maybe especially) the commercially available plugins to extend Wordpress are a source for PHP worst practices and contain all kinds of examples how not to write PHP. Part of it, is the platform, the rest is unexperienced developers or general lazyness.

Anyhow! Enough the rant!

Disqus and the loop

In Wordpress, almost everything is a loop. If you'd like to display a list of posts somewhere (for whatever reason), a loop is executed. The advantage (vs. a straight SQL query) range from all kinds all things like caching to convenience. When said hook is used different actions (plugin hooks) and filters are run. So even when the objective is to just collect data (and not even display it) — for example for an Ajax request/response — all these things happen in the back.

So in this case, whenever a loop is used, disqus will attempt to add their JavaScript to it. Usually, to display a comment form, counts and what not.

Problem?

The problem is, that the JavaScript code is then added all over and especially with Ajax you end up with the same code multiple times but add to that the cost of transport.

Solution!

Here's a simple workaround to prevent that.

Stick the following code into your template when you do not want the code to appear:

<?php
if (has_action('loop_end', 'dsq_loop_end')) {
    remove_action('loop_end', 'dsq_loop_end');
}

Yay! Happyness!

Fin

Filters and hooks are really what make Wordpress worth while. Period. In case you happen to do development for it, I urge you to take a look at them. I have a couple more ideas for small posts — stay tuned.

From Subversion to GIT (and beyond!)

Friday, December 9. 2011
Comments

Here's a more or less simple way to migrate from Subversion to GIT(hub), this includes mapping commits and tags and what not!

Authors

If multiple people congtributed to your project, this is probably the toughest part. If you're not migration from let's say Google Code but PHP's Subversion repository, then it's really pretty simple indeed: the username is the email address.

I found a nifty bash script to get it done (and adjusted it a little bit):

#!/usr/bin/env bash
authors=$(svn log -q | grep -e '^r' | awk 'BEGIN { FS = "|" } ; { print $2 }' | sort | uniq)
for author in ${authors}; do
  echo "${author} = ${author} <${author}@php.net>";
done

Since I migrated my project already, I didn't have the Subversion tree handy. That's why I used another package I maintain to demo this.

This is how you run it (assumes you have chmod +x'd it before):

# ./authors.sh
cvs2svn = cvs2svn <...>
cweiske = cweiske <...>
danielc = danielc <...>
gwynne = gwynne <...>
kguest = kguest <...>
pmjones = pmjones <...>
rasmus = rasmus <...>
till = till <...>

If you redirect the output to authors.txt, you're done.

Note: In case people don't have the email address you used on their Github account, they can always add it later on. Github allows you to use multiple email addresses, which is pretty handy for stuff like open source and work-related repositories.

git clone

This part took me a long time to figure out — especially because of the semi-weird setup in Google Code. The wiki is in Subversion as well, so the repository root is not the root where the software lives. This is probably a non-issue if you want to migrate the wiki as well, but I don't see why you would cluter master with it. Instead, I'd suggest to migrate the wiki content into a seperate branch.

Without further ado, this works:

# git svn clone --authors-file=./authors.txt --no-metadata --prefix=svn/ \
--tags=Services_ProjectHoneyPot/tags \
--trunk=Services_ProjectHoneyPot/trunk \
--branches=Services_ProjectHoneyPot/branches \
http://services-projecthoneypot.googlecode.com/svn/ \
Services_ProjectHoneyPot/

The final steps are to add a new remote and push master to it. Done!

You can see the result on Github.

A shortcut with Google Code

I facepalm'd myself when I saw that I could have converted my project on Google Code from Subversion to GIT.

This seems a lot easier since it would allow me to just push the branch to Github without cloning etc.. I'm not sure how it would spin off the wiki-content and how author information is preserved, but I suggest you try it out in case you want to migrate your project off of Google Code.

Doing it the other way is not time wasted since I had to figure out the steps regardless.

Summary

There seem to be literally a million ways to migrate (from Subversion) to GIT. I hope this example got you one step closer to your objective.

The biggest problem migrating is, that often people in Subversion-land screw up tags by committing to them (I'm guilty as well). I try to avoid that in open source, but as far as work is concerned, we sometimes need to hotfix a tag and just redeploy instead of running through the process of recreating a new tag (which is sometimes super tedious when a large Subversion repository is involved).

When I migrated a repository the other day, I noticed that these tags became branches in GIT. The good news is, I won't be able to do this anymore with GIT (Yay!), which is good because it forces me to create a more robust and streamlined process to get code into production. But how do I fix this problem during the migration?

Fix up your tags

If you happen to run into this problem, my suggestion is to migrate trunk only and then re-create the tags in GIT.

GIT allows me to create a tag based on a branch or based on a commit. Both options are simple and much better than installing a couple Python- and/or Ruby-scripts to fix your tree, which either end up not working or require a PHD in Math to understand.

To create a tag from a branch, I check out the branch and tag it. This may work best during a migration and of course it depends on how many tags need to be (re-)created and if you had tags at all. Creating a tag based on a commit comes in handy, when you forgot to create a tag at all: for example, you fixed a bug for a new release and then ended up refactoring a whole lot more.

In order to get the history of your GIT repository, try git log:

# git log --pretty=oneline                                                                                                                             [16:03:13]
1d973dfe6f6e361e6f54953f374d60289bb0abea add AllTests
f53404579f5416058937941d0609df4720717cae  * update package.xml for 0.6.0 release
d5b42eef2035d26b1e1d119ff44a09efa418685e  * refactored Services_ProjectHoneyPot_Response:    * no static anymore    * type-hinting all around
82d7e8d229109565d42f98c6548354f85734583c make skip more robust
b9e77a427eb546bacce600f5bc41546e85c148d7 prep package.xml for 0.6.0
6cecfbc19c00f0bf06b800c297e23f00cee650ef  * remove response-format mambojambo
036a9d9509adb456114f601c60d188839c012004 make test more robust
713c4ec91c28e19fbb33d6bb853ced0bdeb3f321  * update harvester's IP (this fails always)
755a2bba8f8506525a9cd2a1f11b266b7d26bbe6 throw exception if not a boolean
2aa21913946e2b4b3db949233a118dbbe2e34bf4  * all set*() are a fluent interface now  * update from Net_DNS_Resolver to Net_DNS2_Resolver  * dumb down setResolver(): Net_DNS2_Resolver is created in __const
81f544d880fc7b7a6321be9420b911817b567bd1 update docblock
dbe74da67c5fa1f1209fe85d3050041ca2a2de6b  * update docblock  * fix cs, whitespace
...

If I wanted to create a tag based on a certain commit (e.g. see last revision in the previous listing), I'd run the following command:

# git tag -a 0.5.4 dbe74da67c5fa1f1209fe85d3050041ca2a2de6b

Pro-tip: GIT allows you to create tags based on part of the hash to. Try "dbe74da", it should work as well.

That's all.

Things to learn

Moving from Subversion to GIT doesn't require too much to relearn. Instead of just commit, you also push and pull. These commands will get you pretty far if you just care for the speed and not for the rest.

Since I'm hoping, you want more, here are a couple things to look into:

  • branching
  • merging
  • git add -p
  • git remote add

Especially branching and merging are almost painless with GIT. I highly, highly recommend you make heavy use of it.

While GIT is sometimes a brainf*ck (e.g. submodules, commit really stages, subtree, absense of switch), the many benefits usually outweigh the downside. The one and only thing I truely miss are svn:externals currently. However, I'm hoping to master subtree one day and then I'll be a very happy camper.

Fin

That's all.

Cooking PHPUnit (and a chef-solo example on top)

Sunday, December 4. 2011
Comments

I'm sure most of you noticed that with the recent upgrade of PHPUnit to version 3.6, a lot of breakage was introduced in various projects.

And for example Zend Framework 1.x won't update to the latest version either. When I ranted on twitter someone send me Christer Edvartsen's blog post on how to setup multiple versions of PHPUnit. It's really neat since it walks you through the setup step by step and you learn about things such as --installroot on the way. --installroot in particular is something I never ever saw before and I've been using PEAR for more than a few years now. So kudos to Christer for introducing myself to it.

The only thing to add from my side would be, Why are you guys not aggregated on planet-php?.

Cooking with Chef

Another reason why I decided to write this blog entry was that I created a chef-recipe based on Christer's blog entry.

If you follow my blog for a while, you might have noticed that I'm a huge fan of automation. I just moved one of our development servers the other day and had one of these moments where something just paid off. Taking for granted that I can spin up fully operational EC2 instances in minutes, I also had our development stack installed and configured in an instant.

My recipe basically follows Christer's instructions and because I distribute phpunit's command along with it, editing of the file is no longer required: when the chef run completes, phpunit34 is installed and ready to be used.

Get started

I'm doing the following commands as root — my setup is in /root/chef-setup.

Install chef(-solo) and clone my cookbooks

shell# gem install --no-ri --no-rdoc chef
... 
shell# git clone git://github.com/till/easybib-cookbooks.git
...

Chef configuration

Then setup a node.json file which chef-solo will need to run:

{
  "run_list": [
    "recipe[phpunit]"
  ]
}

Then create a solo.rb:

file_cache_path "/var/chef-solo"
cookbook_path ["/root/chef-setup/easybib-cookbooks"]

Chef run

Finally we start chef-solo with following command:

shell# chef-solo -c /root/chef-setup/solo.rb -j /root/chef-setup/node.json -l debug
...

The command runs chef-solo (which is part of the gem we installed) and reads the basic configuration from the solo.rb-file. This file contains the location of the cookbooks (remember git clone ...) and a path to cache files. You don't need to create anything, it should be all taken care of.

The node.json-part allows us to set node-specific values. The prime example is the run-list, but it allows you to set attributes as well. Attributes contain values for variables used in recipes, but are not used in this example.

Last but not least: -l debug — a lot of useful output, but we usually run with -l warn. And if this is interesting enough for you, I suggest the other blog entries I wrote on this topic.

Did it work?

Depending on the location of your pear setup — usually /usr/bin/pear or /usr/local/bin/pear — the phpunit34 script is created in the same path:

shell# which phpunit34
/usr/local/bin/phpunit34

Yay!

Fin

This feels like hitting two birds with one stone. Though just by figure of speech! I object to violence against birds.

It might be overkill to setup chef to just install phpunit 3.4 by itself, but I think this serves as a stellar example of how you can leverage the power of chef to get more done. Writing a couple more recipes to install and configure the rest of your stack shouldn't be too hard.

If you'd like to see anything in particular: I'll take requests via email, Twitter or in the comments.

PHAR and FreeBSD

Sunday, November 6. 2011
Comments

I noticed that archivers/pecl-phar vanished from the ports tree on one of my FreeBSD servers.

Problem?

Reasons to remove the port were:

  • the port is unmaintained
  • the port was based on the outdated phar extension from pecl
  • phar (in pecl) contains open security issues

The simple solution is to create a new port which of course will use the phar which is bundled in PHP's core. And I will get to that (but feel free to beat me at it ;-)).

Solution

In the meantime, here's a simple solution to get phar on FreeBSD.

At first, make sure you're running PHP 5.3.8 (installed from lang/php5). Then fetch the PHP source and compile the phar extension only.

foo# fetch http://de2.php.net/get/php-5.3.8.tar.gz/from/de.php.net/mirror
foo# tar zxvf php-5.3.8.tar.gz
...
foo# cd php-5.3.8/
foo# ./configure --disable-all --enable-phar=shared
...
foo# make
...

If all goes well the modules/ directory contains a phar.so file (among other phar-things).

The remaining steps are to copy phar.so to your extension_dir and load it in extension.ini:

foo# cp modules/phar.so /usr/local/lib/php/20090626/

Feel free to double-check the location of directory:

foo# php -r 'echo ini_get("extension_dir");'

Finally, make sure PHP loads far by adding the following to /usr/local/etc/php/extensions.ini:

extension=phar.so

Fin

That's all. Once you restart php, or your webserver, phar should show up in phpinfo().

And as soon as a new php5-phar port is added (probably in archivers), you should make sure to delete phar.so and also remove the line added to the .ini.

WPML: icl_object_id() and custom post types

Friday, October 28. 2011
Comments

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.

icl_object_id()

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:

<?php
wp_redirect(get_permalink($post->post_parent));

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:

<?php
/* 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);
}
wp_redirect(get_permalink($parent));

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, ...)

Fin

That's all!