Rumblings from the keyboard of Pete Eveleigh,
a web designer and developer based in Gloucester, UK

Searching across multiple categories with ExpressionEngine

Posted: July 29th, 2011 | Author: | Filed under: How to, Web Design | | 1 Comment »

I recently put a new ExpressionEngine site live which featured a search facility that returned results based on multiple category selections. To do this without using a third-party add-on such as Super Search I had to create a little work-around. To be honest, I didn’t think much of this as it seemed quite straightforward but a number of people have asked me how I did it so I thought I would share the information here – mainly because I’m likely to forget an need to do it again at some point.

The premise is thus: We have a number of “products” that are assigned categories. Each product can have more than one category.

We want to be able to search for products based on these categories and return results (for the sake of this demo) that exist in multiple categories.

Our search box might look something like this:

search box

Each drop-down in the search represents one of our categories and is set to return the category id when the form is submitted.

Here is our form’s HTML with EE tags inserted…
<form method="post" action="/search-results/">
<select id="roomtypesel" name="cat[]">
<option value="">Room type</option>
{exp:channel:categories channel="products" category_group="1" style="linear"}
<option value="{category_id}">{category_name}</option>
{/exp:channel:categories}
</select>
<select id="flooringtype" name="cat[]">
<option value="">Flooring type</option>
{exp:channel:categories channel="products" category_group="2" style="linear"}
<option value="{category_id}">{category_name}</option>
{/exp:channel:categories}
</select>
<select id="colourtype" name="cat[]">
<option value="">Colour type</option>
{exp:channel:categories channel="products" category_group="3" style="linear"}
<option value="{category_id}">{category_name}</option>
{/exp:channel:categories}
</select>
<input type="submit" value="Find products" />
</form>

So what we have there are a number of select boxes generated by looping through our chosen category groups and outputting each category as an option.

Note that each select has the same name attribute and we have called that ‘cat[]‘.

When the form is submitted the data from it is POSTed to our ‘search-results’ template and by giving each select the same name attribute, and using the ‘[]‘ we pass the category id of each selection along as values within a single array.

On the search-results template we must enable PHP parsing. This allows us to retrieve the values from the POSTed array and do something with them.

The way in which I do the actual search is to grab the values from the array, combine them into a string and then feed that string into a regular ExpressionEngine channels tag. Because we want to find things that exist in ALL the categories we are interested in we join the category IDs together with a ‘&’.

So within our search-results page we add the following code (including a bit of mild sanitation to ensure we are only getting id numbers)

<?php
// Grab the categories selected from the $_POST
// join them with an ampersand - we are searching for AND matches
$cats = "";
foreach($_POST['cat'] as $cat){
// check we are working with a number
if(is_numeric($cat)){
$cats .= $cat."&";
}
}
// strip the last & off the category string
$cats = substr($cats,0,-1);
?>

Then, within our template we can use the ExpressionEngine Channels tag and feed our string into the category parameter to get the entries that match…

{exp:channel:entries channel="products" dynamic="on" category="<?php echo($cats);?>" orderby="price" sort="asc"}

And that’s it!


How To Create a Facebook Style Password Field with jQuery

Posted: May 20th, 2010 | Author: | Filed under: design, General, How to | Tags: , , , , | No Comments »

Note: This is a pretty old demo I made for someone on a forum somewhere. Since there is never one way to skin a cat I may well do it slightly differently if I did it today.

OK. Facebook, and probably many other sites, employ a method by which they put a form field’s label inside the field itself. This is no biggie, and quite easy to accomplish but what about password fields. By default, in every browser I can think of, the password field type is masked – that is to say the characters you enter are hidden by asterisks or bullet points. This presents a problem since if you shift your label into the field it will be masked.

The solution, therefore, is to change the fieldtype to a plain text field before putting the label into it, then switching to a password field when the user enters something.

Demonstration

Note: this won’t work until I can work out how to include Javascript in a WordPress post.


Why can’t you just make it a plain text field to start with?

For users that are browsing with agents that don’t use Javascript or those that have just blocked it, the password field must still be a password field – so it has to start out that way and be changed by Javascript.

Where my method beats Facebook’s is that if you empty the password field and leave it, the label is restored. Facebook’s effort leaves it blank.

The Code

Let’s start with a simple login form.

<form action="#" method="get" accept-charset="utf-8">
	<p><label>Password</label><input type="password" name="password" id="password" /<p>

	<p><<input type="submit" value="Continue"></p><
</form>

There, told you it was simple.

Now a little sprinking of jQuery. (of course you’ve already included the jQuery library)

$(function(){

	// first we remove label tags from dom
	$('#password').siblings('label').remove();

	// then we add a faux-label inside the field (there's a neater way to do this)
	$('#password').replaceWith('<input type="text" name="password" id="password" value="Password" />');

    // capture the initial click and bind a custom function to it
    $('#password').bind('click',fieldcheck);

	function fieldcheck(el){
		if($(this).attr('type')=='text'){
			$(this).val('');
			$(this).replaceWith('<input type="password" name="password" id="password" />')
			$('#password').focus();
			$('#password').bind('blur',fieldcheck);

		}

		if($(this).attr('type')=='password'){
			if($(this).val()==''){
				$('#password').replaceWith('<input type="text" name="password" id="password" value="Password" />');
				$('#password').bind('click',fieldcheck);
			}
		}
	}

});

And there you have it. A neat, degradeable and, I hope, accessible method to tidy up a password field.

There are a few ways you could improve or expand this, the obvious being to create the text field and faux-label dynamically rather than hardcoding it as I have done for this example.