Chapter 26: Implementing the Search Function

Chapter 26: Implementing the Search Function

With all of our content sections in place, let's hook up ExpressionEngine's builtin search engine. But first, some caveats.

EE's supplied search engine doesn't function like high-end search engines in that it doesn't roll through your site looking at and indexing your rendered pages. I think of that as an "outside-in" search, where a search spider would approach your website from the outside and then crawl through it as a collection of fully-assembled HTML pages.

EE's search is more of an "inside-out" approach - where a submitted search goes to the database level first, then when it finds a match, needs to be told where that database content is supposed to show up on the site. Because of this, there are some inherent limitations that will affect your results:

  • Content that is re-used will not get multiple hits. For example, if your search contained words that were contained in the Latest News sidebar we created above, an outside-in search engine would return hits for every page/section on the site. EE's inside-out search engine will return one hit, mapped to the weblog/comments template for that weblog entry.
  • Content in our Miscellaneous Content Channel cannot be easily configured to be searched. We've used this Channel to hold chunks of text that get reused around the site but they don't have a "home template" for us to map EE to, so it's best to exclude them from the search.
  • Category content cannot be searched. EE's categories don't have a database level mapping to an output template, so any content stored at the category level isn't currently included in the search. You can, however search within categories using the Advanced Search Form.

In spite of these limitations, the native search engine is still often good enough for an EE-based website. Let's go through the implementation and you can decide if it meets your needs or not.

Hooking Up the Search Engine

To fully implement the search function, you'll need to:

  • Make sure all Custom Channel Fields are searchable.
  • Update your embeds/page_header template to include the EE Simple Search Form tags.
  • Create a new Template Group for the search related templates.
  • Create a template to display when there are no results.
  • Create two entries in the Miscellaneous Content Channel to display on the No Results template.
  • Create a template to display when there are results.

Configuring Channel Fields

Each field in ExpressionEngine is configurable to be searchable or not. Before we do anything else, let's run through all of our fields and make sure they are configured properly (see Figure 105 on next page):

  1. Navigate to Admin > Channel Administration > Channel Fields.
  2. For each Field Group click Add/Edit Channel Fields.
  3. For each Field, click its Field Label.
  4. Make sure Is field searchable? is set to Yes.
  5. Repeat for all fields that should be searchable.

It is a good idea to know in advance if you plan to use the EE search engine - then you can configure your fields as you create them rather than having to go back at the end.

Figure 105: Setting Fields to be Searchable

Placing the Search Code

With the fields configured, we can now move onto the coding. Here is the new code for embeds/page_header:

Template Name: embeds/page_header

<div id="title">
 <h1><span class="green"><a
href="{homepage}">{site_name}</a></span></h1>
 <span id="slogan">A Tutorial Series from Trainee.com</span>
</div>
<div id="menu">
 <div class="submit">
 <ul>
 <li><a{if embed:my_location=='home'}
class="selected"{/if} href="{homepage}" ><span>Home</span></
a></li>
 <li><a{if embed:my_location=='about'}
class="selected"{/if} href="{path='about'}"><span>About</
span></a></li>
 <li><a{if embed:my_location=='products'}
class="selected"{/if}
href="{path='products'}"><span>Products</span></a></li>
 <li><a{if embed:my_location=='services'}
class="selected"{/if}
href="{path='services'}"><span>Services</span></a></li>
 <li><a{if embed:my_location=='weblog'}
class="selected"{/if} href="{path='weblog'}"><span>Weblog</
span></a></li>
 <li><a{if embed:my_location=='contact'}
class="selected"{/if} href="{path='contact'}"><span>Contact</
span></a></li>
 </ul>
 </div>
</div>
<div id="subheader">
 <div class="rside">
 <div class="padding">
 <div id="search">
 {exp:search:simple_form
channel="about|home|products|services|weblog"
no_result_page="search/no_results" result_page="search/index"
search_in="everywhere"}
 <p>
 <input type="text"
name="keywords" id="keywords" value="" size="20"
maxlength="250" class="text" />
 <input type="submit"
value="" class="btn1" />
 </p>
 {/exp:search:simple_form}
 </div>
 </div>
 </div>
 <div class="lside">
Implementing the Search Function
296
 <div class="padding">
 {exp:channel:entries
channel="misc_content" limit="1" dynamic="no"
disable="categories|member_data|pagination"
url_title="{embed:the_url_title}" }
 {page_body}
 {/exp:channel:entries}
 </div>
 </div>
</div>

Companion Files: chapter_26/embeds/page_header.txt

Code Notes:

  • With this code we are using the EE Simple Search. Look for the {exp:search:simple_form} tag pair. You can review the Simple Search
    in the EE User Guide:
    http://ellislab.com/expression...simple.html
    There is also an Advanced Search tag set if you want to offer users the ability for more targeted searches.
  • As with any EE tag pair, there are a number of parameters you can configure to meet your needs. The most important parameter is
    search_in="everywhere". This tells ExpressionEngine to search Channel entry titles, fields, and comments. If you don't change this parameter, the
    default behavior is that EE searches in entry titles only.
  • The important thing to remember when integrating the EE Simple Search Form tags with an existing design is you can specify both a form id and
    class using a parameter on the {exp:search:simple_form} tag pair for styling - but one of the fields in the form needs to have name=keywords. This is how the search keywords are actually submitted to ExpressionEngine.

Save the updated code in that template and let's load up the results and no results templates.

Create a Search Template Group

You'll need to create a Template Group for the search-related templates. Name it "search". It will contain two templates - one for results and one for no results.

Create the No Results Template

For these, I typically just create a dedicated template, but, again, use the Miscellaneous Content Channel as a source for the messages that are
displayed. This approach lets my clients control those messages easily.

Create a new template in the search Template Group and name it "no_results".

Here's the code for it - either key it in or grab it from the Companion Files:

Template Name: search/no_results

{embed="embeds/html_header" my_page_title="Search | No
Results"}
 {embed="embeds/page_header" the_url_title="pleasetry-again" my_location=""}
 <div id="maincontent">
 <div id="right_side">
 {snp_latest_news}
 {snp_latest_products}
 </div>
 <div id="left_side">
 {exp:channel:entries
channel="misc_content" disable="pagination|categories|
member_data" url_title="no-results" dynamic="off"}
 <h2 class="underline">{title}</h2>
 {page_body}
 {/exp:channel:entries}
 </div>
 </div>
{snp_footer}

Companion Files: chapter_26/search/no_results.txt

If you scan through the code, you'll see that it:

  • Assumes an entry in the Miscellaneous Content Channel for the section intro entry that appears next to the search bar in the green area. This entry
    needs a URL Title of "please-try-again." Enter some text and save.
  • Assumes another entry in the Miscellaneous Content Channel for the Page Body content. The entry needs a URL Title of no-results. Enter some sort of
    sympathetic "we're sorry" text and save.
  • Passes an empty string to the embeds/page_header for the my_location value. Since these pages don't live in the main navigation, this ensures that
    the main navigation doesn't get an active class applied.

Test

You should now be able to test your no results operation:

  1. Re-visit your site.
  2. Refresh the page to ensure you've got the latest rendered version of the template.
  3. Enter in a non-sensical search term that you know doesn't appear on the site.
  4. You should get the new search/no_results template as a result, with the messages you created in the Miscellaneous Content Weblog:

Figure 106: Displaying the No Results Template

Search Results

With the no results template handled, let's move on now to the search results. We'll be using the Search Results tag, but implementing it in a vastly simplified
fashion that just feels better for this site

Our process here will be:

  • Editing the search/index template.
  • Creating a "results found" entry in the Miscellaneous Content Weblog.
  • Going through our Weblog configurations, make sure the search results path is specified, and the excerpt field is specified.

Edit the Search Template Group Index Template

Here's the code - either key this in or copy it from the Companion Files and place it in the search/index template:

Template Name: search/index

{embed="embeds/html_header" my_page_title="Search | Results"}
 {embed="embeds/page_header" the_url_title="resultsfound" my_location=""}
 <div id="maincontent">
 <div id="right_side">
 {snp_latest_news}
 {snp_latest_products}
 </div>
 <div id="left_side">
 <h2 class="underline">
{exp:search:total_results} Result(s) for {exp:search:keywords}
</h2>
 <ul>
 {exp:search:search_results}
 <li
class="search_results"><strong><a href="{auto_path}">{title}</
a></strong> from <em>{channel}</em>
{excerpt}
</li>
 {/exp:search:search_results}
 </ul>
 </div>
 </div>
{snp_footer}

Companion Files: chapter_26/search/index.txt

Code Notes:

  • By now, you should be able to look at the template code and understand that it's going to be looking for a section intro from the Miscellaneous Content Weblog - with a url_title of "results-found". Take a moment to publish that entry now.
  • The main content area is being driven by the {exp:search:search_results} tag pair. You can review the EE User Guide for this tag pair:
    http://ellislab.com/expression...
    This tag pair largely mimics the {exp:channel:entries} tag pair in its available parameters and variables.
  • We do, however, have some new search-specific variables being displayed on this template. The tag contains a couple of them - one for total hits and one that displays the keywords that were passed to the search:
    {exp:search:total_results} Result(s) for
    {exp:search:keywords}
  • Each result has a couple of search-specific variables in each list item - {auto_path} and {excerpt}. We'll look at those in a moment.
  • Save this template and run a search that you know will be successful.

Search Results

Here's the search results page for my site with three hits:

Figure 107: First Take at Search Results

Initially, this is great! With a couple of quick templates in place, we are getting search results back. Before crossing search off the to-do list, however, let's take a closer look. There are two issues with these results:

  • The results for each hit are inconsistent. I have additional text for the first result, but the second and third only have a title and from value.
  • If you roll over the first link, you'll see the path for the link is: http://localhost/index.php/were-hiring The value after index.php is the url_title of the entry containing the search term. No Template Group or template values are in the link that EE is generating.

These two issues relate to the last two search-specific variables in our code template. Let's explore each.

{auto_path}

This variable is where EE holds that "mapping of database content to template location" I spoke of at the beginning of this chapter. We will be using this variable to create the link for the returned hit; therefore we need to tell ExpressionEngine where this link should point to for each Channel. Do that by:

  1. Navigating to Admin > Channel Administration > Channels.
  2. Going through each Channel and click Edit Preferences.
  3. Selecting Path Settings.
    1. Figure 108: Specifying a Search Result Path
  4. Specifying a path for Search Results URL - this is where EE looks for that database - to - template relationship to build the link that will be placed {auto_path}.
  5. Entering a path and clicking Update.

I've found that you can use variables with these settings to make up parts of the link path - which comes in handy for sites either with long domains/Template Group names or sites that need to move URLs once live. Example, for a Search Results URL for my About section I can enter:

{homepage}/about/

This is undocumented/unsupported behavior for ExpressionEngine, so I can't guarantee that it will always work in the future (but it has so far). If it doesn't work just replace it with the URL to your homepage (ie: http://www.mysite.com/index.php).

Here is a table of the search paths for each Channel in this book and its Search accompanying Results URL setting.

ChannelSearch Results URL
About{homepage}/about/
Home{homepage}/site/
Products{homepage}/products/detail/
Services{homepage}/services/detail/
Weblog{homepage}/weblog/comments/

You'll notice some sections have a deeper URL specified. Basically, the rule of thumb is to link to the most-specific template for each Channel.

In other words, when the section is configured with single-view (detail or comments) template I link there. If there is no single-view template, I link to the multi-entry view, knowing that when the search results are formatted, EE will append the URL Title onto the end of the generated link. This will have the effectively make the multi-view template display only the one entry (that dynamic thing in action).

{excerpt}

Now, let's tackle the {excerpt} variable. ExpressionEngine will pull existing Channel content and populate this variable with it, but we have to tell EE which content field should be used.

To set up this connection:

  1. Navigate to Admin > Channel Administration > Channels.
  2. For each Channel click Edit Preferences.
  3. Choose Administrative Preferences.
  4. The drop-down for Which field should be used for search excerpt? will contain the names of your Custom Channel Fields for this Channel:
    1. Figure 109: Setting the Source Field for the Search Excerpt
  5. Chose the most appropriate field. Typically, I just pick the field that will, on average, have the most content for that Channel. For our Channels above, it's the Page Body field for the Home, About and Services Channels, the Product Description field for Products, and the Full Entry field for the Weblog.

The Results

With those configurations saved, you should be able to use your search engine with terms that you know appear in the content and get results. The results should have text excerpts and links that take you to the specific entry on the site, using the template you've specified.

Figure 110: Second Take at Search Results

Better Results

On the search results template you can use conditionals and "nearly all" of the variables, etc. from the {exp:channel:entries} tag pair, in addition to any Plugins, etc. I have built more complex search results templates with these extra tools that performed a bit better than the defaults, but with our work here you you at least have a starting point.

Not Working?

Not seeing the results you expect? Here are some things you can check:

  • The most common search issues are not getting the search_in="everywhere" parameter specified in the simple search tags, and forgetting to set a field as searchable.
  • Make sure the Template Group and template names that are specified in the {exp:simple:search} tag pair match what you created.
  • Make sure you don't have any typos in your Search Results URL configuration.
  • Make sure you aren't searching for category content.

And Done! Oh, Wait...

We have one more small change before we declare our small business site fully-developed (at least in getting the content sections in place).

Now that the site's main sections are fully implemented, you can go back to the Miscellaneous Content entry that's holding your footer content and update the
links. I got rid of the links to the HTML and CSS validator in order to make room to replicate the main navigation with text links:

Figure 111: Revised Site Footer

If your site copyright jumps down a line after editing the footer links, make sure the entry dates still have the copyright entry as being older than the footer links entry. It needs to render first in the source code for correct formatting.

And with that change - Tada! The main site development is done. Don't call the client yet, though! We still need to look at 404 management, tweak site performance, and finally configure EE for client access.