Theming view for multiple value field - drupal

I know this is probably a n00b question but I've searched everywhere for an answer and havent found anything.
I have a CCK multiple value field for "Features" where a product can have a random number of multiple features entered for it. I am editing the view so I can style the output of the features on the product page.
Right now in my view I can output the entire list of features at once using:
<?php print $fields['field_features_value']->content ?>
This will give me a list all the features given for a product. But what I want to do is loop through and pull out each individual feature and format/style it separately. How exactly would I do this?

I ran into this yesterday again, and spent hours trying to Google the syntax, to no avail.
I was able to get this to work, but I must admit it is not the best way. It is duplicating some of the work that Views has already potentially done for us, and should be considered a brute-force approach.
My use case involved theming each filefield file in a node separately, per node-based row:
<?php
// $Id: views-view-field.tpl.php,v 1.1 2008/05/16 22:22:32 merlinofchaos Exp $
/**
* This template is used to print a single field in a view. It is not
* actually used in default Views, as this is registered as a theme
* function which has better performance. For single overrides, the
* template is perfectly okay.
*
* Variables available:
* - $view: The view object
* - $field: The field handler object that can process the input
* - $row: The raw SQL result that can be used
* - $output: The processed output that will normally be used.
*
* When fetching output from the $row, this construct should be used:
* $data = $row->{$field->field_alias}
*
* The above will guarantee that you'll always get the correct data,
* regardless of any changes in the aliasing that might happen if
* the view is modified.
*/
?>
<?php
$output = explode('|', $output); // I've rewritten the field output in Views like this: [field_portfolio_image-field_name]|[nid]
$paths = $output[0]; // I've set filefield to show file paths rather than the file
$nid = $output[1]; // The NID is all that's really needed for this approach
$node = node_load($nid);
$slots = $node->field_portfolio_image;
foreach($slots as $prop) {
print ''.$prop[data][description].'';
}
?>
I used the Devel module heavily here (image reference for this example attached), in order to get the nested values I needed.
I know there is a better, proper way of doing this, rather than reloading the node data, since views should already have access to this upon page load.

When theming views is too specific I set conditions, relationships, parameters and all the views stuff except fields. The only field I use is node id.
Then when doing the theming I use...
$node = node_load($nid);
... to get the node object. You can inspect the node object with the dpm function that comes with the devel module.
dpm($node);
This "technique" works well for nodes and when you don't care about optimization or speed, because if you are going to do this with 1000 nodes you should load the nodes on batch.

Related

Drupal: How to restrict apachesolr search results by user/article facets

I have a wiki built with drupal, with a taxonomy category Workgroup, assigned to both the users and the articles. I am using apache solr search module with facet api and my end goal is to set up the search so that by default when users search for the articles, only articles from their workgroup are shown.
That is, when they launch the search from a search box, they should get the same results as for /search/site/hello?f[0]=im_field_kb_workgroups%3A4529 (where 4529 is one workgroup id) instead of just /search/site/hello (current behavior) Users should still be allowed to search in other workgroup facets when they want, by removing the checkbox in the facet block.
I have this working almost by hacking the apachesolr module (not recommended I know but really want this to work). In the function apachesolr_search_custom_page_search_form_submit, I have:
// Get the workgroup id
global $user;
$account = user_load($user->uid);
$user_kb_wg_fieldinfo = field_get_items('user', $account, 'field_kb_workgroups');
$user_kb_wg_tid= '';
if ($user_kb_wg_fieldinfo) {
$user_kb_wg_tid = $user_kb_wg_fieldinfo[0]['tid'];
}
// Add the solr filter for this workgroup facet so that by default, search results are
// fetched only from that workgroup.
if ($user_kb_wg_tid === '4529') {
$get['f[0]'] = 'im_field_kb_workgroups:4529';
}
This does the job but the problem is that this relies on the apachesolr search form. I have users coming to the wiki by searching from sites external to the wiki, where the wiki search form is just a simple POST form pointing to the KB domain and the path /search. So this will work only when people are searching from inside the wiki, where I present them the apachesolr search form.
I have investigated some other options:
In my custom module, I implement this hook (without the user workgroup checks for now, for testing):
function kb_hacks_apachesolr_query_prepare($query) {
$query->addFilter('im_field_kb_workgroups', '4529');
}
This filters the results from searches everywhere, but the filter is applied all the time, and users don't get to deselect this or other filters. (in fact, other filters appear only when passing the filter as a GET param like above with f[0])
I also played with the url_inbound_alter hook, but could not figure out how to pass the solr query param as GET. The following did not work.
function kb_hacks_url_inbound_alter(&$path, $original_path, $path_language) {
if ($path == 'search/site/hello') {
$_GET['f[0]'] = "im_field_kb_workgroups:4529";
//$_GET['f[0]'] = "im_field_kb_workgroups%3A4529";
//$path = 'search/site/hello?f[0]=im_field_kb_workgroups%3A4529;
}
}
Is there a way to set GET params from this hook? But even if this had worked, I would still have to figure out how to do this only by default (when the search form is submitted), and not when the filter itself is deselected. Is there a way to detect checkbox changes in the facet block?
Maybe there's another way to do this? I have been stuck here for the last two days and would really appreciate any help I can get. Thanks!
You can add a relationship to the taxonomy term "Workgroup" and use a contextual filter for the current user. In the contextual filters section, you can change the behavior when the filter is not present.

Referenced node display references

I have a node "Bug/Requests" which references one "Project".
On the project "node" page, I would like to display a list of bugs/requests which link to that project. Is this possible?
here is how I ended up doing it:
Is this good or bad? Is there a better way? (in template.php)
<?php
function digital_preprocess_node(&$vars)
{
$node = $vars['node'];
if ($node->type == 'project' )
{
$bugs_requests_nids = array();
$query = 'SELECT entity_id FROM field_data_field_project WHERE field_project_nid = :project_nid';
$result = db_query($query, array(':project_nid' =>$node->nid));
foreach($result as $row)
{
$bugs_requests_nids[] = $row->entity_id;
}
$vars['tasks'] = node_load_multiple($bugs_requests_nids);
}
}
I think you want the References Module (provides node and user reference fields for Drupal 7)
Apologies I didn't read properly, you also want the Corresponding node reference module which makes the node reference bi-directional (D7 versions of the modules given in another answer).
EDIT to address your new code:
I'm guessing you're pretty new to Drupal from your recent questions but either way you've hit on (in my opinion) the best method to do this. If you're comfortable writing PHP code (which a lot of Drupal users aren't) then grabbing the data directly will always be more efficient than using a contributed module that might have a lot of overhead.
A few minor points:
I'd consider moving your code out of the template file and into a custom module, inside a hook_node_load function instead so this data is available throughout the life of the nodes (that way you can re-use it in many different contexts). However if you don't need to reuse this data anywhere except in the template file then it's fine where it is.
If you're going to go directly into the field tables you should probably use the field_revision_field_x tables instead of field_data_field_x so you can take advantage of the revision system and always grab the most recent data.
As fields can be attached to multiple entity types you should make sure you're getting the right field data for the right entity (you may not plan to attach this field to any other nodes/entities but it's good practice in case you do).
This is a slightly edited version of your code taking into account the proper field types (untested but should work):
function digital_preprocess_node(&$vars) {
$node = $vars['node'];
if ($node->type == 'project' ) {
$bugs_requests_nids = db_select('field_revision_field_project', 'p')
->fields('p', array('entity_id'))
->condition('entity_type', 'node')
->condition('bundle', 'project')
->condition('entity_id', $node->nid)
->condition('revision_id', $node->vid)
->execute()
->fetchCol();
$vars['tasks'] = node_load_multiple($bugs_requests_nids);
}
}

comma separated views list

everyone. I've got a problem with Views 2. I have a view with row's style set to fields (Got only title field). I want to display these titles with comma separated list.
For example:
Kazakhstan, England, China, Korea
tried to do this:
foreach($fields['title']->content as $titles) {
$zagolovki[] = $titles['view'];
}
$title_list = implode(', ', $zagolovki);
print $title_list;
but it doesn't works - says error in argument. Please help me someone to display node titles in views with comma separated list. Thanks!
I quikly took a look in the views-view-fields.tpl.php that comes with the views module and it says
/*
* - $view: The view in use.
* - $fields: an array of $field objects. Each one contains:
* - $field->content: The output of the field.
* - $field->raw: The raw data for the field, if it exists. This is NOT output safe.
* - $field->class: The safe class id to use.
* - $field->handler: The Views field handler object controlling this field. Do not use
* var_export to dump this object, as it can't handle the recursion.
* - $field->inline: Whether or not the field should be inline.
* - $field->inline_html: either div or span based on the above flag.
* - $field->separator: an optional separator that may appear before a field.
* - $row: The raw result object from the query, with all data it fetched.
*/
So I think $fields is what you should iterate over. If you want to debug the structure of your $fields install the devel-module and use dpm() or dsm() to display the content of $field. Maybe take the template you edited (that should be one of the view-module templates in the views/theme folder) and look what happens there.
Where does it say the error occurs, though? nonsenz is probably right that $fields['title']->content is not an array. For debugging only, try adding
print("array content: "+ is_array($fields['title']->content));
before the foreach. If you know that $fields is a small nested structure, you can try a
print(str_replace("\n","<br/>",print_r($fields,true));
to see what exactly is in it, so that you can make verify that what you're trying to iterate over is in fact iterable.
I've created this module:
http://drupal.org/project/views_delimited_list
I'm not too sure about fiddling with the options to create merely a comma-separated list. You should be able to, and if you can't I'll fix it.

Drupal Taxonomy Block, Vocabulary Listing

I looking for the best way to implement a block that lists all terms of a certain vocabulary. Each term should link to page that lists all nodes associated with that term. Any help would be greatly appreciated. Thanks!
See here for a great tutorial to achieve exactly what you want
http://chrisshattuck.com/blog/how-add-block-menu-tags-or-other-taxonomy-terms-drupal-site
The easiest way to approach this would probably be to use Views, and simply create a new view of the type "term". Here's a quick example which assumes that you have some basic familiarity with the Views UI:
Visit Views > Add (build/views/add), give your new view a name, and select Term from the "View type" radio buttons.
On the next page, start by adding a Taxonomy: Vocabulary filter and selecting your vocabulary in the filter settings.
Add a Taxonomy: Term field and enable the Link this field to its taxonomy term page option in the field settings. You might also want to remove the field's label, since this is just a simple listing.
You probably want your display to display all terms in your vocabulary, so change the "Items to display" 0 (unlimited). By default, new views only display 10 items at a time.
Check out the Live preview below to see if it's outputting what you need.
Add a new Block display using the dropdown on the left side of the Views UI.
Give your new block a name in the "Block settings" area. This is the description that will appear on Drupal's block admin page.
Save your view and visit admin/build/block to place and configure your block.
It's worth noting that Views does indeed have some overhead, but in my experience, its flexibility and ease-of-use far outweigh the relatively minor performance hit.
If you'd like to avoid using Views, you could write a pretty simple custom module using hook_block() and adapting http://drupal.org/node/247472. If you'd like, I can edit this answer with an example module based on that.
(Posting this as another answer, since this is a different approach than my first answer.)
As I mentioned above, here's another approach involving a custom module based on the code at http://drupal.org/node/247472. You could also just drop that code into a custom block with the "PHP" input format selected, but that's generally considered to be bad practice.
Add a new folder in sites/all/modules called vocabulary_block. Customize and add the following two files:
vocabulary_block.module
<?php
/**
* #file
* Exposes a block with a simple list of terms from [vocabulary].
* Each term is linked to its respective term page.
*/
/**
* Lists terms for a specific vocabulary without descriptions.
* Each term links to the corresponding /taxonomy/term/tid listing page.
*/
function vocabulary_block_get_terms($vid) {
$items = array();
$terms = taxonomy_get_tree($vid, 0, -1, 1);
foreach($terms as $term) {
$items[]= l($term->name, "taxonomy/term/$term->tid");
}
if(count($items)) {
return theme('item_list', $items);
}
}
/**
* Implementation of hook_block().
*/
function vocabulary_block_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('List of [vocabulary] terms');
return $blocks;
case 'view':
if ($delta == 0) {
$vid = 43;
$block['subject'] = t('[Vocabulary]');
$block['content'] = vocabulary_block_get_terms($vid);
}
return $block;
}
}
vocabulary_block.info
name = Vocabulary Block
description = Exposes a block with a simple list of terms from [vocabulary]. Each term is linked to its respective term page.
; Core version (required)
core = 6.x
; Package name (see http://drupal.org/node/101009 for a list of names)
package = Taxonomy
; Module dependencies
dependencies[] = taxonomy
Notes
Be sure to change $vid = 43; to
reflect the ID of the vocabulary that
you'd like to load. You can find the
VID by visiting
admin/content/taxonomy and looking at
the destination of the edit
vocabulary link for your
vocabulary. The VID will be the last
fragment of that URL:
admin/content/taxonomy/edit/vocabulary/[vid].
I wouldn't normally hard-code the
$vid into the module itself. However,
setting up the necessary Drupal
variable and administration form (to
allow users to select a vocabulary
from the Drupal interface) would be
overkill for this answer.
For your own documentation purposes,
don't forget to search/replace
[vocabulary] in those two files and
use your own vocabulary's name
instead.
This method may not necessarily be more performant
than the Views method I described
earlier, especially once you start considering caching,
optimization, etc.
Since performance is a priority,
I recommend thoroughly testing a
variety of different methods on this page and
choosing whichever one is fastest for you.

Drupal - Getting node id from view to customise link in block

How can I build a block in Drupal which is able to show the node ID of the view page the block is currently sitting on?
I'm using views to build a large chunk of my site, but I need to be able to make "intelligent" blocks in PHP mode which will have dynamic content depending on what the view is displaying.
How can I find the $nid which a view is currently displaying?
Here is a more-robust way of getting the node ID:
<?php
// Check that the current URL is for a specific node:
if(arg(0) == 'node' && is_numeric(arg(1))) {
return arg(1); // Return the NID
}
else { // Whatever it is we're looking at, it's not a node
return NULL; // Return an invalid NID
}
?>
This method works even if you have a custom path for your node with the path and/or pathauto modules.
Just for reference, if you don't turn on the path module, the default URLs that Drupal generates are called "system paths" in the documentation. If you do turn on the path module, you are able to set custom paths which are called "aliases" in the documentation.
Since I always have the path module turned on, one thing that confused me at first was whether it was ever possible for the arg function to return part of an alias rather than part of system path.
As it turns out, the arg function will always return a system path because the arg function is based on $_GET['q']... After a bit of research it seems that $_GET['q'] will always return a system path.
If you want to get the path from the actual page request, you need to use $_REQUEST['q']. If the path module is enabled, $_REQUEST['q'] may return either an alias or a system path.
For a solution, especially one that involves a view argument in the midst of a path like department/%/list, see the blog post Node ID as View Argument from SEO-friendly URL Path.
In the end this snippet did the job - it just stripped the clean URL and reported back the very last argument.
<?php
$refer= $_SERVER ['REQUEST_URI'];
$nid = explode("/", $refer);
$nid = $nid[3];
?>
Given the comment reply, the above was probably reduced to this, using the Drupal arg() function to get a part of the request path:
<?php
$nid = arg(3);
?>
You should considder the panels module. It is a very big module and requires some work before you really can tap into it's potential. So take that into considderation.
You can use it to setup a page containing several views/blocks that can be placed in different regions. It uses a concept called context which can be anything related to what you are viewing. You can use that context to determine which node is being viewed and not only change blocks but also layout. It is also a bit more clean since you can move the PHP code away from admin interface.
On a side note, it's also written by the views author.
There are a couple of ways to go about this:
You can make your blocks with Views and pass the nid in through an argument.
You can manually pass in the nid by accessing the $view object using the code below. It's an array at $view->result. Each row in the view is an object in that array, and the nid is in that object for each one. So you could run a foreach on that and get all of the nid of all rows in the view pretty easily.
The first option is a lot easier, so if that suits your needs I would go with that.
New about Drupal 7: The correct way to get the node id is using the function menu_get_object();
Example:
$node = menu_get_object();
$contentType = node_type_get_name($node);
Drupal 8 has another method. Check this out:
arg() is deprecated

Resources