Drupal 7 - Insert taxonomy into node object - drupal

I have a script which successfully creates new nodes. But I'm having trouble setting the taxonomy before saving.
I believe in Drupal 6 I would use this method.
$cat1_tid = taxonomy_get_term_by_name($data[$i]['cat1']);
$cat2_tid = taxonomy_get_term_by_name($data[$i]['cat2']);
$cat3_tid = taxonomy_get_term_by_name($data[$i]['cat3']);
$node->taxonomy = array($cat1_tid, $cat2_tid, $cat3_tid);
I think in Drupal 7 I would do this (my field name is Catalog)
$node->taxonomy_catalog['und'][0] = array($term1Obj, $term2Obj);
taxonomy_get_term_by_name doesn't seem to return the correct object to insert into the node object.
If anyone can shed some light, appreciated.
Thanks
EDIT
Solution:
// Taxonomy
$categories = array($data[$i]['cat1'], $data[$i]['cat2'], $data[$i]['cat3']);
foreach ($categories as $key => $category) {
if ($term = taxonomy_get_term_by_name($category)) {
$terms_array = array_keys($term);
$node->taxonomy_catalog[LANGUAGE_NONE][$key]['tid'] = $terms_array['0'];
}
}

Below is some quick-and-dirty code I used recently to import "command" nodes into a site. Mid-way down, the foreach loop takes care of creating and assigning terms, as needed.
$command = new stdClass;
$command->language = LANGUAGE_NONE;
$command->uid = 1;
$command->type = 'drubnub';
$command->title = $line['0'];
$command->body[LANGUAGE_NONE]['0']['value'] = $line['1'];
$command->url[LANGUAGE_NONE]['0']['value'] = trim($line['2']);
$command->uses[LANGUAGE_NONE]['0']['value'] = $line['3'];
$tags = explode(',', $line['4']);
foreach ($tags as $key => $tag) {
if ($term = taxonomy_get_term_by_name($tag)) {
$terms_array = array_keys($term);
$command->field_tags[LANGUAGE_NONE][$key]['tid'] = $terms_array['0'];
} else {
$term = new STDClass();
$term->name = $tag;
$term->vid = 1;
if (!empty($term->name)) {
$test = taxonomy_term_save($term);
$term = taxonomy_get_term_by_name($tag);
foreach($term as $term_id){
$command->product_tags[LANGUAGE_NONE][$key]['tid'] = $term_id->tid;
}
$command->field_tags[LANGUAGE_NONE][$key]['tid'] = $tid;
}
}
}
node_save($command);

Here you are, this code successfully add a new term to the node before the node is created.
$my_term_name = 'micky';
$term_array = taxonomy_get_term_by_name($my_term_name);
if($term_array == array()){
//empty term ..
$term->name = $my_term_name;
$term->vid = 1;
taxonomy_term_save($term);
$term_array = taxonomy_get_term_by_name($my_term_name);
}
//get the first index of the array .
foreach ($term_array as $tid => $term_object)break;
$node->field_tag['und'][$tid] = (array)$term_object;

Perhaps my experience is unique, but I found that using
$term = taxonomy_get_term_by_name($tag)
$tid = $term->tid;
caused an error.
I found that after $term is saved, there is no need to fetch the newly created term.
The $term object is updated to include the new tid.

Any answer that use LANGUAGE_NONE or 'und' to alter a field is not the proper way of doing it as it assumes that the drupal site is one language. The proper way to edit a field is to use entity_metadata_wrapper.
$node_wrapper = entity_metadata_wrapper('node', $node);
// If you have Entity API [entity] module installed you can simply.
$node_wrapper = $node->wrapper();
// It is good practice to check the terms in the field before adding
// a new one to make sure that the term is not already set.
$term_ids_current = $node_wrapper->taxonomy_catalog->raw();
if (!in_array($term_new_id, $term_ids_current)) {
$node_wrapper->taxonomy_catalog[] = $term_new_id;
}
// To add multiple terms iterate an array or terms ids.
$term_ids_current = $node_wrapper->taxonomy_catalog->raw();
$tern_new_ids = array(1, 2, 3);
foreach ($term_new_ids as $term_new_id) {
if (!in_array($term_new_id, $term_ids_current)) {
$node_wrapper->taxonomy_catalog[] = $term_new_id;
}
}
// To remove a term.
$term_ids_current = $node_wrapper->taxonomy_catalog->raw();
$delta = array_search($term_remove_id, $term_ids_current);
if (is_int($delta)) {
$node_wrapper->taxonomy_catalog->offsetUnset($delta);
}
// To replace all terms.
$term_new_ids = array(1, 2, 3);
$node_wrapper->taxonomy_catalog->set($term_new_ids);
// To get all the fully loaded terms in a field.
$terms = $node_wrapper->taxonomy_catalog->value();
// At the end make sure to save it.
$node_wrapper->save();

Related

Cron Job In Custom Plugin Not Working In Wordpress

I have added this cronjob in my WordPress custom plugin but when I run the function manually it is working but through cronjob, it is not working. Here is my code! All the plugin files are loaded correctly not showing any error.
Can anybody help me to sort this out! I have tried a lot but still, it is not working.
<?php
if (!wp_next_scheduled('generateusedcarsfeed'))
{
wp_schedule_event(time() , '5mins', 'generateusedcarsfeed');
}
add_action('generateusedcarsfeed', 'generate_used_car_feed');
if (!wp_next_scheduled('generateusedcarsfeed'))
{
wp_schedule_event(time() , '5mins', 'generateusedcarsfeed');
}
add_action('generateusedcarsfeed', 'generate_used_car_feed');
// Getting all used cars with all data
function generate_used_car_feed(){
try{
// for opening the csv file
$file = fopen('all-cars-feed.csv', 'r');
fwrite($file, '');
$loop = new WP_Query($args);
chmod('all-cars-feed.csv', 0777);
// for creating array from csv file
$file="all-cars-feed.csv";
$csv= file_get_contents($file);
$array = array_map("str_getcsv", explode("\n", $csv));
$json_csv_arr = json_encode($array);
$my_array_csv = json_decode($json_csv_arr, true);
// for getting used car list from databse, only take publish used car
global $wpdb;
$query = "SELECT wp_postmeta.post_id, wp_postmeta.meta_value FROM wp_postmeta
INNER JOIN wp_posts ON wp_posts.id = wp_postmeta.post_id WHERE meta_key = 'car_registration_number'
AND post_status = 'publish'";
$result = $wpdb->get_results($query);
$json_reg_num = json_encode($result);
$my_array = json_decode($json_reg_num, true);
print_r($my_array);
foreach ($my_array as $value) {
$car_reg_array = $value['meta_value'];
$Post_id= $value['post_id'];
$isTrue=true;
$ch = fopen("all-cars-feed.csv", "r");
while($row = fgetcsv($ch)) {
if (in_array($car_reg_array, $row)) {
echo 'found</hr>';
$isTrue=false;
}
}
if($isTrue)
{
$wpdb->query(
'UPDATE '.$wpdb->prefix.'posts SET post_status = "trash"
WHERE ID = "'.$Post_id.'"');
}
}
//fclose($file);
}
catch(\Exception $e)
{
$txt = 'Message: ' . $e->getMessage();
$myfile = fopen("newfile.txt", "w") or die("Unable to open file!");
fwrite($fileLoger, $txt);
fclose($fileLoger);
}
}
I wonder if this 5mins interval really exists in your setup. Try adding this code to make sure this actually exists (if it does already, it won't break stuff):
function add_custom_cron_schedules($schedules){
if (!isset($schedules["5mins"])) {
$schedules["5min"] = array(
'interval' => 5*60,
'display' => __('Every 5 minutes'));
}
return $schedules;
}
add_filter('cron_schedules','add_custom_cron_schedules');
If you want to retrieve currently available schedules, you can also use wp_get_schedules() and check out if a certain key (like '5mins') exists.

Query Builder "OR" in dynamic query

I would like to build a query with clause "OR" and the query receive an array parameter and doesn't know how elements it contains.
The query has to return a list of contents that have the category "1" or "2"(if $categ array contain [1,2]) etc.
Category is a foreign key in the content entity.
My repository:
public function getContentOfSomeCategories($categs)
{
$query = $this->createQueryBuilder('c');
$conditions = [];
foreach($categs as $value){
$conditions[] = 'c.contentCategory = '.$value;
}
$orX = $query->expr()->orX();
foreach ($conditions as $condition) {
$orX->add($condition);
}
$query->add('where', $orX);
I obtain the error message "Too many parameters: the query defines 1 parameters and you bound 2".
From PHP 5.6 onward, you can probably use PHP splat ... to expand an array to arguments.
$query = $this->createQueryBuilder('c');
$expr = $query->expr();
$conditions = [];
$valueNo = 0;
foreach ($categs as $value) {
$conditions[] = $expr->eq('c.contentCategory', 'value'.$valueNo);
$query->setParameter('value'.$valueNo, $value);
$valueNo++;
}
$query->andWhere($expr->orX(...$conditions));
Disclaimer: I've not tested this.
See: https://www.php.net/manual/en/functions.arguments.php
You can also use ... when calling functions to unpack an array or Traversable variable or literal into the argument list:
Edit:
If your query is simple, you could just use orWhere instead.
$query = $this->createQueryBuilder('c');
$expr = $query->expr();
$valueNo = 0;
foreach ($categs as $value) {
$query->orWhere($expr->eq('c.contentCategory', 'value'.$valueNo));
$query->setParameter('value'.$valueNo, $value);
$valueNo++;
}
Edit 2:
You might even want to just use an in clause instead.
$query->where($expr->in('c.contentCategory', ':values'));
$query->setParameter('values', $categs);`
You can achieve this quite easily, below utilises the query builder expression builder:
$queryBuilder = $this->createQueryBuilder('c');
$conditions = [];
$i = 0;
foreach ($categs as $value) {
$i++;
$conditions[] = $queryBuilder->expr()->eq('c.contentCategory', $i);
$queryBuilder->setParameter($i, $value);
}
$queryBuilder->andWhere(
$queryBuilder->expr()->orX()->addMultiple($conditions)
);
If you parameter applies to all then you can just add
$queryBuilder->setParameter();

Add class to drupal body

How can I add term id of all terms related to a node, to that node body class in drupal site?
For example, A node named stackoverflow is tagged with four terms
term1
term2
term3
term4
term5
I want to add these classed to node body class...
article-term-(term1tid)
article-term-(term2tid)
article-term-(term3tid)
article-term-(term4tid)
article-term-(term5tid)
These are pages I want to change their class names:
عکس نوزاد
عکس نوزاد
کاردستی
سوپ ساده
داستان برای کودک
کاردستی
leymannx code is really complete and fine.
But it does not contains all terms of a node.
I wrote this code and i wish it will be useful for you.
function YOURTHEME_preprocess_html(&$variables) {
if (arg(0) == 'node' && is_numeric(arg(1))) {
$node = node_load(arg(1));
$results = stackoverflow_taxonomy_node_get_terms($node);
if (is_array($results)) {
foreach ($results as $item) {
$variables['classes_array'][] = "article-term-" . $item->tid;
}
}
}
}
There is a function named ""stackoverflow_taxonomy_node_get_terms"" that returns all terms attached to a node.
function stackoverflow_taxonomy_node_get_terms($node, $key = 'tid'){
static $terms;
if (!isset($terms[$node->vid][$key])) {
$query = db_select('taxonomy_index', 'r');
$t_alias = $query->join('taxonomy_term_data', 't', 'r.tid = t.tid');
$v_alias = $query->join('taxonomy_vocabulary', 'v', 't.vid = v.vid');
$query->fields($t_alias);
$query->condition("r.nid", $node->nid);
$result = $query->execute();
$terms[$node->vid][$key] = array();
foreach ($result as $term) {
$terms[$node->vid][$key][$term->$key] = $term;
}
}
return $terms[$node->vid][$key];
}
i wish this code could be the best.
write all of this codes in template.php file in your theme.
if you want just some nodes have class name, add replace this part of code.
> if (arg(0) == 'node' && is_numeric(arg(1)) && ( arg(1)==X || arg(1)==Y
> ) ) {
As #P1ratRuleZZZ already pointed out template_preprocess_html (implemented from your sub-theme's template.php file) is the function to add body classes.
Thing is, that within this function, you need to load the actual node object first, then get the values of that term reference field, to finally add them as classes to the body tag.
Replace MYTHEME and field_MYFIELD with your names.
/**
* Implements template_preprocess_html().
*/
function MYTHEME_preprocess_html(&$variables) {
// Get the node.
if ($node = menu_get_object()) {
// Check node type.
if ($node->type === 'article') {
// Get taxonomy terms.
$terms = field_get_items('node', $node, 'field_MYFIELD');
foreach ($terms as $term) {
// Add body class.
$variables['classes_array'][] = 'article-term-' . $term['tid'];
}
}
}
}
Try to use template_preprocess_html()
this is in your theme's template.php file:
YOURTHEMENAME_preprocess_html(&$variables) {
$term_id = arg(1); // For example, or use some &drupal_static() to store a value while preprocessing from module
$variables['classes_array'][] = 'article-term-' . $term_id;
}
So as you can see it you shoud change template_ to your themename_ first

Drupal - 2 seperate feeds updating the same set of nodes (feeds module)

I'm using the feeds module to pull in a set of publications into a Drupal content type. They are set to run at regular intervals using cron. I have two separate feeds, which should work as follows:
Feed 1 (pure_feed) - pulls in the bulk of the fields
Feed 2 (harvard_format) - accesses a separate url source and updates one field on the content type.
The problem I have is that feed 2 always creates a new set of nodes rather than updating the existing nodes (that were created using feed 1). I have used the debug options at /import and can see that the GUIDs for feed 2 match the GUIDs for feed 1, but it still creates 2 sets of nodes rather than updating the 1 set of nodes.
Here is an excerpt from the feeds_items database table:
As you can see they both have the same GUID but they are mapped to separate nodes. Is there any way to have the second feed map to the same nodes as the first feed?
I knocked something together that allows my second feed to update the nodes from my first feed. Not sure if this is the right way of doing things but it works. Here's what I did in case it helps someone else in future:
Created a custom processor that extends FeedsNodeProcessor
Copied across all of FeedsNodeProcessor's functions to the new class.
Overrided the existingEntityId function as follows (harvard_format is my secondary feed and pure_feed is my primary feed):
protected function existingEntityId(FeedsSource $source, FeedsParserResult $result) {
if($source->id == 'harvard_format') {
$query = db_select('feeds_item')
->fields('feeds_item', array('entity_id'))
->condition('feed_nid', $source->feed_nid)
->condition('entity_type', $this->entityType())
->condition('id', 'pure_feed');
// Iterate through all unique targets and test whether they do already
// exist in the database.
foreach ($this->uniqueTargets($source, $result) as $target => $value) {
switch ($target) {
case 'url':
$entity_id = $query->condition('url', $value)->execute()->fetchField();
break;
case 'guid':
$entity_id = $query->condition('guid', $value)->execute()->fetchField();
break;
}
if (isset($entity_id)) {
// Return with the content id found.
return $entity_id;
}
}
return 0;
}
elseif ($nid = parent::existingEntityId($source, $result)) {
return $nid;
} else {
// Iterate through all unique targets and test whether they do already
// exist in the database.
foreach ($this->uniqueTargets($source, $result) as $target => $value) {
switch ($target) {
case 'nid':
$nid = db_query("SELECT nid FROM {node} WHERE nid = :nid", array(':nid' => $value))->fetchField();
break;
case 'title':
$nid = db_query("SELECT nid FROM {node} WHERE title = :title AND type = :type", array(':title' => $value, ':type' => $this->config['content_type']))->fetchField();
break;
case 'feeds_source':
if ($id = feeds_get_importer_id($this->config['content_type'])) {
$nid = db_query("SELECT fs.feed_nid FROM {node} n JOIN {feeds_source} fs ON n.nid = fs.feed_nid WHERE fs.id = :id AND fs.source = :source", array(':id' => $id, ':source' => $value))->fetchField();
}
break;
}
if ($nid) {
// Return with the first nid found.
return $nid;
}
}
return 0;
}
}
Copied across the the Process and newItemInfo functions from FeedsProcessor.
Overrided newItemInfo as follows:
protected function newItemInfo($entity, $feed_nid, $hash = '') {
$entity->feeds_item = new stdClass();
$entity->feeds_item->entity_id = 0;
$entity->feeds_item->entity_type = $this->entityType();
// Specify the feed id, otherwise pure_feed's entries in the feeds_item table will be changed to harvard_format
$entity->feeds_item->id = ($this->id == "harvard_format") ? "pure_feed" : $this->id;
$entity->feeds_item->feed_nid = $feed_nid;
$entity->feeds_item->imported = REQUEST_TIME;
$entity->feeds_item->hash = $hash;
$entity->feeds_item->url = '';
$entity->feeds_item->guid = '';
}

Nested relations in Drupal

I have a D7 website where users can make content (obviously...). So every node has it's own author. Every author is a member of an organization. But he can be a member of more then one organization. So far the facts.
I would like to create a view where the content is filtered on Author. Very easy, set the relation of the view on "Content's Author" and select the current user as filter.
But what I would like is to filter on the author's organization. So in fact it's a nested relation. Filter the nodes on the current logged in user (that's easy), but how can I filter on the current logged in user's organization?
Ok, the panels didn't work out, so I wrote my own hook :-)
function mymodule_views_pre_view (&$view, &$display_id, &$args) {
// Only execute this script when the view 'fiches_my_thema' is called
if ('fiches_my_thema' == $view->name) {
// Get users thema
global $user;
$userRoles = $user->roles;
$user_themas = array();
// Filter roles so you end up with the "Thema's".
foreach ($userRoles as $key) {
if(strpos($key,'edacteur')) {
$key = str_replace('Redacteur - ','', $key);
$key = str_replace('Eindredacteur - ','', $key);
$user_themas[] = $key;
}
}
// Resolve tid
$terms = taxonomy_get_tree(5);
$allRoles = array();
$arguments = array();
// Assign the 'tid' to a variable
foreach ($terms as $key) {
$singleRoles = $key->name;
$allRoles[] = $singleRoles;
if(in_array($singleRoles, $user_themas)) {
$arguments[] = $key->tid;
}
}
// Only when the arguments are NOT empty, set the arguments
if(!empty($arguments)) {
$finalArguments = implode("+", $arguments);
$args[] = "$finalArguments";
$view->set_arguments($args);
}
}
}

Resources