Installing PHP 5.4 (like a boss) with MacPorts

PHP 5.4.7 is the latest stable release of PHP. WordPress has a minimum required version of 5.2.6. Most developers aren’t using the PHP 5.4 branch. Actually, most aren’t even rocking PHP 5.3. This disgusts me.

PHP 5.3 added support for closures. If you come from the world of JavaScript, you know how useful they can be. If you have used PHP 5.3 and closures in classes, you will be happy to know that PHP 5.4 allows you to use $this in closures in class methods.

If you haven’t messed around with PHP 5.3, you can install these MacPorts to get started:

php5 +apache2+fastcgi+pear
php5-mysql +mysqlnd

If you already have PHP 5.3 and want to upgrade to PHP 5.4, these are some tricks to get you on the right path:

sudo -s // use sudo mode throughout

port uninstall php5
// won't work if you have extensions installed,
// so uninstall everything that has PHP5 as a dependency first

port install php54
cd /opt/local/etc/php54 && sudo cp php.ini-development php.ini

Install a bunch of PHP extensions:

port install php54-apc php54-curl php54-gd php54-http php54-iconv php54-imagick php54-mbstring php54-mcrypt php54-memcached php54-mysql php54-openssl php54-tidy

To use mysqlnd with a local MySQL server, edit /opt/local/etc/php54/php.ini and set

mysql.default_socket, mysqli.default_socket and pdo_mysql.default_socket


Make sure PHP 5.4.6 is the default PHP binary:

which php

If it’s something like /usr/bin/php:

cd /usr/bin && sudo rm -rf php
sudo ln -s /opt/local/bin/php54 php

You now have PHP 5.4.6 and your extensions, but you no longer have the apache variant.

port install php54-apache2handler

cd /opt/local/apache2/modules
sudo /opt/local/apache2/bin/apxs -a -e -n php5

vi /opt/local/apache2/conf/httpd.conf (remove the old

You now have PHP 5.4 and the apache handler, but you no longer have the PEAR variant. You can try to make this work:

port install pear-PEAR

Or you can do the following:

cd #
curl -o go-pear.phar
sudo php go-pear.phar

You will prompted to specify config vars, we want to change #1 and #4.

Press 1 – Installation base ($prefix) – and enter:


Press 4 – Binaries directory – and enter:


More checks for PEAR:

pear info pear && rm go-pear.phar
pear config-set auto_discover 1

// make sure PEAR is in the PHP include path
pear config-get php_dir

// if you don't see "/opt/local/lib/php54/share/pear" in there
php54 -i|grep 'php.ini'
// you should see "/opt/local/etc/php54" - if you don't:
sudo vi php.ini
// change include_path to:
include_path = ".:/opt/local/lib/php54/share/pear"

PEAR is installed, let’s install some PEAR stuffs:

// Unit tests
pear install
// Documentation generator
pear install

Restart Apache:

sudo /opt/local/apache2/bin/apachectl restart

You can start Apache and Memcached, et al by using commands like:

sudo port load apache2
sudo port unload apache2

sudo port load memcached
sudo port unload memcached

// memcached debugging, start with:
memcached -vv

A few notes on bbPress

I have been spending a lot of time off and on the past week creating a bbPress (message boards, or “forum software,” or “bulletin board”) theme for eMusic. Theming is fun because you get to touch almost every feature of the product, bbPress and/or WordPress. In the midst of this, I’ve been discovering how bbPress does things and making some modifications along the way. Those mods may only exist in eMusic and never make it into bbPress, but I have shared ideas with JJJ so I figured I would share them here as well for anyone to check out and supply feedback.

Queries within Queries with Queries

bbPress abstracts almost everything. For most WordPress-y things, there is a bbPress-y thing. One thing that will immediately confuse and potentially wreak havoc is the way “topics” are queried. Because the default WordPress query is the page or custom post type you are on, the topics for a forum are queried using a second mechanism: bbp_has_topics( ), which upon success, returns a WP_Query object.

That’s all well and good, but at any given time, there is only 1 bbPress query and no hardened reference to the original query. If you are using the default theme or just modifying its presentation, you probably don’t care. If you are implementing a design that has multiple “topics” queries, you are kinda up shit’s creek unless you roll your own code. The template tags / functions provided by bbPress will work to an extent, but they will also shift bbPress’s entire context every time you call bbp_has_topics( ).

The solution espoused to me was to roll my own WP_Query objects to replicate what bbPress is doing in the background, but I don’t want to do that. I want to use bbPress functions and fix whatever context is set along the way when necessary. WordPress maintains state and stores the main query by using $wp_the_query and $wp_query, for the main query and then the current query, respectively. bbPress clobbers $bbp->topic_query every time bbp_has_topics( ) is run. bbPress is treating bbp_has_topics( ) like query_posts( ) in WordPress, not like new WP_Query( ). Ask Nacin how he feels about query_posts( ).

bbPress makes an attempt to provide query context by providing the function bbp_set_query_name( $name )

Guess what it does internally… basically nothing. So I wanted to fix this, here’s some code I am using:

global $emusic_the_bbp_query;
$emusic_the_bbp_query = array();
function emusic_set_bbp_query( $name = 'main', $params = array() ) {
    global $emusic_the_bbp_query;
    $bbp = bbpress();

    bbp_set_query_name( $name );

    if ( !empty( $bbp->topic_query ) && empty( $emusic_the_bbp_query ) )
        $emusic_the_bbp_query['main'] = $bbp->topic_query;

    if ( !empty( $name ) && isset( $emusic_the_bbp_query[$name] ) ) {
        $bbp->topic_query = $emusic_the_bbp_query[$name];
        return $bbp->topic_query;

    if ( !empty( $params ) ) {
        bbp_has_topics( $params );
        $emusic_the_bbp_query[$name] = $bbp->topic_query;
        return $bbp->topic_query;

function emusic_reset_bbp_query() {
    global $emusic_the_bbp_query;
    $bbp = bbpress();
    $bbp->topic_query = $emusic_the_bbp_query['main'];

My code does a few things:

  • Sets $emusic_the_bbp_query whenever you start to change context the first time
  • Always allows you to retrieve the default context when you are done with a sub-query for topics
  • Non-persistently caches topic queries by name

So where’s my use case? I want to show a “snapshot” of your subscribed-to topics, favorite topics, popular topics, and super-sticky topics in the sidebar on every page, and I want to reuse theme code (template parts) to do so. Imagine calling query_posts( ) 5 times in a template on the WordPress side…

Could I have accomplished this with WP_Query? Yeah, but… I want to use the bbPress stuff. So here’s what I do:

<?php if ( is_user_logged_in() ):   ?>
<div class="meta-block">
    <h3>Your Topics</h3>
    <span class="double-line-narrow"></span>
    if ( bbp_is_subscriptions_active() ) : ?>
        <h4 class="sub-head">
            <a class="aux" href="<?php bbp_user_profile_url( get_current_user_id() ) ?>">view all</a>
        <span class="double-line-narrow"></span>
        $subscriptions = bbp_get_user_subscribed_topic_ids( get_current_user_id() );
        if ( !empty( $subscriptions ) ):
            emusic_set_bbp_query( 'bbp_user_profile_subscriptions', array( 'post__in' => $subscriptions, 'posts_per_page' => 3 ) );

            while ( bbp_topics() ) : bbp_the_topic();

                bbp_get_template_part( 'loop' , 'single-sidebar-topic' );

            printf( '<p>%s</p>', __( 'You haven't subscribed to any posts.' ) );


    endif; ?>

    <h4 class="sub-head">
        <a class="aux" href="<?php bbp_user_profile_url( get_current_user_id() ) ?>">view all</a>
    <span class="double-line-narrow"></span>
    $favorites = bbp_get_user_favorites_topic_ids( get_current_user_id() );
    if ( !empty( $favorites ) ):
        emusic_set_bbp_query( 'bbp_user_profile_favorites', array( 'post__in' => $favorites, 'posts_per_page' => 3 ) );

        while ( bbp_topics() ) : bbp_the_topic();

            bbp_get_template_part( 'loop' , 'single-sidebar-topic' );

        printf( '<p>%s</p>', __( 'You haven't favorited any posts.' ) );

<?php endif ?>

$super_stickies = get_option( '_bbp_super_sticky_topics', array() );
if ( !empty( $super_stickies ) ): ?>
    <div class="meta-block">
        <h3>Featured Discussions</h3>
        <span class="double-line-narrow"></span>
        emusic_set_bbp_query( 'bbp_super_stickies', array( 'post__in' => $super_stickies, 'posts_per_page' => 4 ) );

        while ( bbp_topics() ) : bbp_the_topic();

            bbp_get_template_part( 'loop' , 'single-sidebar-topic' );

<?php endif ?>

Meta Queries like whoa

First of all, JJJ has done an awesome job making bbPress a plugin, and it is super sweet how seamlessly it integrates with everything else in WordPress. The two areas I would like to help make improvements in are 1) cache and non-persistent cache 2) Meta Query performance in WordPress as a whole. bbPress makes Meta Queries like (holy shit) whoa. For 99% of installs, who cares. For us, my current dataset is already 100s of 1000s of posts and 2-3 million rows of postmeta. A meta query basically says:

  • I need stuff from the posts table
  • I need stuff joined from the postmeta table
  • I have indexed columns in both
  • Fuck that noise, let’s join on an unindexable LONGTEXT column and pray for mercy

I wish meta_query never existed in WordPress. But it does, and bbPress sings its song throughout. I have a few ideas for reducing number of queries made and also splitting the query into 2, so that PHP can compare integers instead of trying to sort them as text in MySQL. I have done a lot of performance testing on meta_queries, and I actually ditched them in a few places for WP_Query because they do not scale out of the box.

But I’m not just gonna whine about it, I’m gonna try to contribute and I’ll report back when I do.

Intstalling MySQL 5.5 on OS X (Mountain) Lion

I have a dark and painful history of installing MySQL the wrong way, which has forced many late nights and ungodly amounts of frustration. It should be super easy, and sometimes it is, but sometimes it is not. And it can suck.

This post is as much a documentation of what I did so I can re-read it the next time I screw up something as it is a tutorial for you. Let’s begin.

Don’t use MacPorts, use the .dmg from the MySQL website

MacPorts will give you MySQL 5.1.48 or something like it when you install the mysql5 port. The mysql55 port doesn’t upgrade your mysql5 port, it runs side by side and can be super confusing if you want to run terminal commands or change permissions on directories your forgot about when you installed mysql5. mysql5-devel doesn’t build on Mountain Lion yet. Awesome.

The .dmg file will give you everything you need: installs beautifully in /usr/local/mysql, provides a startup item installer that will fire up the mysqld_safe launch daemon when you turn your computer on, and a Preferences pane item that will allow you to start and restart MySQL until you are blue in the face with the simple press of a button.

Your install should start like this:

  • Download the .dmg
  • port uninstall mysql5 and mysql5-devel or whatever else you have installed
  • Add this to your ~/.bash_profileexport PATH=$PATH:/usr/local/mysql/bin
  • Restart your computer to make sure only your new MySQL 5.5’s daemon is running (when you uninstall the MacPorts, their daemons are still running until you kill them or restart) by typing:
    ps aux | grep mysql

If you see anything running from /opt, your MacPort(s) aren’t uninstalled.

After you have restarted your computer:

  • Fire up Terminal and type: mysql -u root
  • Run this query:  GRANT ALL ON *.* TO 'root'@'localhost' IDENTIFIED BY 'mypassword' WITH GRANT OPTION; (replacing ‘mypassword’ with whatever you want your root password to be)

At this point, you should have a database that works. If not, read about symlink-ing .sock files, etc here: How to install MySQL 5.5 on Mac OS X 10.7 Lion