Commit 85303f91 authored by Robert Lyon's avatar Robert Lyon

Bug 1775106: Adding tagging to some blocktypes

If the configuration for a block instance has a tags field it can save
the tag against this block

behatnotneeded

Change-Id: Ib2f0f73aa6e082472879acb0e4fc1eb60e744087
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent ee8d8cdb
......@@ -562,6 +562,7 @@ EOF;
unset($values['chooseartefact']);
unset($values['managenotes']);
unset($values['allowcomments']);
unset($values['tags']); // We save the tags against the artefact so don't need to save again against the block
// Pass back a list of any other blocks that need to be rendered
// due to this change.
......
......@@ -25,6 +25,10 @@ class PluginBlocktypeEntireresume extends MaharaCoreBlocktype {
return array('internal' => 29000);
}
public static function get_blocktype_type_content_types() {
return array('entireresume' => array('resume'));
}
public static function render_instance(BlockInstance $instance, $editing=false) {
require_once(get_config('docroot') . 'artefact/lib.php');
$smarty = smarty_core();
......@@ -50,15 +54,21 @@ class PluginBlocktypeEntireresume extends MaharaCoreBlocktype {
return $smarty->fetch('blocktype:entireresume:content.tpl');
}
// Yes, we do have instance config. People are allowed to specify the title
// of the block, nothing else at this time. So in the next two methods we
// say yes and return no fields, so the title will be configurable.
public static function has_instance_config() {
return true;
}
public static function instance_config_form(BlockInstance $instance) {
return array();
$elements = array(
'tags' => array(
'type' => 'tags',
'title' => get_string('tags'),
'description' => get_string('tagsdescblock'),
'defaultvalue' => $instance->get('tags'),
'help' => false,
)
);
return $elements;
}
public static function artefactchooser_element($default=null) {
......
......@@ -25,7 +25,11 @@ class PluginBlocktypeResumefield extends MaharaCoreBlocktype {
return array('internal' => 30000);
}
/**
public static function get_blocktype_type_content_types() {
return array('resumefield' => array('resume'));
}
/**
* Optional method. If exists, allows this class to decide the title for
* all blockinstances of this type
*/
......@@ -73,7 +77,13 @@ class PluginBlocktypeResumefield extends MaharaCoreBlocktype {
'type' => 'html',
'value' => '<p class="alert alert-info">' . get_string('filloutyourresume', 'blocktype.resume/resumefield', '<a href="' . get_config('wwwroot') . 'artefact/resume/index.php">', '</a>') .'</p>',
);
$form['tags'] = array(
'type' => 'tags',
'title' => get_string('tags'),
'description' => get_string('tagsdescblock'),
'defaultvalue' => $instance->get('tags'),
'help' => false,
);
return $form;
}
......
......@@ -56,19 +56,6 @@ class PluginArtefactResume extends PluginArtefact {
);
}
public static function get_artefact_type_content_types() {
return array(
'coverletter' => array('text'),
'interest' => array('text'),
'personalgoal' => array('text'),
'academicgoal' => array('text'),
'careergoal' => array('text'),
'personalskill' => array('text'),
'academicskill' => array('text'),
'workskill' => array('text'),
);
}
public static function submenu_items() {
$tabs = array(
'subnav' => array(
......
......@@ -60,6 +60,10 @@ class PluginBlocktypeExternalfeed extends MaharaCoreBlocktype {
}
}
public static function get_blocktype_type_content_types() {
return array('externalfeed' => array('media'));
}
public static function render_instance(BlockInstance $instance, $editing=false) {
$configdata = $instance->get('configdata');
if (!empty($configdata['feedid'])) {
......@@ -203,6 +207,13 @@ class PluginBlocktypeExternalfeed extends MaharaCoreBlocktype {
'description' => get_string('showfeeditemsinfulldesc', 'blocktype.externalfeed'),
'defaultvalue' => (bool)$full,
),
'tags' => array(
'type' => 'tags',
'title' => get_string('tags'),
'description' => get_string('tagsdescblock'),
'defaultvalue' => $instance->get('tags'),
'help' => false,
)
);
}
......
......@@ -114,6 +114,10 @@ class PluginBlocktypeExternalvideo extends MaharaCoreBlocktype {
return '<iframe width="' . $width . '" height="' . $height . '" src="' . $url . '" frameborder=0 allowfullscreen mozallowfullscreen webkitallowfullscreen></iframe>';
}
public static function get_blocktype_type_content_types() {
return array('externalvideo' => array('media'));
}
public static function render_instance(BlockInstance $instance, $editing=false) {
global $THEME;
......@@ -236,6 +240,13 @@ class PluginBlocktypeExternalvideo extends MaharaCoreBlocktype {
),
'defaultvalue' => (!empty($configdata['height'])) ? $configdata['height'] : 0,
),
'tags' => array(
'type' => 'tags',
'title' => get_string('tags'),
'description' => get_string('tagsdescblock'),
'defaultvalue' => $instance->get('tags'),
'help' => false,
)
);
}
......
......@@ -28,6 +28,10 @@ class PluginBlocktypeGoogleApps extends MaharaCoreBlocktype {
return array('external' => 36000);
}
public static function get_blocktype_type_content_types() {
return array('googleapps' => array('media'));
}
public static function render_instance(BlockInstance $instance, $editing=false) {
$configdata = $instance->get('configdata');
if (!isset($configdata['appsid'])) {
......@@ -89,6 +93,13 @@ class PluginBlocktypeGoogleApps extends MaharaCoreBlocktype {
),
'defaultvalue' => (!empty($configdata['height'])) ? $configdata['height'] : self::$default_height,
),
'tags' => array(
'type' => 'tags',
'title' => get_string('tags'),
'description' => get_string('tagsdescblock'),
'defaultvalue' => $instance->get('tags'),
'help' => false,
)
);
}
......
......@@ -647,6 +647,7 @@ class BlockInstance {
private $maxorderincolumn;
private $artefacts = array();
private $temp = array();
private $tags = array();
public function __construct($id=0, $data=null) {
if (!empty($id)) {
......@@ -685,6 +686,20 @@ class BlockInstance {
$this->configdata = unserialize($this->configdata);
}
}
if ($field == 'tags') {
$typecast = is_postgres() ? '::varchar' : '';
$this->tags = get_column_sql("
SELECT
(CASE
WHEN t.tag LIKE 'tagid_%' THEN CONCAT(i.displayname, ': ', t2.tag)
ELSE t.tag
END) AS tag, t.resourceid
FROM {tag} t
LEFT JOIN {tag} t2 ON t2.id" . $typecast . " = SUBSTRING(t.tag, 7)
LEFT JOIN {institution} i ON i.name = t2.ownerid
WHERE t.resourcetype = ? AND t.resourceid = ?
ORDER BY tag", array('blocktype', $this->get('id')));
}
if (strpos($field, 'canmove') === 0) {
return $this->can_move(substr($field, strlen('canmove'))); // needs to be calculated.
}
......@@ -702,6 +717,9 @@ class BlockInstance {
public function set($field, $value) {
if (property_exists($this, $field)) {
if ($field == 'tags') {
$this->set_tags($value);
}
if ($field == 'configdata') {
$value = serialize($value);
}
......@@ -715,6 +733,43 @@ class BlockInstance {
throw new ParamOutOfRangeException("Field $field wasn't found in class " . get_class($this));
}
private function set_tags($tags) {
global $USER;
if ($this->view_obj->get('group')) {
$ownertype = 'group';
$ownerid = $this->view_obj->get('group');
}
else if ($this->view_obj->get('institution')) {
$ownertype = 'institution';
$ownerid = $this->view_obj->get('institution');
}
else {
$ownertype = 'user';
$ownerid = $this->view_obj->get('owner');
}
$this->tags = check_case_sensitive($tags, 'tag');
delete_records('tag', 'resourcetype', 'blocktype', 'resourceid', $this->get('id'));
foreach ($this->tags as $tag) {
// truncate the tag before insert it into the database
$tag = substr($tag, 0, 128);
if ($institutiontag = get_record('tag', 'tag', $tag, 'resourcetype', 'institution', 'ownertype', 'institution')) {
$tag = 'tagid_' . $institutiontag->id;
}
insert_record('tag',
(object)array(
'resourcetype' => 'blocktype',
'resourceid' => $this->get('id'),
'ownertype' => $ownertype,
'ownerid' => $ownerid,
'tag' => $tag,
'ctime' => db_format_timestamp(time()),
'editedby' => $USER->get('id'),
)
);
}
}
// returns false if it finds a bad attachment
// returns true if all attachments are allowed
private function verify_attachment_permissions($id) {
......@@ -809,6 +864,11 @@ class BlockInstance {
$title = (isset($values['title'])) ? $values['title'] : '';
unset($values['title']);
if (isset($values['tags'])) {
$this->set('tags', $values['tags']);
unset($values['tags']);
}
// A block may return a list of other blocks that need to be
// redrawn after configuration of this block.
$torender = !empty($values['_redrawblocks']) && $form->submitted_by_js() ? $values['_redrawblocks'] : array();
......@@ -1604,6 +1664,12 @@ class BlockInstance {
if (($sameowner && $copytype != 'fullinclself') || $copytype == 'reference') {
$newblock->set('configdata', $configdata);
$newblock->commit();
// Copy any tagged block tags - we need to commit before here so the block instance has an ID value
if ($tags = $this->get('tags')) {
$newblock->set('tags', $tags);
$newblock->commit();
}
if ($this->get('blocktype') == 'taggedposts' && $copytype == 'tagsonly') {
$this->copy_tags($newblock->get('id'));
}
......@@ -1686,6 +1752,11 @@ class BlockInstance {
$newblock->set('configdata', $configdata);
$newblock->commit();
// Copy any tagged block tags - we need to commit before here so the block instance has an ID value
if ($tags = $this->get('tags')) {
$newblock->set('tags', $tags);
$newblock->commit();
}
if ($this->get('blocktype') == 'taggedposts' && $copytype == 'tagsonly') {
$this->copy_tags($newblock->get('id'));
}
......@@ -1766,3 +1837,42 @@ class BlockInstance {
return array();
}
}
function require_blocktype_plugins() {
static $plugins = null;
if (is_null($plugins)) {
$plugins = plugins_installed('blocktype');
foreach ($plugins as $plugin) {
safe_require('blocktype', $plugin->name);
}
}
return $plugins;
}
function blocktype_get_types_from_filter($filter) {
static $contenttype_blocktype = null;
if (is_null($contenttype_blocktype)) {
$contenttype_blocktype = array();
foreach (require_blocktype_plugins() as $plugin) {
$classname = generate_class_name('blocktype', $plugin->name);
if (!is_callable($classname . '::get_blocktype_type_content_types')) {
continue;
}
$blocktypetypes = call_static_method($classname, 'get_blocktype_type_content_types');
foreach ($blocktypetypes as $blocktype => $contenttypes) {
if (!empty($contenttypes)) {
foreach ($contenttypes as $ct) {
$contenttype_blocktype[$ct][] = $blocktype;
}
}
}
}
}
if (empty($contenttype_blocktype[$filter])) {
return null;
}
return $contenttype_blocktype[$filter];
}
......@@ -74,6 +74,10 @@ class PluginBlocktypeOpenbadgedisplayer extends SystemBlocktype {
return self::$source;
}
public static function get_blocktype_type_content_types() {
return array('openbadgedisplayer' => array('media'));
}
public static function render_instance(BlockInstance $instance, $editing=false) {
$configdata = $instance->get('configdata');
if (empty($configdata) || !isset($configdata['badgegroup']) || !get_config('openbadgedisplayer_source')) {
......@@ -320,6 +324,13 @@ class PluginBlocktypeOpenbadgedisplayer extends SystemBlocktype {
'value' => json_encode($current_values),
),
)
),
'tags' => array(
'type' => 'tags',
'title' => get_string('tags'),
'description' => get_string('tagsdescblock'),
'defaultvalue' => $instance->get('tags'),
'help' => false,
)
);
......
......@@ -38,6 +38,10 @@ class PluginBlocktypeText extends MaharaCoreBlocktype {
return $artefacts;
}
public static function get_blocktype_type_content_types() {
return array('text' => array('text'));
}
public static function render_instance(BlockInstance $instance, $editing=false) {
safe_require('artefact', 'file');
$configdata = $instance->get('configdata');
......@@ -79,6 +83,13 @@ class PluginBlocktypeText extends MaharaCoreBlocktype {
'defaultvalue' => $text,
'rules' => array('maxlength' => 65536),
),
'tags' => array(
'type' => 'tags',
'title' => get_string('tags'),
'description' => get_string('tagsdescblock'),
'defaultvalue' => $instance->get('tags'),
'help' => false,
)
);
return $elements;
}
......
......@@ -28,7 +28,8 @@ $smarty->assign('collectiontitle', $collection->get('name'));
$smarty->assign('ownername', $firstview->formatted_owner());
$smarty->assign('collectiondescription', $collection->get('description'));
$smarty->assign('viewcontent', $firstview->build_rows(false, true));
$smarty->assign('tags', $firstview->get('tags'));
list($tagcount, $alltags) = $firstview->get_all_tags_for_view();
$smarty->assign('tags', $alltags);
$shownav = $collection->get('navigation');
if ($shownav) {
......
......@@ -158,6 +158,7 @@ $string['select'] = 'Select';
$string['tags'] = 'Tags';
$string['tagsdesc'] = 'Search for/enter tags for this item.';
$string['tagsdescprofile'] = 'Search for/enter tags for this item. Items tagged with \'profile\' are displayed in your sidebar.';
$string['tagsdescblock'] = 'Search for/enter tags for this block.';
$string['viewtags'] = 'Page tags';
$string['youhavenottaggedanythingyet'] = 'You have not tagged anything yet';
$string['mytags'] = 'My tags';
......@@ -196,6 +197,8 @@ $string['tagfilter_blog'] = 'Journal';
$string['tagfilter_blogpost'] = 'Journal entry';
$string['tagfilter_plan'] = 'Plan';
$string['tagfilter_task'] = 'Plan task';
$string['tagfilter_external'] = 'External';
$string['tagfilter_resume'] = 'Résumé';
$string['edittags'] = 'Edit tags';
$string['selectatagtoedit'] = 'Select a tag to edit';
$string['edittag'] = 'Edit <a href="%s">%s</a>';
......
......@@ -110,6 +110,10 @@ function get_all_tags_for_user($query = null, $limit = null, $offset = null) {
if ($query) {
$querystr = " WHERE tag LIKE '%' || ? || '%'";
$values[] = $query;
// Also do matching by institution name so we can list valid institution tags
// if we only know institution name
$querystr .= " OR prefix LIKE '%' || ? || '%'";
$values[] = $query;
}
$sql = "
SELECT tag, SUM(count) AS count, prefix
......@@ -122,7 +126,7 @@ function get_all_tags_for_user($query = null, $limit = null, $offset = null) {
FROM {tag} t
LEFT JOIN {tag} t2 ON t2.id" . $typecast . " = SUBSTRING(t.tag, 7)
LEFT JOIN {institution} i ON i.name = t2.ownerid
WHERE t.ownerid=? AND t.resourcetype IN ('artefact', 'view', 'collection')
WHERE t.ownerid=? AND t.resourcetype IN ('artefact', 'view', 'collection', 'blocktype')
GROUP BY 1, 3
UNION ALL
SELECT t.tag, 0 AS count, i.displayname AS prefix
......
......@@ -3873,7 +3873,7 @@ function get_my_tags($limit=null, $cloud=true, $sort='freq', $excludeinstitution
FROM {tag} t
LEFT JOIN {tag} t2 ON t2.id" . $typecast . " = SUBSTRING(t.tag, 7)
LEFT JOIN {institution} i ON i.name = t2.ownerid
WHERE t.resourcetype IN ('artefact', 'view', 'collection')
WHERE t.resourcetype IN ('artefact', 'view', 'collection', 'blocktype')
AND t.ownertype = 'user'
AND t.ownerid = ?" . $excludeinstitutiontagssql . "
GROUP BY 1
......@@ -4521,6 +4521,23 @@ function build_portfolio_search_html(&$data) {
$item->url = $c->get_url();
$item->views = $viewarray;
}
else if ($item->type == 'blocktype') {
safe_require('blocktype', $item->artefacttype);
$bi = new BlockInstance($item->id);
$bi->set('dirty', false);
$item->title = $bi->get_title();
$item->url = $bi->get_view()->get_url();
// Get the correct css icon
$namespaced = blocktype_single_to_namespaced($item->artefacttype, $bi->get('artefactplugin'));
$classname = generate_class_name('blocktype', $namespaced);
$item->typestr = call_static_method($classname, 'get_css_icon', $item->artefacttype);
if (in_array($item->artefacttype, array('entireresume', 'resumefield'))) {
$item->typelabel = get_string('title', 'blocktype.resume/' . $item->artefacttype);
}
else {
$item->typelabel = get_string('title', 'blocktype.' . $item->artefacttype);
}
}
else { // artefact
safe_require('artefact', $artefacttypes[$item->artefacttype]->plugin);
$links = call_static_method(generate_artefact_class_name($item->artefacttype), 'get_links', $item->id);
......@@ -4563,6 +4580,8 @@ function build_portfolio_search_html(&$data) {
'blogpost' => get_string('tagfilter_blogpost'),
'plan' => get_string('tagfilter_plan'),
'task' => get_string('tagfilter_task'),
'media' => get_string('tagfilter_external'),
'resume' => get_string('tagfilter_resume'),
);
$smarty = smarty_core();
......@@ -4694,6 +4713,19 @@ function generate_csv($data, $csvfields, $csvheaders = array()) {
* @return array Array of strings
*/
function check_case_sensitive($a, $table) {
// Need to avoid tags that could clash with institution tag format
// So we remove or strip anything beginning with tagid/tagid_
foreach ($a as $k => $v) {
if (preg_match("/^tagid(\_*)(.*)/i", $v, $matches)) {
if (empty($matches[2])) {
unset($a[$k]);
}
else {
$a[$k] = $matches[2];
}
}
}
if (is_mysql()) {
$db = get_config('dbname');
$table = get_config('dbprefix') . $table;
......
......@@ -1021,14 +1021,23 @@ function get_portfolio_types_from_param($filter) {
if (is_null($filter) || $filter == 'all') {
return null;
}
$types = array('view' => false, 'collection' => false, 'artefact' => false, 'blocktype' => false);
if ($filter == 'view') {
return array('view' => true, 'collection' => false, 'artefact' => false);
$types['view'] = true;
return $types;
}
if ($filter == 'collection') {
return array('view' => false, 'collection' => true, 'artefact' => false);
$types['collection'] = true;
return $types;
}
require_once(get_config('docroot') . 'artefact/lib.php');
return array('view' => false, 'collection' => false, 'artefact' => artefact_get_types_from_filter($filter));
$artefactfilter = artefact_get_types_from_filter($filter);
$types['artefact'] = $artefactfilter;
require_once(get_config('docroot') . 'blocktype/lib.php');
$blocktypefilter = blocktype_get_types_from_filter($filter);
$types['blocktype'] = $blocktypefilter;
return $types;
}
function get_portfolio_items_by_tag($tag, $owner, $limit, $offset, $sort='name', $type=null, $returntags=true, $viewids=array()) {
......
......@@ -722,6 +722,64 @@ class View {
return $this->tags;
}
public function get_all_tags_for_view($limit = null) {
$count = 0;
$alltags = array();
$artefactids = get_column_sql("
SELECT artefact
FROM {view_artefact}
WHERE view = ?
UNION
SELECT id AS artefact
FROM {artefact}
WHERE parent IN (
SELECT artefact
FROM {view_artefact}
WHERE view = ?)", array($this->id, $this->id));
$blockids = get_column('block_instance', 'id', 'view', $this->id);
$typecast = is_postgres() ? '::varchar' : '';
$alltags = get_column_sql("
SELECT (
CASE
WHEN t.tag LIKE 'tagid_%' THEN CONCAT(i.displayname, ': ', t2.tag)
ELSE t.tag
END) AS tag
FROM {tag} t
LEFT JOIN {tag} t2 ON t2.id" . $typecast . " = SUBSTRING(t.tag, 7)
LEFT JOIN {institution} i ON i.name = t2.ownerid
WHERE t.resourcetype = ? AND t.resourceid = ?
UNION
SELECT (
CASE
WHEN t.tag LIKE 'tagid_%' THEN CONCAT(i.displayname, ': ', t2.tag)
ELSE t.tag
END) AS tag
FROM {tag} t
LEFT JOIN {tag} t2 ON t2.id" . $typecast . " = SUBSTRING(t.tag, 7)
LEFT JOIN {institution} i ON i.name = t2.ownerid
WHERE t.resourcetype = ? AND t.resourceid IN ('" . join("','", $blockids) . "')
GROUP BY 1
UNION
SELECT (
CASE
WHEN t.tag LIKE 'tagid_%' THEN CONCAT(i.displayname, ': ', t2.tag)
ELSE t.tag
END) AS tag
FROM {tag} t
LEFT JOIN {tag} t2 ON t2.id" . $typecast . " = SUBSTRING(t.tag, 7)
LEFT JOIN {institution} i ON i.name = t2.ownerid
WHERE t.resourcetype = ? AND t.resourceid IN ('" . join("','", $artefactids) . "')
GROUP BY 1
ORDER BY tag", array('view', $this->id, 'blocktype', 'artefact'));
$count = sizeof($alltags);
if ($limit && $count > $limit) {
$alltags = array_slice($alltags, 0, $limit);
}
return array($count, $alltags);
}
public function get_collection() {
if (!isset($this->collection)) {
require_once(get_config('libroot') . 'collection.php');
......
......@@ -1015,18 +1015,28 @@ class PluginSearchInternal extends PluginSearch {
if (is_null($types)) {
$artefacttypefilter = '';
}
else if (!empty($types['artefact'])) {
$artefacttypefilter = ' AND a.artefacttype IN (' . join(',', array_map('db_quote', $types['artefact'])) . ')';
$blocktypefilter = '';
}
else {
$artefacttypefilter = ' AND FALSE';
if (!empty($types['artefact'])) {
$artefacttypefilter = ' AND a.artefacttype IN (' . join(',', array_map('db_quote', $types['artefact'])) . ')';
}
else {
$artefacttypefilter = ' AND FALSE';
}
if (!empty($types['blocktype'])) {
$blocktypefilter = ' AND b.blocktype IN (' . join(',', array_map('db_quote', $types['blocktype'])) . ')';
}
else {
$blocktypefilter = ' AND FALSE';
}
}
if (!is_null($tag)) {
$artefacttypefilter .= ' AND at.tag = ?';
$viewfilter .= ' AND vt.tag = ?';
$collectionfilter .= ' AND (ct.tag = ? OR vt.tag = ?)';
$blocktypefilter .= ' AND bt.tag = ?';
// Test if this is an institutionally defined
// tag and strip the displayname prefix out.
......@@ -1040,22 +1050,26 @@ class PluginSearchInternal extends PluginSearch {
JOIN {institution} i ON i.name = t.ownerid
WHERE i.displayname = ? AND t.tag = ?", array($prefix, $tag));
}
$values = array($owner->id, $tag, $owner->id, $tag, $owner->id, $tag, $tag);
$values = array($owner->id, $tag, $owner->id, $tag, $owner->id, $tag, $tag, $owner->id, $tag);
}
else {
$values = array($owner->id, $owner->id, $owner->id);
$values = array($owner->id, $owner->id, $owner->id, $owner->id);
}
if (!empty($viewids) && is_array($viewids)) {
$viewidstr = implode(',', $viewids);
$artefactjoin = ' JOIN {view_artefact} va ON (va.artefact = a.parent OR va.artefact = a.id)
LEFT JOIN {artefact_blog_blogpost} abb ON abb.blogpost = a.id ';
$artefactwhere = ' AND va.view IN (' . $viewidstr . ') AND (abb.published IS NULL OR abb.published = 1) ';
$blocktypejoin = ' JOIN {view_artefact} va ON va.block = b.id ';
$blocktypewhere = ' AND va.view IN (' . $viewidstr . ') ';
$viewwhere = ' AND v.id IN (' . $viewidstr . ') ';
$collectionwhere = ' AND cv.view IN (' . $viewidstr . ') ';
}
else {
$artefactjoin = '';
$artefactwhere = '';
$blocktypejoin = '';
$blocktypewhere = '';
$viewwhere = '';
$collectionwhere = '';
}
......@@ -1082,6 +1096,12 @@ class PluginSearchInternal extends PluginSearch {
LEFT JOIN {tag} ct ON (ct.resourcetype = 'collection' AND ct.resourceid = c.id" . $typecast . ")
LEFT JOIN {tag} vt ON (vt.resourcetype = 'view' AND vt.resourceid = cv.view" . $typecast . ")
WHERE c.owner = ? " . $collectionwhere . $collectionfilter . ")
UNION
(SELECT b.id, b.title, NULL AS description, 'blocktype' AS type, b.blocktype, NULL AS ctime,
NULL AS owner, NULL AS group, NULL AS institution, NULL AS urlid
FROM {block_instance} b
JOIN {tag} bt ON (bt.resourcetype = 'blocktype' AND bt.resourceid = b.id" . $typecast . ") " . $blocktypejoin . "
WHERE bt.ownertype = 'user' AND bt.ownerid = ?" . $blocktypewhere . $blocktypefilter . ")
) p";
$result = (object) array(
......@@ -1099,7 +1119,7 @@ class PluginSearchInternal extends PluginSearch {
$sort = $sort == 'date' ? 'ctime DESC' : 'title ASC';
if ($data = get_records_sql_assoc("SELECT type || ':' || id AS tid, p.* " . $from . ' ORDER BY ' . $sort, $values, $offset, $limit)) {
if ($returntags) {
$ids = array('view' => array(), 'collection' => array(), 'artefact' => array());
$ids = array('view' => array(), 'collection' => array(), 'artefact' => array(), 'blocktype' =>