Concrete5 provides an excellent page builder. It contains many useful blocks and you are allowed to customize any block to match your needs. You are also allowed to create a new block. In this article we create a new block to do AJAX search for pages by tags.

Introduction

Have you ever used search block in Concrete5 and then found only simple textbox to search for pages that’s the most it can do. In this article, we will look how to add autocomplete for search box by tags, filter pages with tags, do search with ajax when type each tag. We will create search_by_tag block to search for pages by tags.

Creating a New Block

This process is fairly straightforward and is documented well in “creating a New Block Type”. All we need is a copy search block from core concrete5 and change folder name to search_by_tag, change table name in controller.php, and then we can add some code on its files.

Adding Autocomplete To Search Box

We will create autocomplete search box with tags by using select2 jquery plugin and get all tags we created in our theme to put it in the search box. we will replace input search box in view.php with this code.

<select id="searchSelectValue" multiple>

<?php

$ak = CollectionAttributeKey::getByHandle('tags');

$akc = $ak->getController();

$ttags = $akc->getOptions();

foreach($ttags as $t) { ?>

<option value="<?php echo $t->value; ?>" <?php echo (in_array($t->value, $query))? 'selected' : '' ?> ><?php echo $t->value; ?></option>

<?php } ?>

</select>

Write below code in view.js to run autocomplete search box with select2 plugin

$( "#searchSelectValue" ).select2();

Filter Pages by Tags

Query Relation

We will add a new option in add/edit form to determine WHERE relation in our query Whether “OR” to get all pages used any of these tags or ”AND” to get only pages used all these tags together.

in form_setup_html.php

<div class="form-group">

<label class="control-label"><?php echo t('Relation') ?></label>

<select class="form-control" name="relation" id="selectRelation">

<option value="OR" <?php echo ($relation == 'OR')? 'selected' : ''?>>OR</option>

<option value="AND" <?php echo ($relation == 'AND')? 'selected' : ''?>>AND</option>

</select>

</div>

we add this code in db.xml to add a new column in btSearchByTags table in database

<field name="relation" type="C" size="255">

<default value="OR" />

</field>

Main Function That Get Result

we will save relation value in controller.php. define $relation variable and fill it in save function

$args['relation'] = $data['relation'];

$this->relation = $args['relation'];

create (action_search_by_tag) function in controller.php to call it with AJAX when type each tag

in this function we will get a query string and convert it to array of tags and filter pages

if (isset($_GET['query'])) {

$ak = CollectionAttributeKey::getByHandle('tags');

$akc = $ak->getController();

$isMultiSelect = $akc->getAllowMultipleValues();

$db = Loader::db();

$criteria = array();

$searchQuery = explode(',', $_GET['query']);

if(is_array($searchQuery)){

foreach ($searchQuery as $v) {

$escapedValue = $v;

if ($isMultiSelect) {

$criteria[] = "(ak_tags LIKE '%

{$escapedValue}

%')";

} else {

$criteria[] = "(ak_tags = '

{$escapedValue}

')";

}

}

$where = '(' . implode($this->relation, $criteria) . ')';

$ipl->filter(false, $where);

}

}

get result and if we have an attribute for pages, we must get it separately because we will use it in javascript file. in this example we will handle thumbnail attribute.

$pagination = $ipl->getPagination();

$results = $pagination->getCurrentPageResults();

$resultImage = array();

$linkProduct = array();

$ih = Loader::helper('image');

foreach ($results as $r) {

$resultJS[$key]["description"] = $r->getCollectionDescription();

$resultJS[$key]["pageName"] = $r->getCollectionName();

$linkProduct[] = $r->getCollectionLink();

$oPage = Page::getById($r->getCollectionID());

$pageName[] = $r->getCollectionName();

$pageDescription[] = $r->getCollectionDescription();

$oThumb = $oPage->getAttribute('thumbnail');

if(isset($oThumb) && $oThumb != false){

$resultImage[] = $ih->getThumbnail($oThumb, 270, 200, true)->src;

}

}

you must handle pagination in AJAX, is there pagination or not? if result more than 10 pages we will show the pagination if result less than or equal 10 pages we will remove the pagination

$paginationView;

if ($pagination->getTotalPages() > 1 && $pagination->haveToPaginate()) {

$showPagination = true;

$paginationView = $pagination->renderDefaultView();

}

Finally, return all variables created in the array to use it in javascript file

$ajaxSearchResult = array('result' => $results, 'pageNames' => $pageName, 'pageDescription' => $pageDescription, 'page_thumb' => $resultImage, 'pagination' => $paginationView, 'product_links' => $linkProduct, 'total_number' => $totalPageNumber);

if(isset($_GET['query']) && !empty($_GET['query'])) {

echo json_encode($ajaxSearchResult);

}else{

echo json_encode('');

}

Handle Search Content By Javascript

Get url and search value to use it in ajax function from two inputs type hidden in view.php file.

searchValue: hold all tags we type in search box

searchURLAjax: hold the link for ajax function

<input name="query" type="hidden" id="searchValue" />

<input type="hidden" id="searchURLAjax" value="<?php echo $view->action('search_by_tag'); ?>" />

Create ajax function when type each tag in search box in view.js

response.page_thumb[i] to get page thumbnail

response.result[i].pageName to get page name

response.product_links[i] to get page link

response.result[i].description to get page description

$( "#searchSelectValue" ).change(function(){

var url = $('#searchURLAjax').val();

queryData = $('#searchValue').val();

if(queryData == ''){

queryData = 'nonetaghere';

}

$.ajax({

type : "get",

dataType : "json",

url : url,

data: {

query: queryData,

},

success: function(response){

// do some code

}

});

});

when success we will remove current content for pages and put the new page list.

$(".formcontentTags").empty();

if(response.result.length === 0){

var wholeSearchContent = '';

}else{

var wholeSearchContent = '<div class="searchList">';

}

var searchList = '';

var image = '';

var description = '';

if(response.page_thumb[i] != null){

// response.page_thumb[i] to get page thumbnail

// response.result[i].pageName to get page name

var image =

'<div class="SearchImage">' +

'<a href="' + response.product_links[i] + '">'+

'<img src="'+ response.page_thumb[i] + '" alt="' + response.pageNames[i] + '">' +

'</a>' +

'</div>';

}else{

image = '';

}

for(var i = 0; i< response.result.length; i++){

// response.product_links[i] to get page link

// response.pageDescription[i] to get page description

if(response.pageDescription[i].length > 100 ){

description = '<a href="' + response.product_links[i] + '">'+ response.pageDescription[i].substring(0, 100) +'…</a>';

}else{

description = '<a href="' + response.product_links[i] + '">'+ response.pageDescription[i].substring(0, 100) + '</a>';

}

searchList +=

'<div class="searchSingle">' +

image +

'<div class="singleSearchContent">' +

description +

'</div>' +

'</div>' +

'<div class="searchSeparator"></div>';

}

wholeSearchContent += searchList + '</div>';

$('.formcontentTags').append(wholeSearchContent);

handle pagination links because it will get with wrong page links. we will remove page links and create it again with a right links.

if(response.pagination != null){

$('.ccm-pagination-wrapper').remove();

$('.searchList').append(response.pagination);

var searchURL = window.location.href;

var ajaxsearchURL = searchURL.substring(0,searchURL.indexOf("?"));

$('.ccm-pagination-wrapper li a').each(function(){

wrongSearchURL = $(this).attr('href');

querySearchURL = wrongSearchURL.substring(wrongSearchURL.indexOf("?"));

$(this).attr('href', ajaxsearchURL + querySearchURL);

});

}else{

$('.ccm-pagination-wrapper').remove();

}

Now you can install your block from block type page and use it in your website to search for all page by tags using ajax.

Download search_by_tags Block

You can download search_by_tags block from github, install it from block type page, and then you can use it https://github.com/elgreatly/search-by-tag-block

make sure the name of block’s folder is search_by_tags instead of search_by_tag_block_master

Summary

Add AJAX to search block is a quick way to search for pages without loading current page. Add autocomplete to search box and search for pages by attributes are very useful to make a search more easier. You can customize your block to search for pages with any way you want according to your needs.