/labs

This is a blog by the staff at the web agency Earth People in Stockholm Sweden. Check out our work and get in contact with us here.

WP e-Commerce on multisite with domain mapping

Using WP e-Commerce on a WordPress multisite is easy. But getting it to work with Domain Mapping proved a little tricky.

WP e-Commerce adds a few options to the wp_options table, like “product_list_url”, “shopping_cart_url”, and a few others. These are full links containing the domain name from your multisite setup. If you want your customers to be able to update your basket and checkout, you must manually change these urls in mysql, to contain the full urls to the domain you have mapped.

CodeIgniter/ActiveRecord setup to use master + slave db replication

This is how you can set up CodeIgniter to direct mysql queries to different read/write hosts in your db replicated environment, using a db_slave for your SELECT’s, and a db_master for the INSERT/UPDATE/DELETE queries.

File: application/config/database.php

Specify the different database hosts in the database config file:

< ?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

$active_group = "master";
$active_record = TRUE;

# db_master
$db['master']['hostname'] = "host1";
$db['master']['username'] = "username";
$db['master']['password'] = "password";
$db['master']['database'] = "exampledb";
$db['master']['dbdriver'] = "mysql";
$db['master']['dbprefix'] = "";
$db['master']['pconnect'] = FALSE;
$db['master']['db_debug'] = TRUE;
$db['master']['cache_on'] = FALSE;
$db['master']['cachedir'] = "";
$db['master']['char_set'] = "utf8";
$db['master']['dbcollat'] = "utf8_general_ci";

#db_slave
$db['slave']['hostname'] = "host2";
$db['slave']['username'] = "username";
$db['slave']['password'] = "password";
$db['slave']['database'] = "exampledb";
$db['slave']['dbdriver'] = "mysql";
$db['slave']['dbprefix'] = "";
$db['slave']['pconnect'] = FALSE;
$db['slave']['db_debug'] = TRUE;
$db['slave']['cache_on'] = FALSE;
$db['slave']['cachedir'] = "";
$db['slave']['char_set'] = "utf8";
$db['slave']['dbcollat'] = "utf8_general_ci";
...

File: application/core/My_Model.php

Add this into My_Model:

< ?php

class MY_Model extends CI_Model {
    function __construct(){
        parent::__construct();
	$this->db_master = $this->load->database('default', TRUE);
	$this->db_slave = $this->load->database('default', TRUE);
    }

}

File: application/models/example_model.php

Use the read/write queries in your models like this:

< ?php
class example_model extends MY_Model {

	function example_model()
	{
		parent::MY_Model();
	}

	# read query
	function getSomething()
	{
		$query = $this->db_slave->get('mytable'); // db_slave
		return $query->result();
	}

	# write query
	function insertSomething()
	{
		$this->db_master->insert('mytable', $_POST); // db_master
		return $this->db_master->insert_id();
	}

That´s it!

Fetching WordPress content from CodeIgniter

In a few recent projects we’ve used the excellent WordPress admin for content entry, but built the public facing stuff in CodeIgniter. Making these platforms talk to each other is fairly simple, and this is what we’ve learnt along the way.

- Do not, ever, initialize WordPress to fetch the data.
WordPress is quite the memory hog (compared to CI) and requesting WordPress content via feeds (using the JSON API plugin or such) heavily will bring your server down under load.

- Instead, always query the DB directly.
WordPress data structure is quite simple. But some of the WordPress functions are poorly written, so port them manually rather than just dumping them into CI.

As we’ve used this on a few sites already, it felt like we should wrap this into something generic and reusable. And with Sparks making its way into the CodeIgniter core, the time had come to learn how to wrap reusable CI stuff in sparks. So here we go. Version 0.0.4 of CodeIgniter-WP. There are only a few methods available at the moment, but hey – look at the version number. It will be better.

$this->load->spark('wp/0.0.4');
print_r($this->wp->get_post('blog', 1);
print_r($this->wp->get_installations());
print_r($this->wp->wp_get_recent_posts('blog', array()));
print_r($this->wp->get_post('blog', 1));
print_r($this->wp->get_post_meta('blog', array('post_id' => 1, 'key' => '_edit_last', 'single' => false)));

Download the spark by following the instructions here.

Moving WordPress 2.6 posts to a new 3.x installation

You have an old 2.6 version of WordPress with 2 000+ posts and 100 000+ in total comments. Today you have installed a brand new WordPress 3.x blog and want to import all data from the old blog but it is just too much to export with the built in export function in WP 2.6. In 2.6 there is no filter option as in 3.x so we had to edit the core export.php to split up the export in parts.

The export.php you will find in wp-admin/includes/export.php

Include approved comments only

First we’re going to edit this file so that only approved comment will be exported, no need to keep the spam, right? This might lower the amount of comments to 30-40 000 instead of the 100 000 +. So, around on line 233 you will find

$comments = $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d", $post->ID) );

Copy that line and comment it out. Paste the line above the old and after %d you add

AND comment_approved = '1'

so the finished code will look like

$comments = $wpdb->get_results( $wpdb->prepare("SELECT * FROM  $wpdb->comments WHERE comment_post_ID = %d AND comment_approved =  '1'", $post->ID) );
#$comments = $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d", $post->ID) );

Save the changes and the first part is done.

Split the export into chunks

To split the export we use the LIMIT option in the database request and edit this file after every chunk we export. Let’s dig into the code again.

Around line 24 will you find

$post_ids = $wpdb->get_col("SELECT ID FROM $wpdb->posts $where ORDER BY post_date_gmt ASC");

Copy that line and comment it out. Paste the line above the old and after ASC you add

LIMIT 0, 500

so the finished code will look like

$post_ids = $wpdb->get_col("SELECT ID FROM $wpdb->posts $where ORDER BY post_date_gmt ASC LIMIT 0, 500");
#$post_ids = $wpdb->get_col("SELECT ID FROM $wpdb->posts $where ORDER BY post_date_gmt ASC");

The first value (0) tells where to start and the second (500) how many results to get. With this values the export will take the first 500 blog posts. The 500 value might have to be lower or can be higher, it all depends on how much load your web server can handle. Save your changes and go and run an export. If you get a popup about saving a file, everything works. If not, try to set a lower amount value.

The export option can be find in Design -> Export in WP 2.6

After the first export, we have to change the LIMIT values from 0, 500 to 501, 500 to get the next 500 posts. Repeat this and up the values after every export you do. Don’t forget go name your files with something like part1, part2 and so on.

Make the import

To import your posts and comments you first login to your new 3.x WP. In the Tools section in the menu you have the option “Import”. Go there and choose “WordPress” from the list.

If this is the first time you use this you will get a popup about installing the import plugin, go ahead and do so. After installing it, network activate it and go back to the tools -> import -> wordpress page.

Now you can select a file to import. Click browse and choose the first part of your exported files. Continue with clicking “Upload file and import”.

On the next page you have some options. You can choose to import the posts with the default admin user, create a new user och choose an existing. Also, check the “download and import attachment” to get pictures and other files that in your posts.

Repeat this steps with all your exported xml files from the old blog. Remember to import them in the same order as you exported them!

/ Mattias & Hjalmar

Multiple domains on one WP network installation

Setting up a new WordPress Network is from version 3.0 very simple and done within 5 min. To set this up so you can use multiple domains to your network blogs is no biggie that either. But what if you want to have multiple domains pointed to the main blog/network and not the sub blogs? Not that easy.

Lets start with how we want the url structure:

blog.site.se
blog.site.se/blog1
blog.site.se/blog2
blog.site.dk
blog.site.dk/blog3
blog.site.no
blog.site.no/blog4
blog.anothersite.se
blog.anothersite.se/blog5
blog.yetanothersite.se
blog.yetanothersite.se/blog6

So, how do we manage to get this with just one (1) WordPress Network installation. Problem we thought at first, but after hours of searching, testing domain mapping plugins and asking in forums we found a solution. The plugin Networks for WordPress solved all the problems.

With this plugin you can create several WordPress networks with just one WordPress installation, perfect! :) And it is very easy to install and use. Here are how you proceed.

Point all the domains right

First of we need to point all the domain names we want to use to the same place. This is done with virtual hosts in Apache. I’m using a local installation for this guide

<VirtualHost *:80>
DocumentRoot "/Users/mattias/Sites/Earthpeople/site"
ServerName blog.site.se
ServerAlias blog.site.dk blog.site.no blog.anothersite.se blog.yetanothersite.se
</VirtualHost>

After that is done, restart the Apache server.

Install WordPress and create a WordPress Network

I’m not going to go through this, but here you have a guide for settings up a WP Network.

Setup the Networks for WordPress

First of, install the plugin Networks for WordPress via the Network Admin -> Plugins page. When done you get a new option in the Sites menu named “Networks”. Go there and you will see this page.

Next step is to create all the new networks we need to get all our domains to work.

Network name: The name of the network, can be anything and you can change this at any time.
Domain: Here, put in the domain you want for the network, eg blog.site.dk.
Path: Must be / for this to work
Create a Root site: Leave this checked.
Root site name: This will be the name of you root site, can be anything and you can change this at any time.
New network Preview: Before adding the network, click the “Check Network Settings”, if all checks is green everything is good and you can create the network. If you get a red status here, something is wrong in your Apache vhost settings.

Assigning the blogs

When all the networks we need are created, hover one of the networks in the list and click the “assign sites” link. This will take you to a new page where you select what blog should belong to what network. Repeat this step for all networks and you are almost done.

Get blogs pages and post to work

At first it’s easy to think that this don’t work due to that you can’t access a blogs single posts page or regular pages. You get a 404 page don’t exist error. This is easy fixed. Just go to the dashboard for the blog and update the permalink structure. Yes, this needs to be done on every single blog manually. When done, you have a multiple network site using just one installation of WordPress. This will save you a lot of time and work in the future when managing your network.

Some things to remember thou. Every network has its own dashboard and network admin page so you can have plugins and themes separated from each network. If you want a plugin to be on all networks, install it in the mu-plugins folder.

/ Mattias & Hjalmar

WordPress plugin for fetching hashtag images

Some time ago i made a quick and dirty site for displaying images from a certain Twitter hashtag. Some hours ago i was asked to tweak this into a WordPress plugin, and here we go. This is just tested on my environment, but should be alright on any WordPress 3+ installation on PHP5 with libcurl.

It currently works with twitpic, instagram, yfrog, plixi, flickr. Adding more services is quite easy and can be done on request. URL’s are being curled and cached for 10-12 minutes using the built-in WP_Cache.

The plugin, when enabled, exposes a template tag which you can add to your theme:

<?php
if(function_exists('hashimage')){
 echo '<ul>';
 echo hashimage('hashtag=unicorn&limit=5');
 echo '</ul>';
}
?>

I can’t be bothered add this to the official WordPress repo, but please download it (or fork it!):
https://github.com/EarthPeople/Hashimage-WP

Some notes:
- The Twitter API only returns the latest results when searching on hashtag, so the result set is limited due to this.
- CSS is up to you. Really. I can’t do CSS. It’s magic to me.

Line-out scrobbler – when DJ’ing

When DJ’ing at Debaser Slussen yesterday, we decided to hook up the Line out scrobbler to the DJ mixer. I knew that Echonest wouldn’t be able to resolve all weird stuff we play, but was hoping for at least 70% success rate. Unfortunately we had a resolve rate of about 20%, which make our little hack project quite a disappointment. We also had 3 incorrect resolves under the 7 hour long DJ set.

According to Echonest, the catalogue is only about 150 000 songs, and until this grows substantially, this project will be put on hold.

Here’s a clip of us in action last night:

Here’s the last.fm feed we scrobbled to:
http://www.last.fm/user/fredagsbiten

 

Line-out scrobbler

for years i’ve been trying to hijack music recognition services like shahzam to be able to recognize music. i’ve finally got this working thanks to the fine guys at echonest, who kindly provide a proper api for this. my proof of concept is running on a spare macbook.

here’s how it works on the mac atm:
1. the os x automator runs in a 90 second loop, recording audio with quicktime and then running a cli php script.
2. the php script first converts the recorded .mov file to .mp3 with ffmpeg/lame
3. the php script then runs the echonest binary for music fingerprinting, which generates a json string
4. part of the json string is sent via curl to the echonest service and (hopefully) resolved
5. echonest returns artist, title and a unique id. this id is saved i a recent-log so that the php script can skip a run if it runs 2 times during the same song
6. artist and title are curled back to our lamp-server, where we save all plays in a database (mongodb atm)
7. artist and title can then be sent to any service you wish to interact with

making this projekt was pretty straight forward, except for a minor obstacle which took me a few hours to figure out. it turns out that the echonest binary calls ffmpeg internally, and for some reason automator couldn’t find ffmpeg in it’s $PATH. when i realized this the fix was done in a second, i just needed to make a symlink from the $PATH automator used to where i had ffmpeg locally.

next step: will try this a few days and see how well it performs. if it’s good enough i’ll buy a tiny linux box and give it a pair of rca jacks.

links:
the earth people account on last.fm which we scrobble vinyl to atm
the awesome echonest service

kanjagcykla.nu

Vi som bara cyklar av estetiska skäl är rätt kräsna när det gäller väder. När man saknar skärmar vill man inte att det ska regna. Kanjagcykla.nu är en mobil webbapp som berättar för dig, utifrån var du befinner dig, om du kan cykla eller inte.

I bakgrunden

  • Koppling till yr.no:s API
  • mongoDB med en massa orter i Sverige, med latitud och longitud
  • Ett bibliotek för att hitta position utifrån IP-adress

I förgrunden

  • HTML5 geolocation API, för att hitta din position ännu bättre
  • jQuery

NOW On Roskilde

Now On Roskilde is a mobile application which users easily can add to their homescreen.
It shows what’s on right now, together with related artists playing in the near future.

Since nothing is playing right now (+ the correct feed hasn’t been published yet), the app is pretty worthless at the moment. There is a way to get a preview though, by adding a querystring to the url. These urls below will fetch the Roskilde data feed from 2010.

# thu, july 1st 2010, 19:43
http://nowonroskilde.com/?timestamp=1278013434

# fri, july 2st 2010, 19:43
http://nowonroskilde.com/?timestamp=1278017704

nowonroskilde.com by Earth People is a quick hack put together for the Roskilde Labs competition. Also, feel free to use the php class we put together for this.