1<?php 2// This file is part of Moodle - http://moodle.org/ 3// 4// Moodle is free software: you can redistribute it and/or modify 5// it under the terms of the GNU General Public License as published by 6// the Free Software Foundation, either version 3 of the License, or 7// (at your option) any later version. 8// 9// Moodle is distributed in the hope that it will be useful, 10// but WITHOUT ANY WARRANTY; without even the implied warranty of 11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12// GNU General Public License for more details. 13// 14// You should have received a copy of the GNU General Public License 15// along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17/** 18 * Blog tags block. 19 * 20 * @package block_blog_tags 21 * @copyright 2006 Shane Elliott 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25defined('MOODLE_INTERNAL') || die(); 26 27define('BLOCK_BLOG_TAGS_DEFAULTTIMEWITHIN', 90); 28define('BLOCK_BLOG_TAGS_DEFAULTNUMBEROFTAGS', 20); 29define('BLOCK_BLOG_TAGS_DEFAULTSORT', 'name'); 30 31class block_blog_tags extends block_base { 32 function init() { 33 $this->title = get_string('pluginname', 'block_blog_tags'); 34 } 35 36 function instance_allow_multiple() { 37 return true; 38 } 39 40 function has_config() { 41 return false; 42 } 43 44 function applicable_formats() { 45 return array('all' => true, 'my' => false, 'tag' => false); 46 } 47 48 function instance_allow_config() { 49 return true; 50 } 51 52 function specialization() { 53 54 // load userdefined title and make sure it's never empty 55 if (empty($this->config->title)) { 56 $this->title = get_string('pluginname', 'block_blog_tags'); 57 } else { 58 $this->title = $this->config->title; 59 } 60 } 61 62 function get_content() { 63 global $CFG, $SITE, $USER, $DB, $OUTPUT; 64 65 if ($this->content !== NULL) { 66 return $this->content; 67 } 68 69 // make sure blog and tags are actually enabled 70 if (empty($CFG->bloglevel)) { 71 $this->content = new stdClass(); 72 $this->content->text = ''; 73 if ($this->page->user_is_editing()) { 74 $this->content->text = get_string('blogdisable', 'blog'); 75 } 76 return $this->content; 77 78 } else if (!core_tag_tag::is_enabled('core', 'post')) { 79 $this->content = new stdClass(); 80 $this->content->text = ''; 81 if ($this->page->user_is_editing()) { 82 $this->content->text = get_string('tagsaredisabled', 'tag'); 83 } 84 return $this->content; 85 86 } else if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL and (!isloggedin() or isguestuser())) { 87 $this->content = new stdClass(); 88 $this->content->text = ''; 89 return $this->content; 90 } 91 92 // require the libs and do the work 93 require_once($CFG->dirroot .'/blog/lib.php'); 94 95 if (empty($this->config)) { 96 $this->config = new stdClass(); 97 } 98 99 if (empty($this->config->timewithin)) { 100 $this->config->timewithin = BLOCK_BLOG_TAGS_DEFAULTTIMEWITHIN; 101 } 102 if (empty($this->config->numberoftags)) { 103 $this->config->numberoftags = BLOCK_BLOG_TAGS_DEFAULTNUMBEROFTAGS; 104 } 105 if (empty($this->config->sort)) { 106 $this->config->sort = BLOCK_BLOG_TAGS_DEFAULTSORT; 107 } 108 109 $this->content = new stdClass(); 110 $this->content->text = ''; 111 $this->content->footer = ''; 112 113 /// Get a list of tags 114 $timewithin = time() - $this->config->timewithin * 24 * 60 * 60; /// convert to seconds 115 116 $context = $this->page->context; 117 118 // admins should be able to read all tags 119 $type = ''; 120 if (!has_capability('moodle/user:readuserblogs', context_system::instance())) { 121 $type = " AND (p.publishstate = 'site' or p.publishstate='public')"; 122 } 123 124 $sql = "SELECT t.id, t.isstandard, t.rawname, t.name, COUNT(DISTINCT ti.id) AS ct 125 FROM {tag} t, {tag_instance} ti, {post} p, {blog_association} ba 126 WHERE t.id = ti.tagid AND p.id = ti.itemid 127 $type 128 AND ti.itemtype = 'post' 129 AND ti.component = 'core' 130 AND ti.timemodified > $timewithin"; 131 132 if ($context->contextlevel == CONTEXT_MODULE) { 133 $sql .= " AND ba.contextid = $context->id AND p.id = ba.blogid "; 134 } else if ($context->contextlevel == CONTEXT_COURSE) { 135 $sql .= " AND ba.contextid = $context->id AND p.id = ba.blogid "; 136 } 137 138 $sql .= " 139 GROUP BY t.id, t.isstandard, t.name, t.rawname 140 ORDER BY ct DESC, t.name ASC"; 141 142 if ($tags = $DB->get_records_sql($sql, null, 0, $this->config->numberoftags)) { 143 144 /// There are 2 things to do: 145 /// 1. tags with the same count should have the same size class 146 /// 2. however many tags we have should be spread evenly over the 147 /// 20 size classes 148 149 $totaltags = count($tags); 150 $currenttag = 0; 151 152 $size = 20; 153 $lasttagct = -1; 154 155 $etags = array(); 156 foreach ($tags as $tag) { 157 158 $currenttag++; 159 160 if ($currenttag == 1) { 161 $lasttagct = $tag->ct; 162 $size = 20; 163 } else if ($tag->ct != $lasttagct) { 164 $lasttagct = $tag->ct; 165 $size = 20 - ( (int)((($currenttag - 1) / $totaltags) * 20) ); 166 } 167 168 $tag->class = ($tag->isstandard ? "standardtag " : "") . "s$size"; 169 $etags[] = $tag; 170 171 } 172 173 /// Now we sort the tag display order 174 $CFG->tagsort = $this->config->sort; 175 usort($etags, "block_blog_tags_sort"); 176 177 /// Finally we create the output 178 /// Accessibility: markup as a list. 179 $this->content->text .= "\n<ul class='inline-list'>\n"; 180 foreach ($etags as $tag) { 181 $blogurl = new moodle_url('/blog/index.php'); 182 183 switch ($CFG->bloglevel) { 184 case BLOG_USER_LEVEL: 185 $blogurl->param('userid', $USER->id); 186 break; 187 188 default: 189 if ($context->contextlevel == CONTEXT_MODULE) { 190 $blogurl->param('modid', $context->instanceid); 191 } else if ($context->contextlevel == CONTEXT_COURSE) { 192 $blogurl->param('courseid', $context->instanceid); 193 } 194 195 break; 196 } 197 198 $blogurl->param('tagid', $tag->id); 199 $link = html_writer::link($blogurl, core_tag_tag::make_display_name($tag), 200 array('class' => $tag->class, 201 'title' => get_string('numberofentries', 'blog', $tag->ct))); 202 $this->content->text .= '<li>' . $link . '</li> '; 203 } 204 $this->content->text .= "\n</ul>\n"; 205 206 } 207 return $this->content; 208 } 209 210 /** 211 * Return the plugin config settings for external functions. 212 * 213 * @return stdClass the configs for both the block instance and plugin 214 * @since Moodle 3.8 215 */ 216 public function get_config_for_external() { 217 // Return all settings for all users since it is safe (no private keys, etc..). 218 $configs = !empty($this->config) ? $this->config : new stdClass(); 219 220 return (object) [ 221 'instance' => $configs, 222 'plugin' => new stdClass(), 223 ]; 224 } 225} 226 227function block_blog_tags_sort($a, $b) { 228 global $CFG; 229 230 if (empty($CFG->tagsort)) { 231 return 0; 232 } else { 233 $tagsort = $CFG->tagsort; 234 } 235 236 if (is_numeric($a->$tagsort)) { 237 return (($a->$tagsort == $b->$tagsort) ? 0 : ($a->$tagsort > $b->$tagsort)) ? 1 : -1; 238 } elseif (is_string($a->$tagsort)) { 239 return strcmp($a->$tagsort, $b->$tagsort); //TODO: this is not compatible with UTF-8!! 240 } else { 241 return 0; 242 } 243} 244 245 246