' . t('About') . ''; $output .= '
' . t('The Read More Control module can add and control the read more link in many different content types, including nodes, terms and even users.') . '
'; return $output; } } /** * Implements hook_theme(). */ function readmorecontrol_theme($existing, $type, $theme, $path) { return array( 'readmorecontrol_link' => array( 'variables' => array( 'entity_type' => NULL, 'entity' => NULL, 'bundle' => NULL, 'link' => NULL, ), ), ); } /** * Implements hook_menu(). */ function readmorecontrol_menu() { $items['admin/config/content/read-more-control'] = array( 'title' => 'Read more settings', 'page callback' => 'drupal_get_form', 'page arguments' => array('readmorecontrol_admin_settings_form', 'node'), 'description' => 'Configure the Read more link settings.', 'access arguments' => array('administer site configuration'), 'file' => 'readmorecontrol.admin.inc', ); $entity_info = entity_get_info(); foreach ($entity_info as $entity_type => $info) { if (readmorecontrol_supported_entity($entity_type, $info)) { if ($entity_type == 'node') { $items['admin/config/content/read-more-control/' . $entity_type] = array( 'title' => $info['label'], 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); } else { $items['admin/config/content/read-more-control/' . $entity_type] = array( 'title' => $info['label'], 'page callback' => 'drupal_get_form', 'page arguments' => array('readmorecontrol_admin_settings_form', $entity_type), 'description' => 'Configure the Read more link settings.', 'access arguments' => array('administer site configuration'), 'file' => 'readmorecontrol.admin.inc', 'type' => MENU_LOCAL_TASK, ); } } } return $items; } /** * Implements hook_node_type_update(). */ function readmorecontrol_node_type_update($info) { if (!empty($info->old_type) && $info->old_type != $info->type) { variable_set('readmorecontrol_behaviour__node__' . $info->type, variable_get('readmorecontrol_behaviour__node__' . $info->old_type, 'always')); variable_del('readmorecontrol_behaviour__node__' . $info->old_type); variable_set('readmorecontrol_format__node__' . $info->type, variable_get('readmorecontrol_format__node__' . $info->old_type, array())); variable_del('readmorecontrol_format__node__' . $info->old_type); // Update all of the view modes if required. $entity_info = entity_get_info('node'); foreach ($entity_info['view modes'] as $view_mode => $view_mode_settings) { if ($old_settings = variable_get('readmorecontrol_behaviour__node__' . $info->old_type . '__' . $view_mode, FALSE)) { variable_set('readmorecontrol_behaviour__node__' . $info->type . '__' . $view_mode, $old_settings); variable_del('readmorecontrol_behaviour__node__' . $info->old_type); } if ($old_settings = variable_get('readmorecontrol_format__node__' . $info->old_type . '__' . $view_mode, FALSE)) { variable_set('readmorecontrol_format__node__' . $info->type . '__' . $view_mode, $old_settings); variable_del('readmorecontrol_format__node__' . $info->old_type); } } } } /** * Implements hook_node_type_delete(). */ function readmorecontrol_node_type_delete($info) { variable_del('readmorecontrol_behaviour__node__' . $info->type); variable_del('readmorecontrol_format__node__' . $info->type); } /** * Implements hook_form_FORM_ID_alter(). */ function readmorecontrol_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) { module_load_include('admin.inc', 'readmorecontrol'); _readmorecontrol_form_field_ui_field_edit_form_alter($form, $form_state, $form_id); } function readmorecontrol_form_field_ui_display_overview_form_alter_submit(&$form, &$form_state) { module_load_include('admin.inc', 'readmorecontrol'); _readmorecontrol_form_field_ui_display_overview_form_alter_submit($form, $form_state); } /** * Implements hook_form_FORM_ID_alter(). */ function readmorecontrol_form_field_ui_display_overview_form_alter(&$form, &$form_state, $display_overview = FALSE) { module_load_include('admin.inc', 'readmorecontrol'); _readmorecontrol_form_field_ui_display_overview_form_alter($form, $form_state, $display_overview); } /** * Preprocessor for search result. * * @see search-result.tpl.php */ function readmorecontrol_preprocess_search_result(&$variables) { // Best guess here, e.g. node or user. $type = $variables['module']; if (isset($variables['result'][$type]) && readmorecontrol_supported_entity($type)) { $entity = $variables['result'][$type]; if (is_object($entity) && !empty($entity->readmorelink)) { if ($entity->readmore_required) { switch ($entity->readmorelink_placement) { case 'search_info': $variables['info_split'][] = $entity->readmorelink; if (empty($variables['info'])) { $variables['info'] = $entity->readmorelink; } else { $variables['info'] .= ' - ' . $entity->readmorelink; } break; default: $elm = strpos($entity->readmorelink_placement, '_inline') ? 'span' : 'div'; $variables['snippet'] .= " <{$elm} class=\"read-more-link\">" . $entity->readmorelink . "{$elm}>"; break; } } } } } ################################################################################ # Helper functions for parsing various settings and options. # ################################################################################ /** * Helper function to get a list of view modes that should not have a Read more * link applied to these. */ function readmorecontrol_excluded_view_modes() { return array( 'search_index', 'token', 'diff_standard', 'diff_complete', ); } /** * Determines if the entity can support a Read more link. */ function readmorecontrol_supported_entity($entity_type, $info = NULL) { if (!$info) { $info = entity_get_info($entity_type); } if ((!empty($info['label callback']) || !empty($info['entity keys']['label'])) && !empty($info['uri callback'])) { if (!empty($info['view modes'])) { $excluded_modes = variable_get('readmorecontrol_disabled_view_modes', readmorecontrol_excluded_view_modes()); $excluded_modes[] = 'default'; $excluded_modes[] = 'full'; $modes = array_keys($info['view modes']); $target_modes = array_diff($modes, $excluded_modes); return !empty($target_modes); } } return FALSE; } /** * Helper function to determine the Read more link behaviour. */ function readmorecontrol_entity_behaviour($entity_type, $bundle, $view_mode) { // This blocks all processing within entity_view(). if (in_array($view_mode, readmorecontrol_excluded_view_modes())) { // Defaulting to none rather than never to prevent any additional processing. return 'none'; } else { $node_teaser = $entity_type == 'node' && $view_mode == 'teaser'; $behaviour = variable_get("readmorecontrol_behaviour__{$entity_type}__{$bundle}__{$view_mode}", $node_teaser ? 'default' : 'none'); if ($behaviour == 'default') { $behaviour = variable_get("readmorecontrol_behaviour__{$entity_type}__{$bundle}", 'default'); if ($behaviour == 'default') { $system_default = $node_teaser ? 'always' : 'none'; $behaviour = variable_get("readmorecontrol_behaviour__{$entity_type}", $system_default); } } return $behaviour; } } /** * Helper function to get any formatting settings. */ function readmorecontrol_format_settings($entity_type, $bundle = NULL, $view_mode = NULL, $is_edit = FALSE) { $settings = array(); if ($is_edit) { if ($view_mode && $view_mode != 'default') { $settings += (array) variable_get('readmorecontrol_format__' . $entity_type . '__' . $bundle. '__' . $view_mode, array('enabled' => 'global')); } elseif ($bundle) { $settings += (array) variable_get('readmorecontrol_format__' . $entity_type . '__' . $bundle, array('enabled' => 'global')); } else { $settings += (array) variable_get('readmorecontrol_format__' . $entity_type, array('enabled' => 'none')); } } else { // Find the setting with the highest precesion, but discard if the use // global setting is selected. if ($view_mode) { $settings += (array) variable_get('readmorecontrol_format__' . $entity_type . '__' . $bundle. '__' . $view_mode, array('enabled' => 'global')); if (!$is_edit && $settings['enabled'] == 'global') { $settings = array(); } } if ($bundle) { $settings += (array) variable_get('readmorecontrol_format__' . $entity_type . '__' . $bundle, array('enabled' => 'global')); if ($settings['enabled'] == 'global') { $settings = array(); } } $settings += (array) variable_get('readmorecontrol_format__' . $entity_type, array('enabled' => 'none')); } $settings += array( 'enabled' => 'none', 'text' => '', 'href' => '', 'query' => '', 'fragment' => '', 'title' => '', 'class' => '', 'rel' => '', 'target' => '', 'placement' => readmorecontrol_default_placement($entity_type, $view_mode), ); return $settings; } /** * Helper function to determine the best placement default value. */ function readmorecontrol_default_placement($entity_type, $view_mode) { switch ($view_mode) { case 'search_result': return 'search_snippet'; default: return 'none'; } } /** * A helper function to help determine if a field should be tested. * * Checks the instance settings and field view access rights. */ function readmorecontrol_field_requires_processing($entity_type, $entity, $field, $instance) { if (field_access('view', $field, $entity_type, $entity)) { // Test the default action to determine if we should use this field. switch ($entity->readmorebehaviour) { case 'when_required': // Check the field settings to see if this field is to be ignored. if ($behaviour = readmorecontrol_instance_settings($instance)) { return $behaviour == 'process'; } return TRUE; case 'when_required_text': if (in_array($field['type'], array('text_with_summary', 'text_long'))) { if ($behaviour = readmorecontrol_instance_settings($instance)) { return $behaviour == 'process'; } return TRUE; } break; case 'when_required_body': if ($field['field_name'] == 'body') { if ($behaviour = readmorecontrol_instance_settings($instance)) { return $behaviour == 'process'; } return TRUE; } break; } } return FALSE; } /** * Helper function to determine the instance readmore_behaviour setting. */ function readmorecontrol_instance_settings($instance) { // Check the field settings to see if this field is to be ignored. if (isset($instance['readmore_behaviour'])) { if ($instance['readmore_behaviour'] != 'default') { return $instance['readmore_behaviour']; } } return FALSE; } ################################################################################ # Core processing functions. # ################################################################################ /** * Extract, update or construct the read more link. */ function readmorecontrol_entity_view($entity, $entity_type, $view_mode, $langcode) { // The module makes the assumption that these are the only two "full" view // modes to compare against. if ($view_mode == 'full' || $view_mode == 'default') { return; } // Ensure that this entity is actually supported. $entity_info = entity_get_info($entity_type); if (!readmorecontrol_supported_entity($entity_type, $entity_info)) { return; } // Only process enabled view modes. list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity); $behaviour = readmorecontrol_entity_behaviour($entity_type, $bundle, $view_mode); if ($behaviour == 'none') { return; } $full_mode = empty($entity_info['view modes']['full']) ? 'default' : 'full'; $view_mode_settings = field_view_mode_settings($entity_type, $bundle); $actual_mode = empty($view_mode_settings[$view_mode]['custom_settings']) ? 'default' : $view_mode; $actual_full_mode = empty($view_mode_settings[$full_mode]['custom_settings']) ? 'default' : $full_mode; // Determine the behaviour of the modules processing of the link. $entity->readmorebehaviour = $behaviour; switch ($entity->readmorebehaviour) { case 'always': $entity->readmore_required = TRUE; break; case 'never': $entity->readmore_required = FALSE; break; default: // Test the view mode to see really different. if ($actual_mode == $actual_full_mode) { $entity->readmore_required = FALSE; } else { foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) { // Get the field display info for full view mode. $display = field_get_display($instance, $view_mode, $entity); $display_full = field_get_display($instance, $full_mode, $entity); // If the full view mode is hidden, we can ignore this field. if ($display_full['type'] == 'hidden') { continue; } $field = field_info_field($field_name); if (readmorecontrol_field_requires_processing($entity_type, $entity, $field, $instance)) { // Only test fields that have data. $items = field_get_items($entity_type, $entity, $field_name, $langcode); if (!empty($items)) { // If current view is hidden, we can assume that the main view // has values. if ($display['type'] == 'hidden') { $entity->readmore_required = TRUE; break; } $func = "readmorecontrol_{$display['module']}_compare_items"; if (function_exists($func)) { $content = array( 'display' => $display, 'display_full' => $display_full, 'instance' => $instance, 'field' => $field, 'langcode' => $langcode, ); if ($func($items, $content)) { $entity->readmore_required = TRUE; break; } } else { if ($display_full['type'] != $display['type'] || $display_full['settings'] !== $display['settings']) { $entity->readmore_required = TRUE; break; } } } } } } break; } // No differences were found. if (!isset($entity->readmore_required)) { $entity->readmore_required = FALSE; } // Apply the settings. $format = readmorecontrol_format_settings($entity_type, $bundle, $view_mode); // Create and append a copy of the Read More link to the entity itself. $has_readmore = !empty($entity->content['links']) && !empty($entity->content['links'][$entity_type]) && !empty($entity->content['links'][$entity_type]['#links'][$entity_type . '-readmore']); if ($has_readmore) { $readmorelink = $entity->content['links'][$entity_type]['#links'][$entity_type . '-readmore']; } else { $title = entity_label($entity_type, $entity); $title_stripped = strip_tags($title); $uri = entity_uri($entity_type, $entity); $readmorelink = array( 'title' => t('Read more about @title', array('@title' => $title_stripped)), 'href' => $uri['path'], 'html' => TRUE, 'attributes' => array('title' => $title_stripped), ); if (in_array($view_mode, variable_get('readmodecontrol_external_view_modes', array('rss')))) { $readmorelink['absolute'] = 1; } } if (!empty($format['text'])) { if ($title = filter_xss_admin(_rmc_token_replace($format['text'], $entity_type, $entity))) { $readmorelink['title'] = $title; $readmorelink['html'] = 1; } } // The generated URL is passed through check_plain() internally. if (!empty($format['href'])) { if ($format['href'] == '