Providing users with source code

Events happening in the community are now at Drupal community events on www.drupal.org.
akanik's picture

Hello all,

I have a question about providing source code to users. I'm developing a news site that will make it's articles available to whoever wants to republish them, provided that appropriate credit and article formatting guidelines are adhered to. For a more clear idea of what I am talking about, you can visit http://www.propublica.org/blog/item/what-exactly-is-the-war-powers-act-a... and click "Republish" by the byline.

A window come up that stipulates republishing guidelines and then a field where the source code is available for copying.

I would assume this is a views related thing.... but does anyone know of a good way to accomplish this?

Thanks so much,
Allie

Comments

Off the top of my head, you

RobW's picture

Off the top of my head, you could:

  1. use a computed field on your content type,
  2. provide it with code in the same structure as your article tpl (or just the parts you want to republish),
  3. process the output with a text/input filter that converts all special characters to html entities,
  4. and render it in the appropriate tpl.

A downside to this approach is there would be no connection with your theme's tpls and the code you insert in the computed field, so any time you update the article tpl you'll have to manually update the computed field. On the other hand, this could be a good thing if you want the two to be slightly different: for example you could use relative image paths in your article tpl and full paths (http://www.yoursite.com/yourtheme/yourimage.png) in the computed field, or you could remove any site specific markup in your computed field and provide republishers with a stripped down, purely semantic version.

[Edit] It occurred to me later that you'd probably provide the computed field with code that's already been sanitized, i.e., all special chars to html or unicode entities, and drop the content in by printing field variables. No need for step 3.

Oh great! That sounds

akanik's picture

Oh great! That sounds wonderful and I think I understand most of it. I'm going to take a few days to research some stuff and see if I get it. One thing though, where does that code sanitation code go? Can I put it in the php of the computed field, or would it need to go somewhere more general?

thanks!

allie

Re: code sanitation, you want

RobW's picture

Re: code sanitation, you want to convert all of the special characters into html entities (stuff like < and >) in the computed field, so the output will display correctly when you print it in your tpl. Quick example:

<?php
//would print <h1>Contents of $your_field</h1>, and then line break.
print '&lt;h1&gt;' . $your_field . '&gt;/h1&lt;' . "\n";
?>

In a computed field your node's fields are in a special object or array, can't remember what it's called, it's in the docs. So it would really be $element->your_field or some such.

So I've been researching

akanik's picture

So I've been researching computed fields and I'm having an issue with the two different textareas that the field settings area provides for you. The first is "Computed Code (PHP)", which seems to want you to add a value for the field. The second is "Display Code (PHP)", which seems to be the php code that will govern the display of the field.

I've searched for documentation on this, but the only real info I've found is here http://drupal.org/node/149225 and they still use ambiguous language (at lease, ambiguous to me). So I suppose I'm asking, what is Computed Code? Display Code? How do they work together to produce a computed field?

I almost took the cowards way out and coded the republish code directly into the article.tpl.php. Then one of my colleges informed me that the "Republish this Article" would need to be an optional feature for an article; some articles can be republished, while others will not have that option. That made me think that having the Republish be a field, as you so wisely suggested, would be better, because then I could use taxonomy, panels, and views to hide and show the field.

Thanks in advance for your help!

Field value and rendered output

tmanhollan's picture

Computed Code is the code that will execute to determine the value of the field. Display code is the code that will execute to render the output. Computed code stores its value in the value element of the field item inside the node. This allows the raw value to be accessible elsewhere, including in the display code. Display code could be as simple as just retrieving the stored value, but it gives you the opportunity to apply some additional output to it that you might not want used elsewhere (in another calculation, for example).

Say your content type had a numeric field 'field_cars' and another numeric field "field_trucks' and a computed field 'field_total_vehicles'. Computed code would do the calculation of cars + trucks, like this:

<?php

  $node_field
[0]['value'] = $node->field_cars[0]['value'] + $node->field_trucks[0]['value'];
?>

and Display Code would control how that value was rendered:

<?php
  $display
= '<div class="total_vehicles_computed_value">' . $node_field_item['value'] . '</div>';
?>

$node_field is a variable available to the code in the computed code block and is the field object that gets attached to the node after it's defined. $node is another variable that represents the entire node that this field is being attached to. You have access to any other portion of the node that has already been loaded (so any field that was defined before or has less weight than the computed field you're dealing with--if your computed field is the last/heaviest field defined for your content type, $node will contain all the other field definitions). Inside display code, $display is a variable that you assign the desired output to--when drupal renders the field, it will basically do a print $display. $node_field_item is another variable available to the display code that represents the item of the field being rendered. It is an array where the element with the key 'value' contains whatever was assigned to the value portion in the computed code. So display-code's $node_field_item['value'] equals computed-code's $node_field[0]['value'].

So, in my example, if you had 2 cars and 2 trucks, the computational portion would simply add 2 + 2 and store it in the fields first value. Note, this assumes those two fields referenced in the computation are single-value fields (field_cars[0] represents the first value). The display portion would take the value and wrap it in a div and your output would be '<div class="total_vehicles_computed_value">4</div>'

For your case, conditionally allowing republishing could be part of the computed code as well (e.g. if($node->field_allow_republishing[0]['value'] == 'Yes') $node_field[0]['value'] = 'Republish output goes here.').

All of that information was

akanik's picture

All of that information was wonderful. I feel like I have a much better understanding of what is happening with Computed Field. I'm now able to get the field to show up! However the references I put into the code are still not recognized. I'm running d7 so a few things are different; computed fields can be added to all sorts of things like users and taxonomy, so they have changed $node to $entity. $display is also now $display_output. I'm not the greatest with php so I'm not sure if other things have changes (code-wise) and I've just missed it.

I was wondering though, where do you find the paths for the field values? I've been looking in my devel tab (which is how I work it when adding things to the tpl.php documents) but none of those values seem to work. Or is it always field_fieldname['0']['value'] when you want to get the value of a field?

thanks so much for your help.

I know very little about

tmanhollan's picture

I know very little about what's changed in d7; what I say here is based on just a cursory look at the documentation and the d7 version of computed field and a brief examination of $entity and the other variables available to computed code. It appears what's changed is that there's a language specification involved in the structure of the field. Generally it appears, field_machine_name[LANGUAGE_NONE][0]['value'] gets you the 'value' of the first (in multi-value fields) or only (in single-value fields) record of a field with the machine name "field_machine_name" in a language-neutral setting. I have no idea how translation fits into the picture here, but the computed code example provided by the module uses the constant LANGUAGE_NONE. Looks like $langcode and $entity_lang are two variables that might be useful in place of LANGUAGE_NONE if you're in a multi-language environment, but again, I'm not completely sure what's going on with the language aspect.

A few comments on the field structure: Some fields don't store a value--e.g. node reference fields store the nid instead of value (field_fieldname[LANGUAGE_NONE][0]['nid'] = 1234), although I think that may also be different in d7. Some fields store additional information besides value--e.g. date fields can store, among other things timezone (field_fieldname[LANGUAGE_NONE][0]['value'] = 2011-08-10, field_fieldname[LANGUAGE_NONE][0]['timezone'] = America/New York). For single-value fields, the number in the brackets is always 0. For multi-value fields, 0 represents the first value for the field, 1 represents the second, n-1 represents the nth value.

If you really want to know what you can reference in the computed code, you can examine the value of the variables available at the time Computed Code executes. I don't know of a good way of doing that inside the computed code block. Normally I'd suggest Drupal for Firebug, which you can use to print messages from anywhere in the php execution process to Firebug. When I tried it though, I got no output from within the Computed Code block. That code may be eval-ed in a way that makes its output unavailable to firebug. Drupal for Firebug might still be useful for you--if $entity is a node, you can examine the node section of the drupal firebug tab and you should see [field_machine_name] => array... If so, then $entity->field_machine_name is an array that will look like what you see inside that array output.

Thanks so much for all your

akanik's picture

Thanks so much for all your help. I've got d7 computed field figured out now (at least for my current purposes), however I'm still running into one problem.

@RobW, you had mentioned at first that I would need to use a filter to convert all special characters to html entities, but then suggested that I just provide the computed field with already sanitized code. This suggestion works on all but the body field, because it cannot just be placed inside of a "p tag" it needs to show all of the individual tags and html entities inside of the body.

I've been trying to get at the raw value of the body (html entities included) but haven't found a way yet. @RobW, if you (or anyone) could elaborate on your first suggestion about running the output through a filter to expose those html entities, that would be great. Alternatively, if anyone has another suggestion, I would be most happy to hear it!

Thanks again,
allie

Ahh, I see. That makes

RobW's picture

Ahh, I see. That makes sense.

I would look at Text Formats under configuration menu - creating a new one based on whatever is being applied to your node in standard display and then putting "Display any HTML as plain text" at the end should get you half way there. Then look at a function like check_markup or some such to apply that filter with php in your computed field.

Sorry this is more a point-in-the-direction post as opposed to a concrete example post, but all my projects are in planning or frontend stages and I haven't been deep in Drupal for a month or two. Hope it helps.

I actually figured it out!

akanik's picture

I actually figured it out! I'm going to post my solution in the computed field section because the examples there helped me out, but here is a brief outline of what i did:

1) used the computed field (field_republish) to pull the title, subtitle(deck), author, and body from the node
1a) to make the body html show i used htmlentities()
1b) the rest of the field i wrapped in the appropriate sanitized code (as RobW suggested)
1c) also had to dig into the author field to get the author name, because it is a node reference field
2) added a boolean field called field_allow_republishing (as tmanhollan suggested)
3) made computed field output the desired code only if field_allow_republishing == "1"
4) in "Display fields", hid both field_allow_republishing and field_republish
5) in the appropriate template, added the field and wrapped it up in a jquery modal dialog box so that people would need to click "Republish this Content" for the field to show up. Again, "Republish this Content" button and field_republish only appear if field_allow_republishing == "1"

Thanks so much for everyone's help! And like I said I will post the link to the full explanation which will be somewhere in the computed field area. I'll also post a link to see it happen when my site goes live.

for now:

computed code -

$title_raw = $node->title;
$title = '&lt;h1&gt;' . $title_raw . '&lt;/h1&gt;';

$deck_raw = $node->field_deck[0]['value'];
$deck = '&lt;h2&gt;' . $deck_raw . '&lt;/h2&gt;';

$author_reference = node_load($node->field_op_author[0]['nid']);
$author_raw = $author_reference->title;
$author = '&lt;h3&gt;by:' . $author_raw . '&lt;/h3&gt;';

$body_raw = $node->body;
$body = htmlentities($body_raw);

$permission = $node->field_allow_republishing[0]['value'];

if($permission == "1")
{$node_field[0]['value'] = $title . $deck . $author . $body; }
else{$node_field[0]['value'] = 'No republishing'; };

display format:

$display =  $node_field_item['value'];

Very nice. I love that

RobW's picture

Very nice. I love that feeling when you pull together 10 things you've learned recently and create something custom and complex that works just how you want it to! It's like a drug, keeps all of us coming back for more.

Pittsburgh

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: