aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>2009-11-06 01:46:36 +0000
committerbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>2009-11-06 01:46:36 +0000
commit5d96c9b12fe0ea953ef95af952e588a1898ef1fc (patch)
tree0d4555c86b3d5c744f46cc37e0b7b45a106017e6
parent06169d33aae4d27129c77baaee9ecb064683e576 (diff)
downloadelgg-5d96c9b12fe0ea953ef95af952e588a1898ef1fc.tar.gz
elgg-5d96c9b12fe0ea953ef95af952e588a1898ef1fc.tar.bz2
Updated search for FTS.
git-svn-id: http://code.elgg.org/elgg/trunk@3619 36083f99-b078-4883-b0ff-0f9b5a30f544
-rw-r--r--mod/search/index.php296
-rw-r--r--mod/search/start.php160
-rw-r--r--mod/search/views/default/search/css.php23
-rw-r--r--mod/search/views/default/search/listing.php67
-rw-r--r--mod/search/views/default/search/startblurb.php8
-rw-r--r--mod/search/views/default/search/tags/listing.php55
6 files changed, 474 insertions, 135 deletions
diff --git a/mod/search/index.php b/mod/search/index.php
index 7cbf6121c..30f33f9f1 100644
--- a/mod/search/index.php
+++ b/mod/search/index.php
@@ -1,6 +1,136 @@
<?php
- /** Main search page */
+// $search_type == all || entities || trigger plugin hook
+$search_type = get_input('search_type', 'all');
+$query = sanitise_string(get_input('query', get_input('tag')));
+
+// get limit and offset. override if on search dashboard, where only 2
+// of each most recent entity types will be shown.
+$limit = ($search_type == 'all') ? 2 : get_input('limit', 10);
+$offset = ($search_type == 'all') ? 0 : get_input('offset', 0);
+
+$type = get_input('type', '');
+$subtype = get_input('subtype', '');
+$owner_guid = get_input('owner_guid', NULL);
+$friends = (int)get_input('friends', 0);
+
+// set up search params
+$params = array(
+ 'query' => $query,
+ 'offset' => $offset,
+ 'limit' => $limit,
+ 'search_type' => $search_type,
+ 'type' => $type,
+ 'subtype' => $subtype,
+ 'tag_type' => $tag_type,
+ 'owner_guid' => $owner_guid,
+ 'friends' => $friends
+);
+
+$results_html = '';
+if ($search_type == 'entities' || $search_type == 'all') {
+ $types = get_registered_entity_types();
+
+ // to pass the correct search type to the views
+ $params['search_type'] = 'entities';
+
+ // foreach through types.
+ // if a plugin returns FALSE for subtype ignore it.
+ // if a plugin returns NULL or '' for subtype, pass to generic type search function.
+ // if still NULL or '' or empty(array()) no results found. (== don't show??)
+ foreach ($types as $type => $subtypes) {
+ if (is_array($subtypes) && count($subtypes)) {
+ foreach ($subtypes as $subtype) {
+ $params['subtype'] = $subtype;
+ $params['type'] = $type;
+
+ $entities = trigger_plugin_hook('search', "$type:$subtype", $params, NULL);
+ if ($entities === FALSE) {
+ // someone is saying not to display these types in searches.
+ continue;
+ } elseif (is_array($entities) && !count($entities)) {
+ // no results, but results searched in hook.
+ } elseif (!$entities) {
+ // no results and not hooked. use default type search.
+ // don't change the params here, since it's really a different subtype.
+ // Will be passed to elgg_get_entities().
+ $results = trigger_plugin_hook('search', $type, $params, array());
+ }
+
+ if (is_array($results['entities']) && $results['count']) {
+ $results_html .= search_get_listing_html($results['entities'], $results['count'], $params);
+ }
+ }
+ }
+
+ // pull in default type entities with no subtypes
+ // @todo this might currently means "all entities regardless of subtype"
+ $params['type'] = $type;
+ $params['subtype'] = 0;
+
+ $results = trigger_plugin_hook('search', $type, $params, array());
+ if ($results === FALSE) {
+ // someone is saying not to display these types in searches.
+ continue;
+ }
+
+ if (is_array($results['entities']) && $results['count']) {
+ $results_html .= search_get_listing_html($results['entities'], $results['count'], $params);
+ }
+ }
+}
+
+// call custom searches
+if ($search_type == 'all' || $search_type != 'entities') {
+ // get custom search types
+ $types = trigger_plugin_hook('search_types', 'get_types', $params, array());
+
+ if (is_array($types)) {
+ foreach ($types as $type) {
+ $params['search_type'] = $type;
+ unset($params['subtype']);
+
+ $results = trigger_plugin_hook('search', $type, $params, array());
+
+ if ($results === FALSE) {
+ // someone is saying not to display these types in searches.
+ continue;
+ }
+
+ if (is_array($results['entities']) && $results['count']) {
+ $results_html .= search_get_listing_html($results['entities'], $results['count'], $params);
+ }
+ }
+ }
+}
+
+//if ($search_type !== 'all') {
+// var_dump('here');
+// $entities = trigger_plugin_hook('search', $search_type, '', $return);
+//}
+/*
+
+call search_section_start to display long bar with types and titles
+call search
+
+
+
+*/
+
+$layout = elgg_view_layout('single_column', '', $results_html);
+
+page_draw($title, $layout);
+
+
+
+
+
+
+
+return;
+
+
+/** Main search page */
global $CONFIG;
@@ -8,28 +138,25 @@ $tag = get_input('tag');
$offset = get_input('offset', 0);
$viewtype = get_input('search_viewtype','list');
if ($viewtype == 'gallery') {
- $limit = get_input('limit', 12); // 10 items in list view
+ $limit = get_input('limit', 12); // 10 items in list view
} else {
- $limit = get_input('limit', 10); // 12 items in gallery view
+ $limit = get_input('limit', 10); // 12 items in gallery view
}
$searchtype = get_input('searchtype', 'all');
-$object_type = get_input('object_type', '');
+$type = get_input('type', '');
$subtype = get_input('subtype', '');
$owner_guid = get_input('owner_guid', '');
$tagtype = get_input('tagtype', '');
$friends = (int)get_input('friends', 0);
+$title = sprintf(elgg_echo('searchtitle'), $tag);
-
-$title = sprintf(elgg_echo('searchtitle'), $tag);
-
-
-if (substr_count($owner_guid,',')) {
- $owner_guid_array = explode(",",$owner_guid);
+if (substr_count($owner_guid, ',')) {
+ $owner_guid_array = explode(',', $owner_guid);
} else {
$owner_guid_array = $owner_guid;
}
if ($friends > 0) {
- if ($friends = get_user_friends($friends,'',9999)) {
+ if ($friends = get_user_friends($friends, '', 9999)) {
$owner_guid_array = array();
foreach($friends as $friend) {
$owner_guid_array[] = $friend->guid;
@@ -40,107 +167,110 @@ if ($friends > 0) {
}
// Set up submenus
-if ($object_types = get_registered_entity_types()) {
-
- foreach($object_types as $ot => $subtype_array) {
- if (is_array($subtype_array) && sizeof($subtype_array))
+if ($types = get_registered_entity_types()) {
+ foreach($types as $ot => $subtype_array) {
+ if (is_array($subtype_array) && count($subtype_array)) {
foreach($subtype_array as $object_subtype) {
$label = 'item:' . $ot;
- if (!empty($object_subtype)) $label .= ':' . $object_subtype;
- add_submenu_item(elgg_echo($label), $CONFIG->wwwroot . "pg/search/?tag=". urlencode($tag) ."&subtype=" . $object_subtype . "&object_type=". urlencode($ot) ."&tagtype=" . urlencode($md_type) . "&owner_guid=" . urlencode($owner_guid));
+ if (!empty($object_subtype)) {
+ $label .= ':' . $object_subtype;
+ }
+
+ $data = http_build_query(array(
+ 'tag' => urlencode($tag),
+ 'subtype' => $object_subtype,
+ 'type' => urlencode($ot),
+ //'tagtype' => urlencode($md_type),
+ 'owner_guid' => urlencode($owner_guid)
+ ));
+
+ $url = "{$CONFIG->wwwroot}pg/search/?$data";
+
+ add_submenu_item(elgg_echo($label), $url);
}
+ }
}
- add_submenu_item(elgg_echo('all'), $CONFIG->wwwroot . "pg/search/?tag=". urlencode($tag) ."&owner_guid=" . urlencode($owner_guid));
-
+
+ $data = http_build_query(array(
+ 'tag' => urlencode($tag),
+ 'owner_guid' => urlencode($owner_guid)
+ ));
+
+ add_submenu_item(elgg_echo('all'), "{$CONFIG->wwwroot}pg/search/?$data");
+}
+
+// pull in search types for external or aggregated searches.
+if ($search_types = trigger_plugin_hook('search', 'types', '', NULL, array())) {
+
}
$body = '';
if (!empty($tag)) {
+ // start with blank results.
+ $results = array(
+ 'entities' => array(),
+ 'total' => 0
+ );
+
+ // do the actual searchts
+ $params = array(
+ 'tag' => $tag,
+ 'offset' => $offset,
+ 'limit' => $limit,
+ 'searchtype' => $searchtype,
+ 'type' => $type,
+ 'subtype' => $subtype,
+ 'tagtype' => $tagtype,
+ 'owner_guid' => $owner_guid_array
+ );
+
+ $results = trigger_plugin_hook('search', 'entities', $params, $results);
- // blank the results to start off
- $results = new stdClass();
- $results->entities = array();
- $results->total = 0;
-
- // do the actual search
- $results = trigger_plugin_hook('search:entities', '', array('tag' => $tag,
- 'offset' => $offset,
- 'limit' => $limit,
- 'searchtype' => $searchtype,
- 'object_type' => $object_type,
- 'subtype' => $subtype,
- 'tagtype' => $tagtype,
- 'owner_guid' => $owner_guid_array
- ),
- $results);
-
- /* // this piece is for future work, to setup submenus for searchtypes
- $searchtypes = trigger_plugin_hook('search:types', '', NULL, array());
- add_submenu_item(elgg_echo('search:type:all'),
- $CONFIG->wwwroot . "pg/search/?tag=". urlencode($tag) ."&searchtype=all");
-
- foreach ($searchtypes as $st) {
- add_submenu_item(elgg_echo('search:type:' . $st),
- $CONFIG->wwwroot . "pg/search/?tag=". urlencode($tag) ."&searchtype=" . $st);
- }
- */
-
-
- if (empty($objecttype) && empty($subtype)) {
- $title = sprintf(elgg_echo('searchtitle'),$tag);
+ if (empty($type) && empty($subtype)) {
+ $title = sprintf(elgg_echo('searchtitle'),$tag);
} else {
- if (empty($objecttype)) $objecttype = 'object';
- $itemtitle = 'item:' . $objecttype;
- if (!empty($subtype)) $itemtitle .= ':' . $subtype;
+ if (empty($type)) {
+ $type = 'object';
+ }
+ $itemtitle = 'item:' . $type;
+ if (!empty($subtype)) {
+ $itemtitle .= ':' . $subtype;
+ }
$itemtitle = elgg_echo($itemtitle);
$title = sprintf(elgg_echo('advancedsearchtitle'),$itemtitle,$tag);
}
-
-
-
-
- //print_r($results);
$body .= elgg_view_title($title); // elgg_view_title(sprintf(elgg_echo('searchtitle'),$tag));
// call the old (now-deprecated) search hook here
$body .= trigger_plugin_hook('search','',$tag, '');
- $body .= elgg_view('search/startblurb', array('tag' => $tag));
+ $body .= elgg_view('search/startblurb', array('query' => $query));
if ($results->total > 0) {
-
-
- $body .= elgg_view('search/entity_list', array('entities' => $results->entities,
- 'count' => $results->total,
- 'offset' => $offset,
- 'limit' => $limit,
- 'baseurl' => $_SERVER['REQUEST_URI'],
- 'fullview' => false,
- 'context' => 'search',
- 'viewtypetoggle' => true,
- 'viewtype' => $viewtype,
- 'pagination' => true
- ));
+ $body .= elgg_view('search/entity_list', array(
+ 'entities' => $results->entities,
+ 'count' => $results->total,
+ 'offset' => $offset,
+ 'limit' => $limit,
+ 'baseurl' => $_SERVER['REQUEST_URI'],
+ 'fullview' => false,
+ 'context' => 'search',
+ 'viewtypetoggle' => true,
+ 'viewtype' => $viewtype,
+ 'pagination' => true
+ ));
} else {
- $body .= elgg_view('page_elements/contentwrapper', array('body' => elgg_echo('search:noresults')));
+ $body .= elgg_view('page_elements/contentwrapper', array('body' => elgg_echo('search:noresults')));
}
-
-
-
elgg_view_entity_list($results->entities, count($results->entities), 0, count($results->entities), false);
} else {
// if no tag was given, give the user a box to input a search term
$body .= elgg_view_title(elgg_echo('search:enterterm'));
$body .= elgg_view('page_elements/contentwrapper', array('body' => '<div>' . elgg_view('page_elements/searchbox') . '</div>'));
-
-
}
-$layout = elgg_view_layout('two_column_left_sidebar','',$body);
-
-
-page_draw($title, $layout);
+$layout = elgg_view_layout('two_column_left_sidebar','',$body);
-?> \ No newline at end of file
+page_draw($title, $layout); \ No newline at end of file
diff --git a/mod/search/start.php b/mod/search/start.php
index 24b038c7a..4bd342285 100644
--- a/mod/search/start.php
+++ b/mod/search/start.php
@@ -1,8 +1,8 @@
<?php
- /**
+/**
* Elgg core search.
- *
+ *
* @package Elgg
* @subpackage Core
* @author Curverider Ltd <info@elgg.com>, The MITRE Corporation <http://www.mitre.org>
@@ -14,21 +14,13 @@
*
*/
function search_init() {
- global $CONFIG;
-
// page handler for search actions and results
register_page_handler('search','search_page_handler');
- // hook into the search callback to use the metadata system (this is the part that will go away!)
- register_plugin_hook('search:entities', 'all', 'search_original_hook');
-
- // list of available search types should include our base parts
- register_plugin_hook('searchtypes', 'all', 'search_base_search_types_hook');
-
// add in CSS for search elements
extend_view('css', 'search/css');
}
-
+
/**
* Page handler for search
*
@@ -36,9 +28,9 @@ function search_init() {
*/
function search_page_handler($page) {
global $CONFIG;
-
+
if(!get_input('tag')) {
- set_input('tag', $page[0]);
+ set_input('tag', $page[0]);
}
include_once($CONFIG->path . "mod/search/index.php");
@@ -47,13 +39,17 @@ function search_page_handler($page) {
/**
* Core search hook.
* Returns an object with two parts:
- * ->entities: an array of instantiated entities that have been decorated with
+ * ->entities: an array of instantiated entities that have been decorated with
* volatile "search" data indicating what they matched. These are
* the entities to be displayed to the user on this page.
* ->total: total number of entities overall. This function can update this
* limit to ask for more pages in the pagination.
*/
function search_original_hook($hook, $type, $returnvalue, $params) {
+ global $CONFIG;
+
+ var_dump($CONFIG->hooks);
+
$tag = $params['tag'];
$offset = $params['offset']; // starting page
$limit = $params['limit']; // number per page
@@ -63,9 +59,21 @@ function search_original_hook($hook, $type, $returnvalue, $params) {
$owner_guid = $params['owner_guid'];
$tagtype = $params['tagtype'];
- $count = get_entities_from_metadata($tagtype, elgg_strtolower($tag), $object_type, $subtype, $owner_guid, $limit, $offset, "", 0, TRUE, FALSE);
+ $count = get_entities_from_metadata($tagtype, elgg_strtolower($tag), $object_type, $subtype, $owner_guid, $limit, $offset, "", 0, TRUE, FALSE);
$ents = get_entities_from_metadata($tagtype, elgg_strtolower($tag), $object_type, $subtype, $owner_guid, $limit, $offset, "", 0, FALSE, FALSE);
+// $options = array(
+// 'metadata_name_value_pair' => array('name' => $params['tagtype'], 'value' => $params['tag'], 'case_sensitive' => false),
+// 'offset' => $params['offset'],
+// 'limit' => $params['limit'],
+// 'type' => $params['object_type'],
+// 'subtype' => $params['subtype'],
+// 'owner_guid' => $params['owner_guid']
+// );
+//
+// $count = elgg_get_entities_from_metadata(array_merge($options, array('count' => TRUE)));
+// $entities = elgg_get_entities_from_metadata($options);
+
/*
* Foreach entity
* get the metadata keys
@@ -99,6 +107,26 @@ function search_original_hook($hook, $type, $returnvalue, $params) {
}
/**
+ * Provides default search for registered entity subtypes.
+ * Entity types should be dealt with in the entity classes. (Objects are an exception).
+ *
+ * @param unknown_type $hook
+ * @param unknown_type $type
+ * @param unknown_type $returnvalue
+ * @param unknown_type $params
+ * @return unknown_type
+ */
+function search_registered_entities($hook, $type, $returnvalue, $params) {
+ $entity_types = get_registered_entity_types();
+ foreach ($entity_types as $type => $subtypes) {
+ if (is_array($subtypes) && count($subtypes)) {
+
+ }
+
+ }
+}
+
+/**
* return our base search types (right now, we have none)
*/
function search_base_search_types_hook($hook, $type, $returnvalue, $params) {
@@ -109,8 +137,104 @@ function search_base_search_types_hook($hook, $type, $returnvalue, $params) {
return $returnvalue;
}
-/** Register init system event **/
-register_elgg_event_handler('init','system','search_init');
+/**
+ * Returns a matching string with $context amount of context, optionally
+ * surrounded by $before and $after.
+ *
+ * If no match is found, restricts string to $context*2 starting from strpos 0.
+ *
+ * @param str $haystack
+ * @param str $needle
+ * @param str $before
+ * @param str $after
+ * @param str $context
+ * @return str
+ */
+function search_get_relevant_substring($haystack, $needle, $before = '', $after = '', $context = 75) {
+ $haystack = strip_tags($haystack);
+ $needle = strip_tags($needle);
+
+ $pos = strpos(strtolower($haystack), strtolower($needle));
+
+ if ($pos === FALSE) {
+ $str = substr($haystack, 0, $context*2);
+ if (strlen($haystack) > $context*2) {
+ $str .= '...';
+ }
+
+ return $str;
+ }
+
+ $start_pos = $pos - $context;
+
+ if ($start_pos < 0) {
+ $start_pos = 0;
+ }
+
+ // get string from -context to +context
+ $matched = substr($haystack, $start_pos, $context*2);
+
+ // add elipses to front.
+ if ($start_pos > 0) {
+ $matched = "...$matched";
+ }
+
+ // add elipses to end.
+ if ($start_pos + $context < strlen($haystack)) {
+ $matched = "$matched...";
+ }
+
+ // surround if needed
+ if ($before || $after) {
+ $matched = str_ireplace($needle, $before . $needle . $after, $matched);
+ }
+
+ return $matched;
+}
+
+
+
+function search_get_listing_html($entities, $count, $params) {
+ if (!is_array($entities) || !$count) {
+ return FALSE;
+ }
+
+ $view_order = array();
+
+ // check if there's a special search view for this type:subtype
+ if (isset($params['type']) && $params['type'] && isset($params['subtype']) && $params['subtype']) {
+ $view_order[] = "search/{$params['type']}/{$params['subtype']}/listing";
+ }
+
+ // also check for the default type
+ if (isset($params['type']) && $params['type']) {
+ $view_order[] = "search/{$params['type']}/listing";
+ }
+
+ // check search types
+ if (isset($params['search_type']) && $params['search_type']) {
+ $view_order[] = "search/{$params['search_type']}/listing";
+ }
+
+ // finally default to a search listing default
+ $view_order[] = "search/listing";
+
+ $vars = array(
+ 'entities' => $entities,
+ 'count' => $count,
+ 'params' => $params
+ );
+
+ foreach ($view_order as $view) {
+ if (elgg_view_exists($view)) {
+ return elgg_view($view, $vars);
+ }
+ }
+
+ return FALSE;
+}
+
+/** Register init system event **/
-?>
+register_elgg_event_handler('init','system','search_init'); \ No newline at end of file
diff --git a/mod/search/views/default/search/css.php b/mod/search/views/default/search/css.php
index 27b532727..936fe5c9d 100644
--- a/mod/search/views/default/search/css.php
+++ b/mod/search/views/default/search/css.php
@@ -1,4 +1,4 @@
-.searchtype {
+.searchtype {
background: #FFFACD;
color: black;
}
@@ -9,8 +9,21 @@ padding: 4px;
margin: 6px;
}
+.searchListing {
+ display: block;
+ margin-bottom: 2em;
+}
+
+.searchMatch {
+ background-color: #FFFF66;
+}
+
+.searchTitle {
+ text-decoration: underline;
+}
+
#searchform input.search_input {
- -webkit-border-radius: 4px;
+ -webkit-border-radius: 4px;
-moz-border-radius: 4px;
background-color:#FFFFFF;
border:1px solid #BBBBBB;
@@ -23,7 +36,7 @@ margin: 6px;
height:12px;
}
#searchform input.search_submit_button {
- -webkit-border-radius: 4px;
+ -webkit-border-radius: 4px;
-moz-border-radius: 4px;
color:#333333;
background: #cccccc;
@@ -44,7 +57,7 @@ margin: 6px;
.search_listing {
display: block;
- -webkit-border-radius: 8px;
+ -webkit-border-radius: 8px;
-moz-border-radius: 8px;
background:white;
margin:0 10px 5px 10px;
@@ -58,7 +71,7 @@ margin: 6px;
/* override the entity container piece */
.search_listing .entity_listing {
- -webkit-border-radius: 0px;
+ -webkit-border-radius: 0px;
-moz-border-radius: 0px;
background: transparent;
margin: 0;
diff --git a/mod/search/views/default/search/listing.php b/mod/search/views/default/search/listing.php
index e3ad91ba8..2ed657547 100644
--- a/mod/search/views/default/search/listing.php
+++ b/mod/search/views/default/search/listing.php
@@ -1,35 +1,54 @@
<?php
+/**
+ * Elgg search listing
+ *
+ * @package Elgg
+ * @subpackage Core
+ * @author Curverider Ltd
+ * @link http://elgg.org/
+ */
+?>
- /**
- * Elgg search listing
- *
- * @package Elgg
- * @subpackage Core
+<div class="search_listing">
- * @author Curverider Ltd
+<?php
+$entities = $vars['entities'];
+$count = $vars['count'];
- * @link http://elgg.org/
- */
+if (!is_array($vars['entities']) || !count($vars['entities'])) {
+ return FALSE;
+}
-?>
+$title_str = elgg_echo("item:{$vars['params']['type']}:{$vars['params']['subtype']}");
+$body = elgg_view_title($title_str);
- <div class="search_listing">
-
-<?php
-
-echo $vars['entity_view'];
+echo elgg_view('page_elements/contentwrapper', array('body' => $body));
-if ($vars['search_types'] && is_array($vars['search_types'])) {
- echo '<div class="searchtypes">' . elgg_echo('search:matched');
- foreach ($vars['search_types'] as $st) {
- echo '<span class="searchtype">' . elgg_echo($st) . '</span> ';
+foreach ($entities as $entity) {
+ if ($owner = $entity->getOwnerEntity()) {
+ $owner_icon = $owner->getIcon('tiny');
+ $icon = "<img src=\"$owner_icon\" />";
+ } else {
+ $icon = '';
}
- echo '</div>';
-
+ $title = $entity->getVolatileData('search_matched_title');
+ $description = $entity->getVolatileData('search_matched_description');
+ $url = $entity->getURL();
+ $title = "<a href=\"$url\">$title</a>";
+ $tc = $entity->time_created;
+ $tu = $entity->time_updated;
+ $time = friendly_time(($tu > $tc) ? $tu : $tc);
+
+ echo <<<___END
+<span class="searchListing">
+ <h3 class="searchTitle">$title</h3>
+ <span class="searchDetails">
+ <span class="searchDescription">$description</span><br />
+ $icon - $time - <a href="">More $title_str</a> -
+ </span>
+</span>
+___END;
}
-
-
-
?>
- </div>
+</div> \ No newline at end of file
diff --git a/mod/search/views/default/search/startblurb.php b/mod/search/views/default/search/startblurb.php
index 0115438f2..82d2d62d1 100644
--- a/mod/search/views/default/search/startblurb.php
+++ b/mod/search/views/default/search/startblurb.php
@@ -7,9 +7,7 @@
*/
?>
<div class="contentWrapper">
- <?php
-
- echo sprintf(elgg_echo("tag:search:startblurb"),$vars['tag']);
-
- ?>
+<?php
+ echo sprintf(elgg_echo("tag:search:startblurb"), $vars['query']);
+?>
</div> \ No newline at end of file
diff --git a/mod/search/views/default/search/tags/listing.php b/mod/search/views/default/search/tags/listing.php
new file mode 100644
index 000000000..a5a33c4a4
--- /dev/null
+++ b/mod/search/views/default/search/tags/listing.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Elgg search listing
+ *
+ * @package Elgg
+ * @subpackage Core
+ * @author Curverider Ltd
+ * @link http://elgg.org/
+ */
+?>
+
+<div class="search_listing">
+
+<?php
+$entities = $vars['entities'];
+$count = $vars['count'];
+
+if (!is_array($vars['entities']) || !count($vars['entities'])) {
+ return FALSE;
+}
+
+$title_str = elgg_echo("item:{$vars['params']['type']}:{$vars['params']['subtype']}");
+$body = elgg_view_title(elgg_echo('tags'));
+
+echo elgg_view('page_elements/contentwrapper', array('body' => $body));
+
+foreach ($entities as $entity) {
+ if ($owner = $entity->getOwnerEntity()) {
+ $owner_icon = $owner->getIcon('tiny');
+ $icon = "<img src=\"$owner_icon\" />";
+ } else {
+ $icon = '';
+ }
+ $tags = $entity->getVolatileData('search_matched_tags');
+
+ $entity_html = elgg_view_entity($entity);
+ $url = $entity->getURL();
+ $title = "<a href=\"$url\">$title</a>";
+ $tc = $entity->time_created;
+ $tu = $entity->time_updated;
+ $time = friendly_time(($tu > $tc) ? $tu : $tc);
+
+ echo <<<___END
+<span class="searchListing">
+ <h3 class="searchTitle">$title</h3>
+ <span class="searchDetails">
+ $entity_html
+ $tags
+ </span>
+</span>
+___END;
+}
+
+?>
+</div> \ No newline at end of file