I am a jack of all trades. Excepting those trades I do not like. I am a web developer of simple, reliable solutions to problems.

Switching WordPress Databases and Git Branches Simultaneously

I’ve recently switched to a rather rad workflow involving a local copy of our website run through MAMP using a git repository.

We’ve recently started working on a bigger set of changes that require a feature branch. But, these changes also will require WordPress to be upgraded to 3.3, requiring database changes.  Making it impossible to use the same database.

I was able to come up with this nifty technique for determining which DB to use.

$stringfromfile = file('.git/HEAD', FILE_USE_INCLUDE_PATH);
$stringfromfile = $stringfromfile[0]; //get the string from the array
$explodedstring = explode("/", $stringfromfile); //separate out by the "/" in the string
$branchname = trim($explodedstring[2]); //get the one that is always the branch name
 
// ** MySQL settings - You can get this info from your web host ** //
if($branchname == "master")
{
	/** The name of the database for WordPress */
	define('DB_NAME', 'wordpress_local');
}
else
{
	define('DB_NAME', 'wordpress_new');
}

That’s all there is to it. It works flawlessly.

Happy coding.

Adding Autocomplete Search To Shopp

This week I tackled another long term todo: autocomplete. It was a fun project with the right amount of difficulties and surprises along the way.

To make this possible, I used jQuery Marco Polo, a very nice autocomplete plugin available here: https://github.com/jstayton/jquery-marcopolo

I had to modify it to make it work exactly how I wanted, but it does the job.

Basically, jQuery Marco Polo takes input into a search field and runs it against a URL in realtime using AJAX. It expects a JSON response from this URL. It has many options on how to display items and what to do when items are clicked.

The first challenge was getting the results into JSON. To do this, I created a function to intercept requests that match a certain format: /q=?somesearchterm&ajax=true

Pretty basic. Here is the function:

add_action('wp', 'ajax_autocomplete_search', 1000);
 
function ajax_autocomplete_search() {
	if(isset($_GET['q']) && isset($_GET['ajax']) && $_GET['ajax'] == "true" && !empty($_GET['q']))
	{
		$q = $_GET['q'];
		shopp('catalog','search-products',"load=true&search=$q");
 
		if(shopp('category','has-products')) 
		{
			global $Shopp;
			$filter_cat = $_GET['category'];
 
			$results = array();
			$count = 0;
			$used_products = array();
 
			while(shopp('category','products'))
			{
				if($count == 3) continue;
 
				$product_id = shopp('product','id','return=true');
 
				shopp('catalog','product',"id=$product_id&load=true");
				require(TEMPLATEPATH.'/name-vars.php');
 
				if(!in_array($first_name, $used_products))
				{	
					$used_products[] = $first_name;
 
					ob_start();
					shopp('product', 'coverimage', 'width=60&height=60');
					$image_tag = ob_get_clean();
 
					$summary = shopp('product','summary','return=true');
					$slug = shopp('product','slug','return=true');
 
					if(strlen($summary) > 90)
					{
						$summary = substr($summary,0,strpos($summary,' ',90))."…";
					}
					else
					{
						$summary = $summary;
					}
 
					if(shopp('product','in-category',"name=$filter_cat") || (!isset($filter_cat) || $filter_cat == "Everything"))
					{
						$results[] = array('name' => $first_name, 'summary' => $summary, 'image' => $image_tag, 'slug' => $slug); 
					}
					$count++;
				}
			}
 
			if(count($Shopp->Category->products) > 3 && count($results) == 3)
			{
				$results[] = array('name' => 'footer', 'summary' => 'See All Search Results', 'search' => $_GET['s'], 'category' => $_GET['category']);
			}
 
			if(count($results) > 0)
			{
				echo json_encode($results);
			}
		}
		die;
	}
}

Now, you’re going to notice right away that there are a lot of specific things going on here that cater to the specific way I implemented this. For instance, I only show the first 3 results with a “See All Results” footer. This also assumes that you, like me, have implemented a category filtered search as described here. There is also some custom stuff in there based on the way we name things. (that’s the name-vars.php and $first_name stuff…I won’t go into that)

No matter. You should be able to see what I’m doing and modify it as necessary.

So that, with some modification, should throw some nice JSON responses out.

Other than that, I just used the following JavaScript:

jQuery("#category-dropdown").change(function() {
				jQuery('input.search').marcoPolo({
				  url: '/?wp-minify-off=1&category=' + jQuery("#category-dropdown").val() + '&x=0&y=0&ajax=true',
				  param: 'q',
				  formatItem: function (data, $item) {
				  	if(data.name != "footer")
				  	{
				   		return '<h2>' + data.name + '</h2>' + data.image + '<p>' + data.summary + '</p>';
				   	}
				   	else
				   	{
				   		$item.addClass('footer');
				   		return data.summary;
				   	}
				  },
				  onSelect: function (data, $item) {
				  	if(data.name != "footer")
				  	{
				    	window.location = '/shop/' + data.slug;
				    }
				    else
				    {
				    	window.location = '/?s=' + data.search + '&category=' + data.category + '&catalog=true';
				    }
				  },
				  formatNoResults: function (q, $item) {
				  	$item.addClass("mp_selectable");
				  	$item.click(function() {
				  		window.location = '/?s=' + q + '&category=Everything&catalog=true';
				  	});
				  	return '<em>No results for <strong>' + q + '</strong> in ' + jQuery("#category-dropdown").val() + '.<br /><br /> Try your search again in Everything?</em>';
				  }
				});
			});
 
			jQuery("#category-dropdown").change();

Again, not the briefest example. It’s either show all or show nothing. You’re going to have to work around my particular usage of all of these things. I instantiate Marco Polo when the dropdown is changed because the search URL depends on the drop down selection.

I modified Marco Polo to get rid of it’s hijacking of the ENTER key, etc. I just removed all of the key binding because it didn’t support the way I wanted to use it.

You can see this fully working here: Moore and Giles, Inc.

Type in Brompton, for example.

That’s it. Feel free to ask questions.
Clif