6 if (module_exists('menu')) {
7 require_once (dirname(__FILE__
) .
'/section.menu.inc');
10 if (module_exists('path')) {
11 require_once (dirname(__FILE__
) .
'/section.path.inc');
16 * Implements hook_entity_info().
18 function section_entity_info() {
21 'label' => t('Section'),
22 'entity class' => 'Entity',
23 'controller class' => 'EntityAPIControllerExportable',
26 'uri callback' => 'section_uri',
27 'static cache' => TRUE
,
28 'view modes' => array(
30 'label' => t('Full content'),
31 'custom settings' => FALSE
,
34 'access callback' => 'section_access',
35 'base table' => 'section',
36 'revision table' => 'section_revision',
37 'module' => 'section',
38 'bundle keys' => array(
42 'entity keys' => array(
52 $bundles = section_bundles();
53 foreach ($bundles as
$bundle) {
54 $definition['section']['bundles'][$bundle->name
] = array(
55 'label' => $bundle->label
,
57 'path' => 'admin/structure/section_bundle/list/%section_bundle/edit',
58 'real path' => 'admin/structure/section_bundle/list/' .
$bundle->name .
'/edit',
59 'bundle argument' => 4,
60 'access arguments' => array('administer section bundles'),
69 * Menu loader callback; Load a section bundle object.
71 function section_bundle_load($name) {
72 $bundles = section_bundles();
73 return isset($bundles[$name]) ?
$bundles[$name] : FALSE
;
76 * Implements hook_permission().
78 function section_permission() {
80 'administer section bundles' => array(
81 'title' => t('Administer section bundles'),
82 'restrict access' => TRUE
,
84 'create section bundles' => array(
85 'title' => t('Create section bundles'),
87 'delete section bundles' => array(
88 'title' => t('Delete section bundles'),
90 'administer sections' => array(
91 'title' => t('Administer sections'),
92 'restrict access' => TRUE
,
94 'access section overview' => array(
95 'title' => t('Access the section overview page'),
97 'access section' => array(
98 'title' => t('View sections'),
102 // Generate standard section permissions for all applicable section bundles.
103 foreach (section_bundles() as
$bundle) {
104 $perms += section_list_permissions($bundle);
111 * Helper function to generate standard asection permission list for a given
115 * The section bundle.
117 * An array of permission names and descriptions.
119 function section_list_permissions($bundle) {
120 $bundle_name = check_plain($bundle->name
);
122 // Build standard list of node permissions for this type.
124 "create $bundle_name section" => array(
125 'title' => t('%bundle_label: Create new sections', array('%bundle_label' => $bundle->label
)),
127 "edit any $bundle_name section" => array(
128 'title' => t('%bundle_label: Edit any sections', array('%bundle_label' => $bundle->label
)),
130 "delete any $bundle_name section" => array(
131 'title' => t('%bundle_label: Delete any sections', array('%bundle_label' => $bundle->label
)),
141 function section_access($op, $section, $account = NULL
) {
142 $rights = &drupal_static(__FUNCTION__
, array());
144 if (!$section || !in_array($op, array('view', 'update', 'delete', 'create'), TRUE
)) {
145 // If there was no section to check against, or the $op was not one of the
146 // supported ones, we return access denied.
149 // If no user object is supplied, the access check is for the current user.
150 if (empty($account)) {
151 $account = $GLOBALS['user'];
154 if (in_array($op, array('view', 'update', 'delete', 'create'), TRUE
) && user_access('administer sections', $account)) {
158 // $section may be either an object or a section bundle. Since section bundles
159 // cannot be an integer, use either sid or bundle as the static cache id.
161 $cid = is_object($section) ?
$section->name
: $section;
163 // If we've already checked access for this section, user and op, return from
165 if (isset($rights[$account->uid
][$cid][$op])) {
166 return $rights[$account->uid
][$cid][$op];
169 if (!user_access('access section', $account)) {
170 $rights[$account->uid
][$cid][$op] = FALSE
;
174 $type = is_string($section) ?
$section : $section->bundle
;
177 foreach(section_bundles() as
$bundle_name => $bundle) {
178 $bundles[] = $bundle_name;
181 if (in_array($type, $bundles)) {
182 if ($op == 'create' && user_access('create ' .
$type .
' section', $account)) {
186 if ($op == 'update') {
187 if (user_access('edit any ' .
$type .
' section', $account)) {
192 if ($op == 'delete') {
193 if (user_access('delete any ' .
$type .
' section', $account)) {
199 if ($op != 'create' && $section->name
) {
200 if (is_object($section) && $op == 'view') {
201 $rights[$account->uid
][$cid][$op] = TRUE
;
209 function _section_add_access() {
210 $bundles = section_bundles();
211 foreach ($bundles as
$bundle) {
212 if (section_access('create', $bundle->name
)) {
216 if (user_access('administer section bundles')) {
223 * Implements hook_ctools_plugin_directory().
225 function section_ctools_plugin_directory($module, $type) {
231 if (in_array($type, $types)) {
232 return 'plugins/' .
$type;
237 * Fetch all bundles for a section.
239 * An array of all available bundles.
241 function section_bundles() {
242 ctools_include('export');
243 return ctools_export_load_object('section_bundle');
247 * Implements hook_menu().
249 function section_menu() {
250 $items['section/autocomplete'] = array(
251 'title' => 'Section autocomplete',
252 'page callback' => 'section_autocomplete',
253 'access callback' => 'section_access',
254 'access arguments' => array('access section'),
255 'type' => MENU_CALLBACK
,
258 $items['admin/section'] = array(
259 'title' => 'Section',
260 'description' => 'Find and manage sections.',
261 'page callback' => 'drupal_get_form',
262 'page arguments' => array('section_admin_section'),
263 'access arguments' => array('access section overview'),
265 'file' => 'section.admin.inc',
268 $items['admin/section/section'] = array(
269 'title' => 'Section',
270 'type' => MENU_DEFAULT_LOCAL_TASK
,
274 $items['section/add'] = array(
275 'title' => 'Add section',
276 'page callback' => 'section_add_page',
277 'access callback' => '_section_add_access',
278 'file' => 'section.pages.inc',
281 $bundles = section_bundles();
282 $bundle_info = array();
283 foreach ($bundles as
$key => $bundle) {
284 $items['section/add/' .
$bundle->name
] = array(
285 'title' => $bundle->label
,
286 'title callback' => 'check_plain',
287 'page callback' => 'section_add',
288 'page arguments' => array($bundle->name
),
289 'access callback' => 'section_access',
290 'access arguments' => array('create', $bundle->name
),
291 'description' => $bundle->description
,
292 'file' => 'section.pages.inc',
296 $items['section/%section'] = array(
297 'title callback' => 'section_page_title',
298 'title arguments' => array(1),
299 // The page callback also invokes drupal_set_title() in case
300 // the menu router's title is overridden by a menu link.
301 'page callback' => 'section_page_view',
302 'page arguments' => array(1),
303 'access callback' => 'section_access',
304 'access arguments' => array('view', 1),
306 $items['section/%section/view'] = array(
308 'type' => MENU_DEFAULT_LOCAL_TASK
,
311 $items['section/%section/edit'] = array(
313 'page callback' => 'section_page_edit',
314 'page arguments' => array(1),
315 'access callback' => 'section_access',
316 'access arguments' => array('update', 1),
318 'type' => MENU_LOCAL_TASK
,
319 'context' => MENU_CONTEXT_PAGE
| MENU_CONTEXT_INLINE
,
320 'file' => 'section.pages.inc',
322 $items['section/%section/delete'] = array(
324 'page callback' => 'drupal_get_form',
325 'page arguments' => array('section_delete_confirm', 1),
326 'access callback' => 'section_access',
327 'access arguments' => array('delete', 1),
329 'type' => MENU_LOCAL_TASK
,
330 'context' => MENU_CONTEXT_INLINE
,
331 'file' => 'section.pages.inc',
338 * Implements hook_menu_local_tasks_alter().
340 function section_menu_local_tasks_alter(&$data, $router_item, $root_path) {
341 // Add action link to 'section/add' on 'admin/section' page.
342 if ($root_path == 'admin/section') {
343 $item = menu_get_item('section/add');
344 if ($item['access']) {
345 $data['actions']['output'][] = array(
346 '#theme' => 'menu_local_action',
354 * Implements hook_admin_paths().
356 function section_admin_paths() {
357 // We can use the same variable as the node module here.
358 if (variable_get('node_admin_theme')) {
360 'section/*/edit' => TRUE
,
361 'section/*/delete' => TRUE
,
362 'section/add' => TRUE
,
363 'section/add/*' => TRUE
,
370 * Implements hook_theme().
372 function section_theme() {
374 'section_add_list' => array(
375 'variables' => array('bundles' => NULL
),
376 'file' => 'section.pages.inc',
382 * Add default section body field to a section bundle.
385 * A section bundle object.
387 * The label for the body instance.
390 * Body field instance.
392 function section_bundle_add_body_field($bundle, $label = 'Body') {
393 // Add or remove the body field, as needed.
394 $field = field_info_field('section_body');
395 $instance = field_info_instance('section', 'section_body', $bundle->name
);
398 'field_name' => 'section_body',
399 'type' => 'text_with_summary',
400 'entity_types' => array('section'),
402 $field = field_create_field($field);
404 if (empty($instance)) {
406 'field_name' => 'section_body',
407 'entity_type' => 'section',
408 'bundle' => $bundle->name
,
410 'widget' => array('type' => 'text_textarea_with_summary'),
411 'settings' => array('display_summary' => TRUE
),
415 'type' => 'text_default',
419 $instance = field_create_instance($instance);
425 * Implements hook_forms().
426 * All sections forms share the same form handler.
428 function section_forms() {
430 if ($bundles = section_bundles()) {
431 foreach (array_keys($bundles) as
$bundle) {
432 $forms[$bundle .
'_section_form']['callback'] = 'section_form';
439 * Entity uri callback.
441 function section_uri($section) {
443 'path' => 'section/' .
$section->name
,
449 * @TODO: Should we use this?
451 function section_page_title($section) {
452 return $section->label
;
456 * Menu callback; view a single section.
458 function section_page_view($section) {
459 // If there is a menu link to this section, the link becomes the last part
460 // of the active trail, and the link name becomes the page title.
461 // Thus, we must explicitly set the page title to be the section title.
462 drupal_set_title($section->label
);
463 $uri = entity_uri('section', $section);
464 // Set the section path as the canonical URL to prevent duplicate content.
465 drupal_add_html_head_link(array('rel' => 'canonical', 'href' => url($uri['path'], $uri['options'])), TRUE
);
466 // Set the non-aliased path as a default shortlink.
467 drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE
)))), TRUE
);
468 return section_show($section);
472 * Generate an array which displays a section detail page.
477 * A $page element suitable for use by drupal_page_render().
479 function section_show($section) {
480 $sections = section_view_multiple(array($section->sid
=> $section), 'full');
485 * Construct a drupal_render() style array from an array of loaded sections.
488 * An array of sections as returned by section_view_multiple().
490 * View mode, e.g. 'full', 'teaser'...
492 * An integer representing the weight of the first node in the list.
494 * (optional) A language code to use for rendering. Defaults to the global
495 * content language of the current request.
498 * An array in the format expected by drupal_render().
500 function section_view_multiple($sections, $view_mode = 'teaser', $weight = 0, $langcode = NULL
) {
501 field_attach_prepare_view('section', $sections, $view_mode, $langcode);
502 entity_prepare_view('section', $sections, $langcode);
504 foreach ($sections as
$section) {
505 $build['sections'][$section->name
] = section_view($section, $view_mode, $langcode);
506 $build['sections'][$section->name
]['#weight'] = $weight;
509 $build['sections']['#sorted'] = TRUE
;
514 * Generate an array for rendering the given node.
516 function section_view($section, $view_mode = 'full', $langcode = NULL
) {
517 if (!isset($langcode)) {
518 $langcode = $GLOBALS['language_content']->language
;
521 $section->content
= field_attach_view('section', $section, $view_mode, $langcode);
523 $build = $section->content
;
524 // We don't need duplicate rendering info in section->content.
525 unset($section->content
);
528 '#theme' => 'section',
530 '#view_mode' => $view_mode,
531 '#language' => $langcode,
534 // Add contextual links for this node, except when the node is already being
535 // displayed on its own page. Modules may alter this behavior (for example,
536 // to restrict contextual links to certain view modes) by implementing
537 // hook_node_view_alter().
539 if (!empty($node->nid) && !($view_mode == 'full' && node_is_page($node))) {
540 $build['#contextual_links']['node'] = array('node', array($node->nid));
548 * Load node entities from the database.
550 function section_load_multiple($names = array(), $conditions = array(), $reset = FALSE
) {
551 return entity_load_multiple_by_name('section', $names, $conditions);
555 * Load a section object from the database.
557 function section_load($name = NULL
) {
558 $names = (isset($name) ?
array($name) : array());
559 $sections = section_load_multiple($names);
560 return $sections ?
reset($sections) : FALSE
;
564 * Returns the section bundle of the passed section or bundle string.
566 function section_bundle_get_name($section) {
567 $bundle_name = _section_extract_bundle($section);
568 $bundle = section_bundle_load($bundle_name);
570 return isset($bundle->label
) ?
$bundle->label
: FALSE
;
574 * Extract the bundle name.
576 function _section_extract_bundle($section) {
577 return is_object($section) ?
$section->bundle
: $section;
586 function section_delete($sid) {
587 section_delete_multiple(array($sid));
591 * Delete multiple sections.
594 * An array of section IDs.
596 function section_delete_multiple($sids) {
597 $transaction = db_transaction();
599 $sections = section_load_multiple($sids, array());
602 foreach ($sections as
$sid => $section) {
603 field_attach_delete('section', $section);
605 entity_get_controller('section')->delete($sids);
607 catch (Exception
$e) {
608 $transaction->rollback();
609 watchdog_exception('section', $e);
613 // Clear the entity cache.
614 entity_get_controller('section')->resetCache();
621 function section_entity_insert($entity, $type) {
622 if ($type !== 'section') {
626 if (module_exists('path')) {
627 if (isset($entity->path
)) {
628 $path = $entity->path
;
629 $path['alias'] = trim($path['alias']);
630 // Only save a non-empty alias.
631 if (!empty($path['alias'])) {
632 // Ensure fields for programmatic executions.
633 $path['source'] = 'section/' .
$entity->sid
;
634 $path['language'] = LANGUAGE_NONE
;
640 if (module_exists('pathauto')) {
641 section_update_alias($entity, 'insert');
648 function section_entity_update($entity, $type) {
649 if ($type !== 'section') {
653 if (module_exists('path')) {
654 if (isset($entity->path
)) {
655 $path = $entity->path
;
656 $path['alias'] = trim($path['alias']);
657 // Delete old alias if user erased it.
658 if (!empty($path['pid']) && empty($path['alias'])) {
659 path_delete($path['pid']);
661 // Only save a non-empty alias.
662 if (!empty($path['alias'])) {
663 // Ensure fields for programmatic executions.
664 $path['source'] = 'section/' .
$entity->name
;
665 $path['language'] = LANGUAGE_NONE
;
671 if (module_exists('pathauto')) {
672 section_update_alias($entity, 'update');
679 function section_entity_delete($entity, $type) {
680 if ($type !== 'section') {
684 if (module_exists('path')) {
685 path_delete(array('source' => 'section/' .
$entity->name
));
688 if (module_exists('pathauto')) {
689 pathauto_entity_path_delete_all('section', $entity, "section/{$entity->name}");
694 * Menu callback; Retrieve a JSON object containing autocomplete suggestions for
697 function section_autocomplete($string = '') {
700 $result = db_select('section', 's')
701 ->fields('s', array('name', 'label'))
702 ->condition('name', '%' .
db_like($string) .
'%', 'LIKE')
705 foreach ($result as
$section) {
706 $matches[$section->name
] = check_plain($section->label
);
710 drupal_json_output($matches);
714 * Implements hook_path_alias_types().
716 function section_path_alias_types() {
717 $objects['section/'] = t('Section');
723 * Implements hook_pathauto().
725 function section_pathauto($op) {
729 $settings['module'] = 'section';
730 $settings['token_type'] = 'section';
731 $settings['groupheader'] = t('Section paths');
732 $settings['patterndescr'] = t('Default path pattern (applies to all section types with blank patterns below)');
733 $settings['patterndefault'] = 'section/[section:name]';
734 $settings['batch_update_callback'] = 'section_pathauto_bulk_update_batch_process';
735 $settings['batch_file'] = drupal_get_path('module', 'section') .
'/section.pathauto.inc';
737 $bundles = section_bundles();
738 foreach ($bundles as
$bundle) {
739 $settings['patternitems'][$bundle->name
] = t('Pattern for all @section_type paths', array('@section_type' => $bundle->label
));
741 return (object) $settings;
748 * Update the URL aliases for an individual section.
750 function section_update_alias($section, $op, array $options = array()) {
751 // Skip processing if the user has disabled pathauto for the node.
752 if (isset($section->path
['pathauto']) && empty($section->path
['pathauto'])) {
756 // Skip processing if the section has no pattern.
757 if (!pathauto_pattern_load_by_entity('section', $section->bundle
)) {
761 module_load_include('inc', 'pathauto');
762 $uri = entity_uri('section', $section);
763 pathauto_create_alias('section', $op, $uri['path'], array('section' => $section), $section->bundle
);
767 * Update the URL aliases for multiple sections.
769 function section_update_alias_multiple(array $sids, $op, array $options = array()) {
770 $options += array('message' => FALSE
);
772 $sections = section_load_multiple($sids);
773 foreach ($sections as
$section) {
774 section_update_alias($section, $op, $options);
777 if (!empty($options['message'])) {
778 drupal_set_message(format_plural(count($sids), 'Updated URL alias for 1 section.', 'Updated URL aliases for @count sections.'));
785 function section_object_prepare(&$section) {
786 $bundle = section_bundle_load($section->bundle
);
787 $bundle_settings = unserialize($bundle->settings
);
788 $settings = $bundle_settings['section_options'];
790 if (!isset($section->sid
) || isset($section->is_new
)) {
797 // Always use the default revision setting.
798 $section->revision
= in_array('revision', $settings);