Newer
Older
* The core module that allows content to be submitted to the site.
*
* Modules and scripts may programmatically submit nodes using the usual form
* API pattern.
Angie Byron
committed
use Drupal\Component\Utility\Xss;
Dries Buytaert
committed
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
Angie Byron
committed
use Drupal\Core\Render\Element;
Angie Byron
committed
use Drupal\Core\Routing\RouteMatchInterface;
Angie Byron
committed
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\Response;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\field\Entity\FieldStorageConfig;
Alex Pott
committed
use Drupal\field\Entity\FieldInstanceConfig;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\node\NodeTypeInterface;
use Drupal\node\NodeInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
Angie Byron
committed
use Drupal\Core\Template\Attribute;
use Drupal\file\Entity\File;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\block\Entity\Block;
use Drupal\Core\Session\AccountInterface;
Dries Buytaert
committed
/**
* Denotes that the node is not published.
Dries Buytaert
committed
*/
const NODE_NOT_PUBLISHED = 0;
Dries Buytaert
committed
/**
* Denotes that the node is published.
Dries Buytaert
committed
*/
const NODE_PUBLISHED = 1;
Dries Buytaert
committed
/**
* Denotes that the node is not promoted to the front page.
Dries Buytaert
committed
*/
const NODE_NOT_PROMOTED = 0;
Dries Buytaert
committed
/**
* Denotes that the node is promoted to the front page.
Dries Buytaert
committed
*/
const NODE_PROMOTED = 1;
Dries Buytaert
committed
/**
* Denotes that the node is not sticky at the top of the page.
Dries Buytaert
committed
*/
const NODE_NOT_STICKY = 0;
Dries Buytaert
committed
/**
* Denotes that the node is sticky at the top of the page.
Dries Buytaert
committed
*/
const NODE_STICKY = 1;
Dries Buytaert
committed
Dries Buytaert
committed
/**
* Denotes that access is allowed for a node.
*
* Modules should return this value from hook_node_access() to allow access to a
* node.
Dries Buytaert
committed
*/
Dries Buytaert
committed
const NODE_ACCESS_ALLOW = TRUE;
Dries Buytaert
committed
/**
* Denotes that access is denied for a node.
*
* Modules should return this value from hook_node_access() to deny access to a
* node.
Dries Buytaert
committed
*/
Dries Buytaert
committed
const NODE_ACCESS_DENY = FALSE;
Dries Buytaert
committed
/**
* Denotes that access is unaffected for a node.
*
* Modules should return this value from hook_node_access() to indicate no
* effect on node access.
Dries Buytaert
committed
*/
const NODE_ACCESS_IGNORE = NULL;
Dries Buytaert
committed
Dries Buytaert
committed
* Implements hook_help().
Angie Byron
committed
function node_help($route_name, RouteMatchInterface $route_match) {
// Remind site administrators about the {node_access} table being flagged
// for rebuild. We don't need to issue the message on the confirm form, or
// while the rebuild is being processed.
if ($route_name != 'node.configure_rebuild_confirm' && $route_name != 'system.batch_page.normal' && $route_name != 'help.page.node' && $route_name != 'help.main'
&& \Drupal::currentUser()->hasPermission('access administration pages') && node_access_needs_rebuild()) {
if ($route_name == 'system.status') {
$message = t('The content access permissions need to be rebuilt.');
}
else {
$message = t('The content access permissions need to be rebuilt. <a href="!node_access_rebuild">Rebuild permissions</a>.', array('!node_access_rebuild' => \Drupal::url('node.configure_rebuild_confirm')));
}
drupal_set_message($message, 'error');
}
switch ($route_name) {
case 'help.page.node':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Node module manages the creation, editing, deletion, settings, and display of the main site content. Content items managed by the Node module are typically displayed as pages on your site, and include a title, some meta-data (author, creation time, content type, etc.), and optional fields containing text or other data (fields are managed by the <a href="!field">Field module</a>). For more information, see <a href="!node">the online documentation for the Node module</a>.', array('!node' => 'https://drupal.org/documentation/modules/node', '!field' => \Drupal::url('help.page', array('name' => 'field')))) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Creating content') . '</dt>';
$output .= '<dd>' . t('When new content is created, the Node module records basic information about the content, including the author, date of creation, and the <a href="!content-type">Content type</a>. It also manages the <em>publishing options</em>, which define whether or not the content is published, promoted to the front page of the site, and/or sticky at the top of content lists. Default settings can be configured for each <a href="!content-type">type of content</a> on your site.', array('!content-type' => \Drupal::url('node.overview_types'))) . '</dd>';
$output .= '<dt>' . t('Creating custom content types') . '</dt>';
$output .= '<dd>' . t('The Node module gives users with the <em>Administer content types</em> permission the ability to <a href="!content-new">create new content types</a> in addition to the default ones already configured. Creating custom content types allows you the flexibility to add <a href="!field">fields</a> and configure default settings that suit the differing needs of various site content.', array('!content-new' => \Drupal::url('node.type_add'), '!field' => \Drupal::url('help.page', array('name' => 'field')))) . '</dd>';
$output .= '<dt>' . t('Administering content') . '</dt>';
Alex Pott
committed
$output .= '<dd>' . t('The <a href="!content">Content administration page</a> allows you to review and bulk manage your site content.', array('!content' => \Drupal::url('system.admin_content'))) . '</dd>';
$output .= '<dt>' . t('Creating revisions') . '</dt>';
$output .= '<dd>' . t('The Node module also enables you to create multiple versions of any content, and revert to older versions using the <em>Revision information</em> settings.') . '</dd>';
$output .= '<dt>' . t('User permissions') . '</dt>';
$output .= '<dd>' . t('The Node module makes a number of permissions available for each content type, which can be set by role on the <a href="!permissions">permissions page</a>.', array('!permissions' => \Drupal::url('user.admin_permissions', array(), array('fragment' => 'module-node')))) . '</dd>';
return $output;
Angie Byron
committed
case 'node.type_add':
return '<p>' . t('Individual content types can have different fields, behaviors, and permissions assigned to them.') . '</p>';
Angie Byron
committed
case 'field_ui.form_display_overview_node':
case 'field_ui.form_display_overview_form_mode_node':
Angie Byron
committed
$type = $route_match->getParameter('node_type');
Alex Pott
committed
return '<p>' . t('Content items can be edited using different form modes. Here, you can define which fields are shown and hidden when %type content is edited in each form mode, and define how the field form widgets are displayed in each form mode.', array('%type' => $type->label())) . '</p>' ;
Alex Pott
committed
case 'field_ui.display_overview_node':
case 'field_ui.display_overview_view_mode_node':
Angie Byron
committed
$type = $route_match->getParameter('node_type');
Angie Byron
committed
return '<p>' . t('Content items can be displayed using different view modes: Teaser, Full content, Print, RSS, etc. <em>Teaser</em> is a short format that is typically used in lists of multiple content items. <em>Full content</em> is typically used when the content is displayed on its own page.') . '</p>' .
'<p>' . t('Here, you can define which fields are shown and hidden when %type content is displayed in each view mode, and define how the fields are displayed in each view mode.', array('%type' => $type->label())) . '</p>';
Angie Byron
committed
Alex Pott
committed
case 'entity.node.version_history':
return '<p>' . t('Revisions allow you to track differences between multiple versions of your content, and revert back to older versions.') . '</p>';
Angie Byron
committed
Alex Pott
committed
case 'entity.node.edit_form':
Angie Byron
committed
$node = $route_match->getParameter('node');
$type = $node->getType();
Angie Byron
committed
return (!empty($type->help) ? Xss::filterAdmin($type->help) : '');
case 'node.add':
Angie Byron
committed
$type = $route_match->getParameter('node_type');
return (!empty($type->help) ? Xss::filterAdmin($type->help) : '');
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
Dries Buytaert
committed
* Implements hook_theme().
Dries Buytaert
committed
*/
function node_theme() {
return array(
Dries Buytaert
committed
'node' => array(
'render element' => 'elements',
'template' => 'node',
Dries Buytaert
committed
),
Dries Buytaert
committed
'node_search_admin' => array(
'render element' => 'form',
Dries Buytaert
committed
),
'node_add_list' => array(
'variables' => array('content' => NULL),
'file' => 'node.pages.inc',
'template' => 'node-add-list',
Dries Buytaert
committed
),
Dries Buytaert
committed
'node_edit_form' => array(
'render element' => 'form',
'template' => 'node-edit-form',
),
'field__node__title' => array(
'base hook' => 'field',
Angie Byron
committed
'template' => 'field--node--title',
Dries Buytaert
committed
);
}
Dries Buytaert
committed
/**
Alex Pott
committed
* Implements hook_entity_view_display_alter().
Dries Buytaert
committed
*/
Alex Pott
committed
function node_entity_view_display_alter(EntityViewDisplayInterface $display, $context) {
if ($context['entity_type'] == 'node') {
// Hide field labels in search index.
if ($context['view_mode'] == 'search_index') {
foreach ($display->getComponents() as $name => $options) {
if (isset($options['label'])) {
$options['label'] = 'hidden';
$display->setComponent($name, $options);
}
}
}
}
}
/**
* Implements hook_entity_form_display_alter().
*/
function node_entity_form_display_alter(EntityFormDisplayInterface $form_display, $context) {
if ($context['entity_type'] == 'node') {
$node_type = node_type_load($context['bundle']);
Dries Buytaert
committed
}
}
Dries Buytaert
committed
* Gathers a listing of links to nodes.
* A database result object from a query to fetch node entities. If your
* query joins the {comment_entity_statistics} table so that the comment_count
* field is available, a title attribute will be added to show the number of
* comments.
* (optional) A heading for the resulting list.
Dries Buytaert
committed
* A renderable array containing a list of linked node titles fetched from
* $result, or FALSE if there are no rows in $result.
Dries Buytaert
committed
$items = array();
Dries Buytaert
committed
$num_rows = FALSE;
Dries Buytaert
committed
foreach ($result as $node) {
Angie Byron
committed
// Do not use $node->label() here, because $node comes from the database.
$items[] = l($node->title, 'node/' . $node->nid, !empty($node->comment_count) ? array('attributes' => array('title' => format_plural($node->comment_count, '1 comment', '@count comments'))) : array());
Dries Buytaert
committed
$num_rows = TRUE;
Dries Buytaert
committed
return $num_rows ? array('#theme' => 'item_list__node', '#items' => $items, '#title' => $title) : FALSE;
Jennifer Hodgdon
committed
* Determines the type of marker to be displayed for a given node.
Angie Byron
committed
* @param int $nid
Angie Byron
committed
* @param int $timestamp
Angie Byron
committed
* @return int
Dries Buytaert
committed
* One of the MARK constants.
Dries Buytaert
committed
function node_mark($nid, $timestamp) {
Angie Byron
committed
$cache = &drupal_static(__FUNCTION__, array());
if (\Drupal::currentUser()->isAnonymous() || !\Drupal::moduleHandler()->moduleExists('history')) {
Dries Buytaert
committed
return MARK_READ;
}
Dries Buytaert
committed
$cache[$nid] = history_read($nid);
Dries Buytaert
committed
if ($cache[$nid] == 0 && $timestamp > HISTORY_READ_LIMIT) {
Dries Buytaert
committed
return MARK_NEW;
}
Dries Buytaert
committed
elseif ($timestamp > $cache[$nid] && $timestamp > HISTORY_READ_LIMIT) {
Dries Buytaert
committed
return MARK_UPDATED;
}
return MARK_READ;
Angie Byron
committed
/**
* Returns a list of all the available node types.
*
Dries Buytaert
committed
* This list can include types that are queued for addition or deletion.
*
Angie Byron
committed
* @return \Drupal\node\NodeTypeInterface[]
* An array of node type entities, keyed by ID.
Dries Buytaert
committed
*
* @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* Use \Drupal\node\Entity\NodeType::loadMultiple().
*
* @see node_type_load()
Angie Byron
committed
*/
function node_type_get_types() {
return NodeType::loadMultiple();
Angie Byron
committed
}
/**
Dries Buytaert
committed
* Returns a list of available node type names.
*
* This list can include types that are queued for addition or deletion.
Angie Byron
committed
*
Angie Byron
committed
* @return string[]
* An array of node type labels, keyed by the node type name.
Angie Byron
committed
*/
function node_type_get_names() {
Alex Pott
committed
return array_map(function ($bundle_info) {
return $bundle_info['label'];
}, \Drupal::entityManager()->getBundleInfo('node'));
}
/**
* Returns the node type label for the passed node.
*
* @param \Drupal\node\NodeInterface $node
* A node entity to return the node type's label for.
*
* @return string|false
* The node type label or FALSE if the node type is not found.
* @todo Add this as generic helper method for config entities representing
* entity bundles.
function node_get_type_label(NodeInterface $node) {
$type = entity_load('node_type', $node->bundle());
return $type ? $type->label() : FALSE;
}
/**
* Description callback: Returns the node type description.
*
* @param \Drupal\node\NodeTypeInterface $node_type
* The node type object.
*
* @return string
* The node type description.
*/
function node_type_get_description(NodeTypeInterface $node_type) {
return $node_type->description;
}
Angie Byron
committed
/**
* Menu argument loader: Loads a node type by string.
Angie Byron
committed
*
* @param $name
* The machine name of a node type to load.
Angie Byron
committed
*
* @return \Drupal\node\NodeTypeInterface
Dries Buytaert
committed
* A node type object or NULL if $name does not exist.
*
* @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* Use \Drupal\node\Entity\NodeType::load().
Angie Byron
committed
*/
function node_type_load($name) {
return NodeType::load($name);
}
Dries Buytaert
committed
Dries Buytaert
committed
/**
* Adds the default body field to a node type.
Dries Buytaert
committed
*
* @param \Drupal\node\NodeTypeInterface $type
* A node type object.
* @param $label
* (optional) The label for the body instance.
Dries Buytaert
committed
*
* @return
* Body field instance.
Dries Buytaert
committed
*/
function node_add_body_field(NodeTypeInterface $type, $label = 'Body') {
Dries Buytaert
committed
// Add or remove the body field, as needed.
$field_storage = FieldStorageConfig::loadByName('node', 'body');
Alex Pott
committed
$instance = FieldInstanceConfig::loadByName('node', $type->id(), 'body');
if (empty($field_storage)) {
$field_storage = entity_create('field_storage_config', array(
'name' => 'body',
'entity_type' => 'node',
'type' => 'text_with_summary',
));
$field_storage->save();
Dries Buytaert
committed
}
if (empty($instance)) {
$instance = entity_create('field_instance_config', array(
'field_storage' => $field_storage,
'bundle' => $type->id(),
'label' => $label,
'settings' => array('display_summary' => TRUE),
));
$instance->save();
Alex Pott
committed
// Assign widget settings for the 'default' form mode.
entity_get_form_display('node', $type->type, 'default')
->setComponent('body', array(
Alex Pott
committed
'type' => 'text_textarea_with_summary',
))
->save();
// Assign display settings for the 'default' and 'teaser' view modes.
entity_get_display('node', $type->type, 'default')
->setComponent('body', array(
'label' => 'hidden',
'type' => 'text_default',
))
->save();
// The teaser view mode is created by the Standard profile and therefore
// might not exist.
$view_modes = \Drupal::entityManager()->getViewModes('node');
if (isset($view_modes['teaser'])) {
entity_get_display('node', $type->type, 'teaser')
->setComponent('body', array(
'label' => 'hidden',
'type' => 'text_summary_or_trimmed',
))
->save();
}
Dries Buytaert
committed
}
Dries Buytaert
committed
return $instance;
Dries Buytaert
committed
* Implements hook_entity_extra_field_info().
function node_entity_extra_field_info() {
$module_language_enabled = \Drupal::moduleHandler()->moduleExists('language');
Angie Byron
committed
$description = t('Node module element');
foreach (node_type_get_types() as $bundle) {
// Add the 'language' select if Language module is enabled and the bundle
// has multilingual support.
// Visibility of the ordering of the language selector is the same as on the
Angie Byron
committed
// node/add form.
if ($module_language_enabled) {
$configuration = language_get_default_configuration('node', $bundle->type);
Dries Buytaert
committed
if ($configuration['language_show']) {
Angie Byron
committed
$extra['node'][$bundle->type]['form']['langcode'] = array(
Angie Byron
committed
'label' => t('Language'),
'description' => $description,
'weight' => 0,
);
}
}
Angie Byron
committed
$extra['node'][$bundle->type]['display']['langcode'] = array(
Angie Byron
committed
'label' => t('Language'),
'description' => $description,
'weight' => 0,
'visible' => FALSE,
);
Dries Buytaert
committed
$extra['node'][$bundle->type]['display']['links'] = array(
'label' => t('Links'),
'description' => $description,
'weight' => 100,
'visible' => TRUE,
);
}
Dries Buytaert
committed
}
/**
Neil Drumm
committed
* Updates all nodes of one type to be of another type.
*
* @param string $old_id
Neil Drumm
committed
* The current node type of the nodes.
* @param string $new_id
Neil Drumm
committed
* The new node type of the nodes.
*
* @return
Neil Drumm
committed
* The number of nodes whose node type field was modified.
*/
function node_type_update_nodes($old_id, $new_id) {
return \Drupal::entityManager()->getStorage('node')->updateType($old_id, $new_id);
/**
* Loads node entities from the database.
*
* This function should be used whenever you need to load more than one node
Jennifer Hodgdon
committed
* from the database. Nodes are loaded into memory and will not require database
* access if loaded again during the same page request.
* @param array $nids
* (optional) An array of entity IDs. If omitted, all entities are loaded.
* @param bool $reset
* (optional) Whether to reset the internal node_load() cache. Defaults to
* FALSE.
* @return \Drupal\node\NodeInterface[]
* An array of node entities indexed by nid.
Angie Byron
committed
*
* @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* Use \Drupal\node\Entity\Node::loadMultiple().
*
* @see entity_load_multiple()
Alex Pott
committed
* @see \Drupal\Core\Entity\Query\EntityQueryInterface
function node_load_multiple(array $nids = NULL, $reset = FALSE) {
if ($reset) {
\Drupal::entityManager()->getStorage('node')->resetCache($nids);
}
return Node::loadMultiple($nids);
}
/**
* Loads a node entity from the database.
*
* @param int $nid
* The node ID.
* @param bool $reset
* (optional) Whether to reset the node_load_multiple() cache. Defaults to
* FALSE.
*
* @return \Drupal\node\NodeInterface|null
* A fully-populated node entity, or NULL if the node is not found.
*
* @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* Use \Drupal\node\Entity\Node::load().
*/
function node_load($nid = NULL, $reset = FALSE) {
if ($reset) {
\Drupal::entityManager()->getStorage('node')->resetCache(array($nid));
}
return Node::load($nid);
}
/**
* Loads a node revision from the database.
*
* @param int $vid
* The node revision id.
*
* @return \Drupal\node\NodeInterface|null
* A fully-populated node entity, or NULL if the node is not found.
*/
function node_revision_load($vid = NULL) {
return entity_revision_load('node', $vid);
Dries Buytaert
committed
/**
* Deletes a node revision.
Dries Buytaert
committed
*
* @param $revision_id
* The revision ID to delete.
* TRUE if the revision deletion was successful; otherwise, FALSE.
Dries Buytaert
committed
*/
function node_revision_delete($revision_id) {
Angie Byron
committed
entity_revision_delete('node', $revision_id);
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Checks whether the current page is the full page view of the passed-in node.
Dries Buytaert
committed
*
* @param \Drupal\node\NodeInterface $node
* A node entity.
*
* @return
* The ID of the node if this is a full page view, otherwise FALSE.
Dries Buytaert
committed
*/
function node_is_page(NodeInterface $node) {
$route_match = \Drupal::routeMatch();
Alex Pott
committed
if ($route_match->getRouteName() == 'entity.node.canonical') {
$page_node = $route_match->getParameter('node');
catch
committed
}
Alex Pott
committed
return (!empty($page_node) ? $page_node->id() == $node->id() : FALSE);
Dries Buytaert
committed
}
/**
* Implements hook_preprocess_HOOK() for HTML document templates.
*/
function node_preprocess_html(&$variables) {
// If on an individual node page, add the node type to body classes.
if (($node = \Drupal::routeMatch()->getParameter('node')) && $node instanceof NodeInterface) {
$variables['attributes']['class'][] = drupal_html_class('node--type-' . $node->getType());
}
}
Jennifer Hodgdon
committed
/**
Angie Byron
committed
* Implements hook_preprocess_HOOK() for block templates.
*/
function node_preprocess_block(&$variables) {
Alex Pott
committed
if ($variables['configuration']['provider'] == 'node') {
switch ($variables['elements']['#plugin_id']) {
Dries Buytaert
committed
case 'node_syndicate_block':
Dries Buytaert
committed
$variables['attributes']['role'] = 'complementary';
break;
}
}
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
function node_theme_suggestions_node(array $variables) {
$suggestions = array();
$node = $variables['elements']['#node'];
$sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
$suggestions[] = 'node__' . $sanitized_view_mode;
$suggestions[] = 'node__' . $node->bundle();
$suggestions[] = 'node__' . $node->bundle() . '__' . $sanitized_view_mode;
$suggestions[] = 'node__' . $node->id();
$suggestions[] = 'node__' . $node->id() . '__' . $sanitized_view_mode;
return $suggestions;
}
Dries Buytaert
committed
/**
Alex Pott
committed
* Prepares variables for node templates.
Dries Buytaert
committed
*
Alex Pott
committed
* Default template: node.html.twig.
Dries Buytaert
committed
*
Alex Pott
committed
* Most themes utilize their own copy of node.html.twig. The default is located
* inside "/core/modules/node/templates/node.html.twig". Look in there for the full
* list of variables.
*
* @param array $variables
Jennifer Hodgdon
committed
* An associative array containing:
* - elements: An array of elements to display in view mode.
* - node: The node object.
* - view_mode: View mode; e.g., 'full', 'teaser'...
Dries Buytaert
committed
*/
function template_preprocess_node(&$variables) {
$variables['view_mode'] = $variables['elements']['#view_mode'];
// Provide a distinct $teaser boolean.
$variables['teaser'] = $variables['view_mode'] == 'teaser';
Dries Buytaert
committed
$variables['node'] = $variables['elements']['#node'];
/** @var \Drupal\node\NodeInterface $node */
Dries Buytaert
committed
$node = $variables['node'];
Alex Pott
committed
$variables['date'] = format_date($node->getCreatedTime());
catch
committed
$username = array(
'#theme' => 'username',
'#account' => $node->getOwner(),
Alex Pott
committed
'#link_options' => array('attributes' => array('rel' => 'author')),
catch
committed
);
$variables['author_name'] = drupal_render($username);
Dries Buytaert
committed
$variables['url'] = $node->url('canonical', array(
'language' => $node->language(),
));
$variables['label'] = $variables['elements']['title'];
unset($variables['elements']['title']);
Angie Byron
committed
// The 'page' variable is set to TRUE in two occasions:
// - The view mode is 'full' and we are on the 'node.view' route.
// - The node is in preview and view mode is either 'full' or 'default'.
$variables['page'] = ($variables['view_mode'] == 'full' && (node_is_page($node)) || (isset($node->in_preview) && in_array($node->preview_view_mode, array('full', 'default'))));
Angie Byron
committed
// Helpful $content variable for templates.
Angie Byron
committed
$variables += array('content' => array());
Angie Byron
committed
foreach (Element::children($variables['elements']) as $key) {
Angie Byron
committed
$variables['content'][$key] = $variables['elements'][$key];
}
Dries Buytaert
committed
// Display post information only on certain node types.
// Avoid loading the entire node type config entity here that may not exist.
$node_type_config = \Drupal::config('node.type.' . $node->bundle());
// Used by RDF to add attributes around the author and date submitted.
$variables['author_attributes'] = new Attribute();
// Display submitted by default.
$variables['display_submitted'] = $node_type_config->isNew() || $node_type_config->get('settings.node.submitted');
if ($variables['display_submitted']) {
if (theme_get_setting('features.node_user_picture')) {
// To change user picture settings (e.g. image style), edit the 'compact'
Alex Pott
committed
// view mode on the User entity. Note that the 'compact' view mode might
// not be configured, so remember to always check the theme setting first.
$variables['author_picture'] = user_view($node->getOwner(), 'compact');
}
Dries Buytaert
committed
}
Angie Byron
committed
catch
committed
// Add article ARIA role.
Dries Buytaert
committed
$variables['attributes']['role'] = 'article';
catch
committed
Angie Byron
committed
// Gather node classes.
Dries Buytaert
committed
$variables['attributes']['class'][] = 'node';
$variables['attributes']['class'][] = drupal_html_class('node--type-' . $node->bundle());
Alex Pott
committed
if ($node->isPromoted()) {
$variables['attributes']['class'][] = 'node--promoted';
Angie Byron
committed
}
Alex Pott
committed
if ($node->isSticky()) {
$variables['attributes']['class'][] = 'node--sticky';
Angie Byron
committed
}
Alex Pott
committed
if (!$node->isPublished()) {
$variables['attributes']['class'][] = 'node--unpublished';
Angie Byron
committed
}
Jennifer Hodgdon
committed
if ($variables['view_mode']) {
$variables['attributes']['class'][] = drupal_html_class('node--view-mode-' . $variables['view_mode']);
Angie Byron
committed
}
Angie Byron
committed
if (isset($node->preview)) {
$variables['attributes']['class'][] = 'node--preview';
Angie Byron
committed
}
Dries Buytaert
committed
}
Dries Buytaert
committed
* Implements hook_permission().
function node_permission() {
$perms = array(
'bypass node access' => array(
'title' => t('Bypass content access control'),
'description' => t('View, edit and delete all content regardless of permission restrictions.'),
'restrict access' => TRUE,
),
Angie Byron
committed
'administer content types' => array(
'title' => t('Administer content types'),
Alex Pott
committed
'description' => t('Promote, change ownership, edit revisions, and perform other tasks across all content types.'),
Dries Buytaert
committed
'restrict access' => TRUE,
Angie Byron
committed
),
'administer nodes' => array(
'title' => t('Administer content'),
Dries Buytaert
committed
'restrict access' => TRUE,
Angie Byron
committed
),
Dries Buytaert
committed
'access content overview' => array(
Alex Pott
committed
'title' => t('Access the Content overview page'),
'description' => t('Get an overview of <a href="!url">all content</a>.', array('!url' => \Drupal::url('system.admin_content'))),
Dries Buytaert
committed
),
'access content' => array(
'title' => t('View published content'),
),
'view own unpublished content' => array(
'title' => t('View own unpublished content'),
Angie Byron
committed
),
'view all revisions' => array(
'title' => t('View all revisions'),
Angie Byron
committed
),
'revert all revisions' => array(
'title' => t('Revert all revisions'),
'description' => t('Role requires permission <em>view revisions</em> and <em>edit rights</em> for nodes in question, or <em>administer nodes</em>.'),
Angie Byron
committed
),
'delete all revisions' => array(
'title' => t('Delete all revisions'),
'description' => t('Role requires permission to <em>view revisions</em> and <em>delete rights</em> for nodes in question, or <em>administer nodes</em>.'),
Angie Byron
committed
),
);
Neil Drumm
committed
Alex Pott
committed
// Generate node permissions for all node types.
foreach (NodeType::loadMultiple() as $type) {
Dries Buytaert
committed
$perms += node_list_permissions($type);
Neil Drumm
committed
}
return $perms;
Dries Buytaert
committed
/**
Dries Buytaert
committed
* Implements hook_ranking().
Dries Buytaert
committed
*/
function node_ranking() {
// Create the ranking array and add the basic ranking options.
$ranking = array(
'relevance' => array(
'title' => t('Keyword relevance'),
// Average relevance values hover around 0.15
'score' => 'i.relevance',
),
'sticky' => array(
'title' => t('Content is sticky at top of lists'),
// The sticky flag is either 0 or 1, which is automatically normalized.
'score' => 'n.sticky',
),
'promote' => array(
'title' => t('Content is promoted to the front page'),
// The promote flag is either 0 or 1, which is automatically normalized.
'score' => 'n.promote',
),
);
// Add relevance based on creation or changed date.
if ($node_cron_last = \Drupal::state()->get('node.cron_last')) {
Dries Buytaert
committed
$ranking['recent'] = array(
'title' => t('Recently posted'),
// Exponential decay with half-life of 6 months, starting at last indexed node
Dries Buytaert
committed
'score' => 'POW(2.0, (GREATEST(n.created, n.changed) - :node_cron_last) * 6.43e-8)',
'arguments' => array(':node_cron_last' => $node_cron_last),
Dries Buytaert
committed
);
}
return $ranking;
}
Gerhard Killesreiter
committed
/**
Dries Buytaert
committed
* Implements hook_user_cancel().
Gerhard Killesreiter
committed
*/
function node_user_cancel($edit, $account, $method) {
Angie Byron
committed
switch ($method) {
case 'user_cancel_block_unpublish':
// Unpublish nodes (current revisions).
$nids = \Drupal::entityQuery('node')
Dries Buytaert
committed
->condition('uid', $account->id())
->execute();
module_load_include('inc', 'node', 'node.admin');
node_mass_update($nids, array('status' => 0), NULL, TRUE);
Angie Byron
committed
break;
case 'user_cancel_reassign':
// Anonymize all of the nodes for this old account.
Angie Byron
committed
module_load_include('inc', 'node', 'node.admin');
$vids = \Drupal::entityManager()->getStorage('node')->userRevisionIds($account);
node_mass_update($vids, array(
'uid' => 0,
'revision_uid' => 0,
), NULL, TRUE, TRUE);
Angie Byron
committed
break;
Dries Buytaert
committed
}
}
Angie Byron
committed
Dries Buytaert
committed
/**
* Implements hook_ENTITY_TYPE_predelete() for user entities.
Dries Buytaert
committed
*/
catch
committed
function node_user_predelete($account) {
Dries Buytaert
committed
// Delete nodes (current revisions).
// @todo Introduce node_mass_delete() or make node_mass_update() more flexible.
$nids = \Drupal::entityQuery('node')
Dries Buytaert
committed
->condition('uid', $account->id())
->execute();
entity_delete_multiple('node', $nids);
Dries Buytaert
committed
// Delete old revisions.
$storage_controller = \Drupal::entityManager()->getStorage('node');
$revisions = $storage_controller->userRevisionIds($account);
Dries Buytaert
committed
foreach ($revisions as $revision) {
node_revision_delete($revision);
Angie Byron
committed
}
Gerhard Killesreiter
committed
}
Gábor Hojtsy
committed
/**
* Returns HTML for the content ranking part of the search settings admin page.
*
* @param $variables
* An associative array containing:
* - form: A render element representing the form.
Gábor Hojtsy
committed
*
* @see node_search_admin()
Gábor Hojtsy
committed
* @ingroup themeable
*/
Dries Buytaert
committed
function theme_node_search_admin($variables) {
$form = $variables['form'];
Dries Buytaert
committed
$output = drupal_render($form['info']);
Angie Byron
committed
$header = array(t('Factor'), t('Influence'));
Angie Byron
committed
foreach (Element::children($form['factors']) as $key) {
$row = array();
$row[] = $form['factors'][$key]['#title'];
Dries Buytaert
committed
$form['factors'][$key]['#title_display'] = 'invisible';
Dries Buytaert
committed
$row[] = drupal_render($form['factors'][$key]);
$rows[] = $row;
}
catch
committed
$table = array(
Angie Byron
committed
'#type' => 'table',
catch
committed
'#header' => $header,
'#rows' => $rows,
);
$output .= drupal_render($table);
$output .= drupal_render_children($form);
return $output;
}
* Title callback: Displays the node's title.
*
* @param \Drupal\node\NodeInterface $node
* The node entity.
* @return
* An unsanitized string that is the title of the node.
*
function node_page_title(NodeInterface $node) {
Angie Byron
committed
return $node->label();
}
/**
* Finds the last time a node was changed.
*
* @param $nid
* The ID of a node.
* @param string $langcode
* (optional) The language the node has been last modified in. Defaults to the
* node language.
*
* @return string
* A unix timestamp indicating the last time the node was changed.
* @todo Remove once https://drupal.org/node/2002180 is resolved. It's only used
* for validation, which will be done by EntityChangedConstraintValidator.
Dries Buytaert
committed
*/
function node_last_changed($nid, $langcode = NULL) {
$changed = \Drupal::entityManager()->getStorage('node')->loadUnchanged($nid)->getChangedTime();
return $changed ? $changed : FALSE;
Dries Buytaert
committed
}
Angie Byron
committed
/**
* Finds the most recently changed nodes that are available to the current user.
Angie Byron
committed
*
* @param $number
* (optional) The maximum number of nodes to find. Defaults to 10.
*
* @return
Jennifer Hodgdon
committed
* An array of node entities or an empty array if there are no recent nodes
* visible to the current user.
Angie Byron
committed
*/
function node_get_recent($number = 10) {
$account = \Drupal::currentUser();
$query = \Drupal::entityQuery('node');
Angie Byron
committed
if (!$account->hasPermission('bypass node access')) {
Angie Byron
committed
// If the user is able to view their own unpublished nodes, allow them
// to see these in addition to published nodes. Check that they actually
// have some unpublished nodes to view before adding the condition.
$access_query = \Drupal::entityQuery('node')
->condition('uid', $account->id())
->condition('status', NODE_NOT_PUBLISHED);
if ($account->hasPermission('view own unpublished content') && ($own_unpublished = $access_query->execute())) {
$query->orConditionGroup()
->condition('status', NODE_PUBLISHED)
->condition('nid', $own_unpublished, 'IN');
Angie Byron
committed
}
else {
// If not, restrict the query to published nodes.
$query->condition('status', NODE_PUBLISHED);
Angie Byron
committed
}
}
Angie Byron
committed
$nids = $query
->sort('changed', 'DESC')
Angie Byron
committed
->range(0, $number)
->addTag('node_access')
->execute();
Angie Byron
committed
$nodes = node_load_multiple($nids);
return $nodes ? $nodes : array();
}
* Page callback: Generates and prints an RSS feed.
*
Angie Byron
committed
* Generates an RSS feed from an array of node IDs, and prints it with an HTTP
* header, with Content Type set to RSS/XML.
*
* @param $nids
* (optional) An array of node IDs (nid). Defaults to FALSE so empty feeds can
* be generated with passing an empty array, if no items are to be added
Gábor Hojtsy
committed
* to the feed.
* @param $channel
* (optional) An associative array containing 'title', 'link', 'description',
* and other keys, to be parsed by format_rss_channel() and
* format_xml_elements(). A list of channel elements can be found at the
* @link http://cyber.law.harvard.edu/rss/rss.html RSS 2.0 Specification. @endlink
* The link should be an absolute URL.
Angie Byron
committed
* @todo Convert taxonomy_term_feed() to a view, so this method is not needed
* anymore.
*
* @return Symfony\Component\HttpFoundation\Response
* A response object.
*
Gábor Hojtsy
committed
function node_feed($nids = FALSE, $channel = array()) {
global $base_url;
$language_content = \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);
$rss_config = \Drupal::config('system.rss');
Gábor Hojtsy
committed
if ($nids === FALSE) {
$nids = \Drupal::entityQuery('node')
->condition('status', 1)
->condition('promote', 1)
->sort('created', 'DESC')
Dries Buytaert
committed
->range(0, $rss_config->get('items.limit'))
Dries Buytaert
committed
->addTag('node_access')
->execute();
$view_mode = $rss_config->get('items.view_mode');
$namespaces = array('xmlns:dc' => 'http://purl.org/dc/elements/1.1/');
// Load all nodes to be rendered.
/** @var \Drupal\node\NodeInterface[] $nodes */
$nodes = node_load_multiple($nids);
Dries Buytaert
committed
foreach ($nodes as $node) {
$item_text = '';
Alex Pott
committed
$node->link = url('node/' . $node->id(), array('absolute' => TRUE));
Dries Buytaert
committed
$node->rss_namespaces = array();
$node->rss_elements = array(
Alex Pott
committed
array('key' => 'pubDate', 'value' => gmdate('r', $node->getCreatedTime())),
array('key' => 'dc:creator', 'value' => $node->getOwner()->label()),
Alex Pott
committed
array('key' => 'guid', 'value' => $node->id() . ' at ' . $base_url, 'attributes' => array('isPermaLink' => 'false'))
Dries Buytaert
committed
);
Dries Buytaert
committed
// The node gets built and modules add to or modify $node->rss_elements
// and $node->rss_namespaces.
Dries Buytaert
committed
$build = node_view($node, 'rss');
Dries Buytaert
committed
unset($build['#theme']);
Steven Wittens
committed
Dries Buytaert
committed
if (!empty($node->rss_namespaces)) {
$namespaces = array_merge($namespaces, $node->rss_namespaces);
}
if ($view_mode != 'title') {
Dries Buytaert
committed
// We render node contents and force links to be last.
Dries Buytaert
committed
$build['links']['#weight'] = 1000;
$item_text .= drupal_render($build);
Dries Buytaert
committed
}
Angie Byron
committed
$items .= format_rss_item($node->label(), $node->link, $item_text, $node->rss_elements);
'title' => \Drupal::config('system.site')->get('name'),