5 * Provide Drupal blocks as content.
7 * Since blocks don't provide all of the features we do, we have to do a little
8 * extra work, including providing icons and categories for core blocks. Blocks
9 * from contrib modules get to provide their own stuff, or get relegated to
10 * the old "Miscellaneous" category.
14 * Plugins are described by creating a $plugin array which will be used
15 * by the system that includes this file.
18 // And this is just the administrative title.
19 // All our callbacks are named according to the standard pattern and can be deduced.
20 'title' => t('Block'),
21 'content type' => 'ctools_block_content_type_content_type',
25 * Return the block content types with the specified $subtype_id.
27 function ctools_block_content_type_content_type($subtype_id) {
28 list($module, $delta) = explode('-', $subtype_id, 2);
29 $module_blocks = module_invoke($module, 'block_info');
30 if (isset($module_blocks[$delta])) {
31 return _ctools_block_content_type_content_type($module, $delta, $module_blocks[$delta]);
36 * Return all block content types available.
38 * Modules wanting to make special adjustments the way that CTools handles their blocks
39 * can implement an extension to the hook_block() family, where the function name is
40 * of the form "$module . '_ctools_block_info'".
42 function ctools_block_content_type_content_types() {
44 foreach (module_implements('block_info') as
$module) {
45 $module_blocks = module_invoke($module, 'block_info');
47 foreach ($module_blocks as
$delta => $block) {
48 $info = _ctools_block_content_type_content_type($module, $delta, $block);
49 // this check means modules can remove their blocks; particularly useful
50 // if they offer the block some other way (like we do for views)
52 $types["$module-$delta"] = $info;
61 * Return an info array for a specific block.
63 function _ctools_block_content_type_content_type($module, $delta, $block) {
64 // strip_tags used because it goes through check_plain and that
67 'title' => strip_tags($block['info']),
70 // Ask around for further information by invoking the hook_block() extension.
71 $function = $module .
'_ctools_block_info';
72 if (!function_exists($function)) {
73 $function = 'ctools_default_block_info';
75 $function($module, $delta, $info);
81 * Load block info from the database.
83 * This is copied from _block_load_blocks(). It doesn't use that
84 * function because _block_load_blocks sorts by region, and it
85 * doesn't cache its results anyway.
87 function _ctools_block_load_blocks() {
88 if (!module_exists('block')) {
92 $blocks = &drupal_static(__FUNCTION__
, NULL
);
93 if (!isset($blocks)) {
96 $query = db_select('block', 'b');
99 ->condition('b.theme', $theme_key)
100 ->orderBy('b.region')
101 ->orderBy('b.weight')
102 ->orderBy('b.module')
103 ->addTag('block_load')
104 ->addTag('translatable')
107 $block_info = $result->fetchAllAssoc('bid');
108 // Allow modules to modify the block list.
109 drupal_alter('block_list', $block_info);
112 foreach ($block_info as
$block) {
113 $blocks["{$block->module}_{$block->delta}"] = $block;
121 * Fetch the stored info for a block.
123 * The primary reason to use this is so that modules which perform alters
124 * can have their alters make it to the block.
126 function _ctools_get_block_info($module, $delta) {
127 $blocks = _ctools_block_load_blocks();
129 $key = $module .
'_' .
$delta;
130 if (isset($blocks[$key])) {
131 return $blocks[$key];
136 * Output function for the 'block' content type. Outputs a block
137 * based on the module and delta supplied in the configuration.
139 function ctools_block_content_type_render($subtype, $conf) {
140 list($module, $delta) = _ctools_block_get_module_delta($subtype, $conf);
142 $info = _ctools_get_block_info($module, $delta);
143 $block = module_invoke($module, 'block_view', $delta);
146 // Allow modules to modify the block before it is viewed, via either
147 // hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter().
148 drupal_alter(array('block_view', "block_view_{$module}_{$delta}"), $block, $info);
150 $block = (object) $block;
156 $block->module
= $module;
157 $block->delta
= $delta;
159 if ($module == 'block' && !empty($info) && isset($info->title
)) {
160 $block->title
= $info->title
;
162 else if (isset($block->subject
)) {
163 $block->title
= $block->subject
;
166 $block->title
= NULL
;
169 if (module_exists('block') && user_access('administer blocks')) {
170 $block->admin_links
= array(
172 'title' => t('Configure block'),
173 'href' => "admin/structure/block/manage/$module/$delta/configure",
174 'query' => drupal_get_destination(),
183 * Empty form so we can have the default override title.
185 function ctools_block_content_type_edit_form($form, &$form_state) {
191 * Submit function to fix the subtype for really old panel panes.
193 function ctools_block_content_type_edit_form_submit($form, &$form_state) {
194 if (empty($form_state['subtype']) && isset($form_state['pane'])) {
195 $form_state['pane']->subtype
= $form_state['conf']['module'] .
'-' .
$form_state['conf']['delta'];
196 unset($form_state['conf']['module']);
197 unset($form_state['conf']['delta']);
202 * Returns an edit form for a block.
204 //function ctools_block_content_type_edit_form($id, $parents, $conf) {
205 // if (user_access('administer advanced pane settings')) {
206 // $form['block_visibility'] = array(
207 // '#type' => 'checkbox',
208 // '#title' => t('Use block visibility settings (see block config)'),
209 // '#default_value' => !empty($conf['block_visibility']),
210 // '#description' => t('If checked, the block visibility settings for this block will apply to this block.'),
212 // // Module-specific block configurations.
213 // if ($settings = module_invoke($module, 'block', 'configure', $delta)) {
214 // // Specifically modify a couple of core block forms.
215 // if ($module == 'block') {
216 // unset($settings['submit']);
217 // $settings['info']['#type'] = 'value';
218 // $settings['info']['#value'] = $settings['info']['#default_value'];
220 // ctools_admin_fix_block_tree($settings);
221 // $form['block_settings'] = array(
222 // '#type' => 'fieldset',
223 // '#title' => t('Block settings'),
224 // '#description' => t('Settings in this section are global and are for all blocks of this type, anywhere in the system.'),
229 // $form['block_settings'] += $settings;
236 //function ctools_admin_submit_block(&$form_values) {
237 // if (!empty($form_values['block_settings'])) {
238 // module_invoke($form_values['module'], 'block', 'save', $form_values['delta'], $form_values['block_settings']);
243 // * Because form api cannot collapse just part of a tree, and the block settings
244 // * assume no tree, we have to collapse the tree ourselves.
246 //function ctools_admin_fix_block_tree(&$form, $key = NULL) {
248 // if (!empty($form['#parents'])) {
249 // $form['#parents'] = array_merge(array('configuration', 'block_settings'), $form['#parents']);
251 // else if (empty($form['#tree'])) {
252 // $form['#parents'] = array('configuration', 'block_settings', $key);
256 // if (isset($form['#type']) && $form['#type'] == 'textarea' && !empty($form['#rows']) && $form['#rows'] > 10) {
257 // $form['#rows'] = 10;
260 // foreach (element_children($form) as $key) {
261 // ctools_admin_fix_block_tree($form[$key], $key);
266 * Returns the administrative title for a type.
268 function ctools_block_content_type_admin_title($subtype, $conf) {
269 list($module, $delta) = _ctools_block_get_module_delta($subtype, $conf);
270 $block = module_invoke($module, 'block_info');
271 if (empty($block) || empty($block[$delta])) {
272 return t('Deleted/missing block @module-@delta', array('@module' => $module, '@delta' => $delta));
275 // The block description reported by hook_block() is plain text, but the title
276 // reported by this hook should be HTML.
277 $title = check_plain($block[$delta]['info']);
282 * Output function for the 'block' content type. Outputs a block
283 * based on the module and delta supplied in the configuration.
285 function ctools_block_content_type_admin_info($subtype, $conf) {
286 list($module, $delta) = _ctools_block_get_module_delta($subtype, $conf);
287 $block = (object) module_invoke($module, 'block_view', $delta);
289 if (!empty($block)) {
290 // Sanitize the block because <script> tags can hose javascript up:
291 if (!empty($block->content
)) {
292 $block->content
= filter_xss_admin(render($block->content
));
295 if (!empty($block->subject
)) {
296 $block->title
= $block->subject
;
298 elseif (empty($block->title
)) {
299 $block->title
= t('No title');
305 function _ctools_block_get_module_delta($subtype, $conf) {
306 if (strpos($subtype, '-')) {
307 return explode('-', $subtype, 2);
310 return array($conf['module'], $conf['delta']);
315 * Provide default icon and categories for blocks when modules don't do this
318 function ctools_default_block_info($module, $delta, &$info) {
319 $core_modules = array('aggregator', 'block', 'blog', 'blogapi', 'book', 'color', 'comment', 'contact', 'drupal', 'filter', 'forum', 'help', 'legacy', 'locale', 'menu', 'node', 'path', 'ping', 'poll', 'profile', 'search', 'statistics', 'taxonomy', 'throttle', 'tracker', 'upload', 'user', 'watchdog', 'system');
321 if (in_array($module, $core_modules)) {
322 $info['icon'] = 'icon_core_block.png';
323 $info['category'] = t('Miscellaneous');
326 $info['icon'] = 'icon_contrib_block.png';
327 $info['category'] = t('Miscellaneous');
331 // These are all on behalf of modules that don't implement ctools but that
333 function menu_ctools_block_info($module, $delta, &$info) {
334 $info['icon'] = 'icon_core_block_menu.png';
335 $info['category'] = t('Menus');
336 if ($delta == 'primary-links' || $delta == 'secondary-links') {
337 $info['icon'] = 'icon_core_primarylinks.png';
341 function forum_ctools_block_info($module, $delta, &$info) {
342 $info['category'] = t('Activity');
345 $info['icon'] = 'icon_core_activeforumtopics.png';
349 $info['icon'] = 'icon_core_newforumtopics.png';
354 ctools_default_block_info($module, $delta, $info);
358 function profile_ctools_block_info($module, $delta, &$info) {
359 // Hide the author information block which isn't as rich as what we can
364 function book_ctools_block_info($module, $delta, &$info) {
365 // Hide the book navigation block which isn't as rich as what we can
370 function blog_ctools_block_info($module, $delta, &$info) {
371 $info['icon'] = 'icon_core_recentblogposts.png';
372 $info['category'] = t('Activity');
375 function poll_ctools_block_info($module, $delta, &$info) {
376 $info['icon'] = 'icon_core_recentpoll.png';
377 $info['category'] = t('Activity');
380 function comment_ctools_block_info($module, $delta, &$info) {
381 $info['icon'] = 'icon_core_recentcomments.png';
382 $info['category'] = t('Activity');
385 function search_ctools_block_info($module, $delta, &$info) {
386 $info['icon'] = 'icon_core_searchform.png';
387 $info['category'] = t('Widgets');
390 function node_ctools_block_info($module, $delta, &$info) {
391 $info['icon'] = 'icon_core_syndicate.png';
392 $info['category'] = t('Widgets');
395 function aggregator_ctools_block_info($module, $delta, &$info) {
396 $info['icon'] = 'icon_core_syndicate.png';
397 $info['category'] = t('Feeds');
400 function block_ctools_block_info($module, $delta, &$info) {
401 $info['icon'] = 'icon_core_block_empty.png';
402 $info['category'] = t('Custom blocks');
404 // The title of custom blocks from the block module is stored in the
405 // {block} table. Look for it in the default theme as a reasonable
406 // default value for the title.
407 $block_info_cache = drupal_static(__FUNCTION__
);
408 if (!isset($block_info_cache)) {
409 $block_info_cache = db_select('block', 'b')
411 ->condition('b.module', 'block')
412 ->condition('b.theme', variable_get('theme_default', 'bartik'))
413 ->addTag('block_load')
414 ->addTag('translatable')
416 ->fetchAllAssoc('delta');
419 if (isset($block_info_cache[$delta])) {
420 $info['defaults'] = array(
421 'override_title' => TRUE
,
422 'override_title_text' => $block_info_cache[$delta]->title
,
427 function user_ctools_block_info($module, $delta, &$info) {
428 $info['category'] = t('Activity');
431 $info['icon'] = 'icon_core_userlogin.png';
432 $info['category'] = t('Widgets');
433 // Provide a custom render callback, because the default login block
434 // will not render on /user, /user/login, or any other URL beginning
435 // /user (unless it's a user-specific page such as /user/123).
436 $info['render callback'] = 'ctools_user_login_pane_render';
440 $info['icon'] = 'icon_core_whosnew.png';
444 $info['icon'] = 'icon_core_whosonline.png';
449 ctools_default_block_info($module, $delta, $info);
453 function locale_ctools_block_info($module, $delta, &$info) {
454 $info['icon'] = 'icon_core_languageswitcher.png';
455 $info['category'] = t('Widgets');
458 function statistics_ctools_block_info($module, $delta, &$info) {
459 $info['icon'] = 'icon_core_popularcontent.png';
460 $info['category'] = t('Activity');
463 function system_ctools_block_info($module, $delta, &$info) {
464 // Remove the main content fake block.
465 if ($delta == 'main') {
470 $menus = array('main-menu', 'management', 'navigation', 'user-menu');
472 if (in_array($delta, $menus)) {
473 $info['icon'] = 'icon_core_block_menu.png';
474 $info['category'] = t('Menus');
476 if ($delta == 'navigation') {
477 $info['icon'] = 'icon_core_navigation.png';
483 $info['icon'] = 'icon_core_drupal.png';
484 if ($delta == 'help') {
485 $info['category'] = t('Page elements');
489 $info['category'] = t('Widgets');
492 function ctools_user_login_pane_render($subtype, $conf, $panel_args, $contexts) {
493 list($module, $delta) = _ctools_block_get_module_delta($subtype, $conf);
495 // The login form is only visible to anonymous users.
501 $info = new stdClass
;
502 $info->module
= $module;
503 $info->delta
= $delta;
506 $block['subject'] = t('User login');
507 // Manually set the content (rather than invoking block_view) because the
508 // block implementation won't render on certain URLs.
509 $block['content'] = drupal_get_form('user_login_block');
511 // Allow modules to modify the block before it is viewed, via either
512 // hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter().
513 drupal_alter(array('block_view', "block_view_{$module}_{$delta}"), $block, $info);
514 $block = (object) $block;
520 $block->module
= $module;
521 $block->delta
= $delta;
523 // $block->title is not set for the blocks returned by block_block() (the
524 // Block module adds the title in block_list() instead), so we look it up
525 // manually, unless the title is overridden and does not use the %title
527 if ($module == 'block') {
528 $block->title
= $info->title
;
530 else if (isset($block->subject
)) {
531 $block->title
= $block->subject
;
534 $block->title
= NULL
;
537 if (isset($block->subject
)) {
538 $block->title
= $block->subject
;
541 $block->title
= NULL
;
544 if (user_access('administer blocks')) {
545 $block->admin_links
= array(
547 'title' => t('Configure block'),
548 'href' => "admin/structure/block/manage/$module/$delta/configure",
549 'query' => drupal_get_destination(),