Getting Taxonomy Terms for a Node ID in Drupal 8 - drupal

I'm trying to add a preprocess hook to add classes based on taxonomy name to the body css of my drupal installation. I've managed to get all the information about the node based on doing some searching around and trial and error, but I'd like to take it to the next step and get all the taxonomy terms based on the particular node id.
My current preprocess code is follows:
function custom_preprocess_html(&$variables) {
// Add the node ID and node type to the body class
$body_classes = [];
$nodeFields =\Drupal::service('current_route_match')->getParameter('node')->toArray();
if (is_array($nodeFields) && count($nodeFields) > 0) {
if (isset($nodeFields['nid'])) {
$body_classes[] = 'node-' . $nodeFields['nid'][0]['value'];
}
if (isset($nodeFields['type'])) {
$body_classes[] = $nodeFields['type'][0]['target_id'];
}
}
$variables['attributes']['class'] = $body_classes;
}
It works fine and pulls down the information regarding the node. Based on the answer here it seems like all I should have to do is add the following line to get the taxonomy terms: $taxonomyTerms = $nodefields->get('field_yourfield')->referencedEntities(); but when I do so Drupal throws an error. I'll freely admit I'm new to Drupal 8, so any suggestions about where I'm going wrong (is field_yourfield not something that exists, maybe?) would be greatly appreciated.

If you are trying to get the referenced term names and add them as body classes, your approach seems a little bit off.
This is what I use:
function CUSTOM_preprocess_html(&$variables) {
// Entity reference field name.
$field_name = 'field_tags';
// Get the node object from the visited page.
// If the page is not a node detail page, it'll return NULL.
$node = \Drupal::request()->attributes->get('node');
// Let's make sure the node has the field.
if ($node && $node->hasField($field_name)) {
$referenced_entities = $node->get($field_name)->referencedEntities();
foreach ($referenced_entities as $term) {
$variables['attributes']['class'][] = \Drupal\Component\Utility\Html::cleanCssIdentifier($term->getName());
}
}
}

Related

How to enable/disable revision in drupal 7

What I am trying to do is to enable/disable revision according to the selected taxonomy term in the content type that I have created i.e. when a user add the content the user can select the taxonomy term field(may be a select field) according to the selected option I want to enable/disable the revision. How can I do this?
Turn off the create new revision setting for the content type.
Then in hook_form_alter add a new submission handler before the main one:
function YOUR_MODULE_form_alter(&$form, &$form_state, $form_id) {
//drupal_set_message("Form ID is : " . $form_id);
switch($form_id) {
case 'CONTENT_TYPE_node_form':
//dpm($form);
$form['actions']['submit']['#submit'][] = 'revision_control_node_form_submit';
$form['actions']['submit']['#submit'] = array_reverse($form['actions']['submit']['#submit']); // reverse array to put our submit handler first
break;
}
}
Then in the new submit handler check if the taxonomy term has the correct value to save a new revision. I've not tried this next bit but according to this page putting
$node->revision = 1;
before node save will create a new revision.
node_save is called in node_form_submit and the node object is built in node_form_submit_build_node.
Looking at the other attributes like vid that belong to $form_state I would say an good educated guess would be to put $form_state->revision = 1; and see if that comes out as a property of the node after node_form_submit_build_node.
So you final new submit handler will look something like:
function revision_control_node_form_submit($form, &$form_state) {
if($form_state['values']['your_taxonomy_field'] == 'your_value') {
$form_state->revision = 1;
}
}
Now I've not actually tried any of this but even if it doesn't work I'm sure you will be on the right track... Good luck!

Modifying a field collection programmatically missing hostEntity fields

I am trying to modify a field collection in a node that already exists so I can change an image on the first element in an array of 3. The problem is, the hostEntity info is not set when I do a entity_load or entity_load_single so when I do a:
$field_collection_item->save(true); // with or without the true
// OR
$fc_wrapper->save(true); // with or without the true
I get the following error:
Exception: Unable to save a field collection item without a valid reference to a host entity. in FieldCollectionItemEntity->save()
When i print_r the field collection entity the hostEntity:protected fields are indeed empty. My field collection is setup as follows:
field_home_experts
Expert Image <--- Want to change this data only and keep the rest below
field_expert_image
Image
Expert Name
field_expert_name
Text
Expert Title
field_expert_title
Text
Here is the code I am trying to use to modify the existing nodes field collection:
$node = getNode(1352); // Get the node I want to modify
// There can be up to 3 experts, and I want to modify the image of the first expert
$updateItem = $node->field_home_experts[LANGUAGE_NONE][0];
if ($updateItem) { // Updating
// Grab the field collection that currently exists in the 0 spot
$fc_item = reset(entity_load('field_collection_item', array($updateItem)));
// Wrap the field collection entity in the field API wrapper
$fc_wrapper = entity_metadata_wrapper('field_collection_item', $fc_item);
// Set the new image in place of the current
$fc_wrapper->field_expert_image->set((array)file_load(4316));
// Save the field collection
$fc_wrapper->save(true);
// Save the node with the new field collection (not sure this is needed)
node_save($node);
}
Any help would be greatly appreciated, I am still quite new to Drupal as a whole (end-user or developer)
Alright so I think I have figured this out, I wrote up a function that will set a field collection values:
// $node: (obj) node object returned from node_load()
// $collection: (string) can be found in drupal admin interface:
// structure > field collections > field name
// $fields: (array) see usage below
// $index: (int) the index to the element you wish to edit
function updateFieldCollection($node, $collection, $fields = Array(), $index = 0) {
if ($node && $collection && !empty($fields)) {
// Get the field collection ID
$eid = $node->{$collection}[LANGUAGE_NONE][$index]['value'];
// Load the field collection with the ID from above
$entity = entity_load_single('field_collection_item', array($eid));
// Wrap the loaded field collection which makes setting/getting much easier
$node_wrapper = entity_metadata_wrapper('field_collection_item', $entity);
// Loop through our fields and set the values
foreach ($fields as $field => $data) {
$node_wrapper->{$field}->set($data);
}
// Once we have added all the values we wish to change then we need to
// save. This will modify the node and does not require node_save() so
// at this point be sure it is all correct as this will save directly
// to a published node
$node_wrapper->save(true);
}
}
USAGE:
// id of the node you wish to modify
$node = node_load(123);
// Call our function with the node to modify, the field collection machine name
// and an array setup as collection_field_name => value_you_want_to_set
// collection_field_name can be found in the admin interface:
// structure > field collections > manage fields
updateFieldCollection(
$node,
'field_home_experts',
array (
'field_expert_image' => (array)file_load(582), // Loads up an existing image
'field_expert_name' => 'Some Guy',
'field_expert_title' => 'Some Title',
)
);
Hope this helps someone else as I spent a whole day trying to get this to work (hopefully I won't be a noob forever in Drupal7). There may be an issue getting formatted text to set() properly but I am not sure what that is at this time, so just keep that in mind (if you have a field that has a format of filtered_html for example, not sure that will set correctly without doing something else).
Good luck!
Jake
I was still getting the error, mentioned in the question, after using the above function.
This is what worked for me:
function updateFieldCollection($node, $collection, $fields = Array(), $index = 0) {
$eid = $node->{$collection}[LANGUAGE_NONE][$index]['value'];
$fc_item = entity_load('field_collection_item', array($eid));
foreach ($fields as $field => $data) {
$fc_item[$eid]->{$field}[LANGUAGE_NONE][0]['value'] = $data;
}
$fc_item[$eid]->save(TRUE);
}
I hope this helps someone as it took me quite some time to get this working.

How to use nodeapi in drupal?

guys i have this node type -> movie. this movie has casts in it. so now i was instructed to display the number of cast in a movie. how do i achieve this by using nodeapi? please someone guide mo through this. im very new to drupal coding here. here's what ive made so far:
function count_cast_nodeapi(&$node, $op) {
switch ($op) {
case 'update index':
if ($node->type == 'movie') {
$text = '';
$q = db_query('SELECT count(field_movie_cast_nid) FROM content_field_movie_cast ' .
'WHERE nid = %d', $node->nid);
if ($r = db_fetch_object($q)) {
$text = $r->count;
}
drupal_set_message($text);
}
}
}
but i have no idea where to put this code. where to save it. do i make a module of this? and is this code even correct?
also i have only copied this code. so i dont know what that 'update index' means. and who or what function will set that parameter $op
I can suggest you follow solution:
Create new integer CCK field for content type "movie" which will store the number of casts. Name it movie_cast_number.
This field will be updating in hook_nodeapi (similar to your example). For that you need to create custom module "count_cast". Place it to sites/all/modules directory.
In hook_nodeapi need to use $op "insert" and "update". $op generating by module node and means which operation is performed with node. Insert means new node has been created and update - existing node has been updated.
If you need custom output for this content type then you need to create node-movie.tpl.php in your theme directory.
Code which update the number of casts can looks follow way:
function count_cast_nodeapi(&$node, $op) {
switch ($op) {
case 'update':
case 'insert':
if ($node->type == 'movie') {
$result = db_result(db_query('
SELECT count(field_movie_cast_nid) cnt
FROM {content_field_movie_cast}
WHERE nid = %d
', $node->nid));
$node->field_movie_cast_number[0]['value'] = $result->cnt;
}
}
}

Drupal: automatically add new nodes to a nodequeue

Can I somehow automatically add a node to a specific nodequeue when it is created ?
(I'm using nodequeue module: drupal.org/project/nodequeue)
thanks
I needed this feature for a drupal 7 site and took the custom module solution. Let's say the setup is one nodequeue, and every 'project' nodes should be automatically added and removed to the queue. Create an empty nodequeue_auto_add directory in sites/all/modules/. This contains these two files
nodequeue_auto_add.info
name = Nodequeue auto add/remove
description = Automatically adds and remove nodes when they are created and deleted.
core = 7.x
version = 7.x-dev
package = Nodequeue
dependencies[] = nodequeue
nodequeue_auto_add.module
<?php
/**
* Implements hook_node_insert().
*/
function nodequeue_auto_add_node_insert($node) {
$nid = $node->nid;
$type = $node->type;
// only process project node
if ($type != 'project') {
return FALSE;
}
// I've only one nodequeue where a specific node type should always be
// added so this is taken from the mysql nodequeue_queue table
$queue_id = 1;
// subqueue id, exists even if we created a really basic nodequeue (from nodequeue_subqueue table)
$sqid = 1;
$queue = nodequeue_load($queue_id);
$subqueue = nodequeue_load_subqueue($sqid);
if (function_exists('views_invalidate_cache')) {
views_invalidate_cache();
}
nodequeue_subqueue_add($queue, $subqueue, $nid);
}
/**
* Implements hook_node_delete().
*/
function nodequeue_auto_add_node_delete($node) {
$nid = $node->nid;
$type = $node->type;
// only process project node
if ($type != 'project') {
return FALSE;
}
if (function_exists('views_invalidate_cache')) {
views_invalidate_cache();
}
// I've only one nodequeue where a specific node type should always be
// added so this is taken from the mysql nodequeue_queue table
$queue_id = 1;
// subqueue id, exists even if we created a really basic nodequeue (from nodequeue_subqueue table)
$sqid = 1;
nodequeue_subqueue_remove_node($sqid, $nid);
}
There is an action "Add to Nodequeue" in Rules. I've solved by creating a new rule.
There's a simple module made just for this purpose, for both Drupal 6 and Drupal 7:
http://drupal.org/project/auto_nodequeue
I'm using drupal 5 which doesn't have rules. This is how I accomplished it, I'm not using any subqueues:
if($op == 'insert'){
if($node->type == 'node_type'){
$queue = nodequeue_load(4);
$subqueue = nodequeue_load_subqueue(4);
nodequeue_subqueue_add($queue, $subqueue, $node->nid);
}
}
You cannot set it up within the admin interface, but you can do it in a custom module using hook_nodeapi op insert.
There is a module for that. Check it out and see if it helps. https://www.drupal.org/project/auto_nodequeue/project/auto_nodequeue
While this module does not exactly meet the OP "auto add" request it does allow you to configure the content type so that you can add it directly to the queue: https://www.drupal.org/sandbox/rlhawk/1444496 It is a sandbox but very stable and I use it all the time and love it.

Loading the previous revision of a node

When you get a node, how do you load the previous version (revision)?
I know how loading a revision but not how getting the previous revision number ($node->vid is the current revision).
thanks
Supposing that you have a node object $node, you can use the following code to get the previous revision.
$previous_vid = db_result(
db_query('SELECT MAX(vid) AS vid FROM {node_revisions} WHERE vid < %d AND nid = %d', $node->vid, $node->nid)
);
Once you have the previous revision, you can load the new node object with node_load(array('nid' => $node-nid, 'vid' => $previous_vid)).
The code should check if db_result() returns FALSE, in the case there isn't a previous revision.
To note that the field vid is global for each node; it doesn't contain the same value for different nodes.
Thanks all.
I found also an other solution:
$revisions = node_revision_list($node);
next($revisions);
if ($preview_key = key($revisions)) {
$preview_revision = $revisions[$preview_key];
$old_node = node_load($node->nid, $preview_revision->vid);
}
But if you have a lot of revision you get a big array.
If I understand what you're trying to do; you want to get the preview of the node after someone submits changes?
The preview button has its own submit handler, node_form_build_preview(). There, it creates a new node object using the data in $form_state and runs node_preview(), which returns the markup for the preview.
If you want to capture that preview when the user clicks the preview button, you'll need to use hook_form_alter to add another submit handler to the preview button:
$['form']['buttons']['preview']['#submit'][] = 'mymodule_custom_preview';
where mymodule_custom_preview is the name of your custom submit function. Take a look at node_form_build_preview() for guidance, but your submit function is going to look something like this:
function mymodule_custom_preview($form, &$form_state) {
$node = node_form_submit_build_node($form, $form_state);
$preview = node_preview($node);
}
Also take a look at node_form(), which gives you an idea of how the node form is structured. When you're all done, you're going to have code in your module that looks something like this:
function mymodule_form_alter(&$form, $form_state, $form_id) {
if (strstr($form_id, '_node_form') !== FALSE) {
$['form']['buttons']['preview']['#submit'][] = 'mymodule_custom_preview';
}
}
function mymodule_custom_preview($form, &$form_state) {
$node = node_form_submit_build_node($form, $form_state);
$preview = node_preview($node);
// Do what you will with $preview.
}

Resources