I like simplifying the node form. One of my tricks in the past has been to conditionally hide CCK elements on new node creation when I want to enforce some kind of default. One of my favorite tricks is to whisk away things put in place by the Prepopulate module. Unfortunately for me, it's recent move to an #after_build-based mechanism seems to be creating all kinds of collisions in how I can manipulate the widget.
This is what I used to do in hook_form_alter():
$form['field_my_nodereference_field'][0]['#type'] = 'hidden';
$form['field_my_nodereference_field'][0]['#value'] = $form['field_my_nodereference_field'][0]['#default_value']['nid'];
$form['field_my_nodereference_field'][0]['#parents'] = array('field_my_nodereference_field', 0, 'nid');
But when I try to play this game in #after_build, I run into errors with the hidden type's validation, or the nodereference_autocomplete_validation. I have resorted to conditionally adding a CSS file. This makes me sad.
Hidden is not enough. Try this one:
$form['field_my_nodereference_field'][0]['#type'] = 'nodereference_hidden';
when the type is a CCK field you have to pass this format _hidden
for instance for a simple text field I used
$form['field_srt'][0]['#type'] = 'text_hidden';
or for a filefield field I used
$form['field_myfile'][0]['#type'] = 'filefield_hidden';
Related
I'd like to translate each node title as a string (using i18n). I'm trying this function in my theme template:
function theme_process_page(&$variables) {
$variables['title'] = t($variables['title']);
}
Yet when I refresh strings, none of my node titles are on the list. Is there something I'm missing?
And to clarify the function name is using my theme name, not the word "theme".
Title is my usual solution for this (I use Entity Translation, it works fine with Title module).
This module replaces node titles by a regular translatable text field. You can choose wich content type titles must be replaced (on the "Manage Field" forms, you'll find a "replace" link in the title row). Pretty useful.
Good luck
You should never use t() to translate user-supplied or variable strings. See the documentation on the function.
That said, there are some solutions, one is to use the built-in language support for entity fields. Following that you should be able to do something like this in a field hook (in a module, not in your template):
$langcode = $field_info['translatable'] ? $content_langcode : LANGUAGE_NONE;
$entity->{$field_name}[$langcode][0]['value'] = t("Salut!");
We had a whole collection of Plone 3 sites with a custom Image type
subclassed from ATImage. This allowed us to add an extra image scaling to the
standard list ("'logo':(454, 58)", used by our theme package).
While this still works in Plone 4, it isn't really the correct approach now that
plone.app.imaging is part of the standard toolkit. That can define custom scales on
the fly.
It looks like I can enable plone.app.imaging on any type subclassed
from ATImage by simply setting "sizes = None" for the collection of custom
scales on the type. I am however then left with a redundant subclass of ATImage.
Looking long term, it would be useful to replace all of our existing "FalconImage"
content items (hundreds in total) with standard "Image" content items.
A brief experiment on a test site reveals that if I just walk through the document
tree updating the portal_type attribute from "FalconImage" to "Image" then
the content behaves as an "Image": each object suddenly acquires a
Transform tab and all of the scales defined by ##imaging-controlpanel.
I am sure that there would be fallout from such a brute force approach.
Is there a recommended approach for transforming one type into another?
(I'm happy to add source for our custom ATImage type if anyone thinks that
it is relevant. It is really just a very minimal tweak of ATImage, with a
different collection of sizes on the ImageField)
Yes, there is a recommended approach:
http://pypi.python.org/pypi/Products.contentmigration
The only thing that you have to do is to write a custom migration from FalconImage to Image.
Bye,
Giacomo
You need to use Products.contentmigration but the docs there are no place to start. Use the docs at plone.org for a step-by-step on migrating content.
Thanks to Giacomo and Ross for the pointers.
Just in case it is useful to others, my migration code ended up looking like the following:
from Products.contentmigration.walker import CustomQueryWalker
from Products.contentmigration.archetypes import InplaceATItemMigrator
class FalconImageMigrator(InplaceATItemMigrator):
walker = CustomQueryWalker
src_meta_type = "FalconImage"
src_portal_type = "FalconImage"
dst_meta_type = "ATBlob"
dst_portal_type = "Image"
# Following stolen from plone.app.blob.migrations, ATImageToBlobImageMigrator
# migrate all fields except 'image', which needs special handling...
fields_map = {
'image': None,
}
def migrate_data(self):
self.new.getField('image').getMutator(self.new)(self.old)
# ATFileToBlobMigrator reindexes certain fields. Otherwise we
# need to clear and rebuild the entire catalog.
def last_migrate_reindex(self):
self.new.reindexObject(idxs=['object_provides', 'portal_type',
'Type', 'UID'])
migrator = FalconImageMigrator
walker = migrator.walker(portal, FalconImageMigrator)
walker.go()
print walker.getOutput()
Complications:
Image is a little odd as a destination type, as data gets migrated into the blob store.
We need to update the catalog so that "resolveuid/UID" links generated by TinyMCE
continue to work. last_migrate_reindex() method on Migrator class should be faster than clearing and rebuilding the entire catalog from scratch.
In my multilanguage Drupal 6 website I need to make my CCK field default values translatable, i.e.
Hello - in the English version
Bonjour - in the French one
I cannot find this text with Translation Table, neither are these values in variable table so that I can use multilingual variables.
Do You know how to have different default values in different languages?
When you define the CCK field, you can enter a PHP code snippet to override the default value of the field.
Enter the following there :
return array(0 => array('value' => t('Hello')));
Now access a node add page with this CCK field from a non-English version so that it gets added to translatable strings.
Now you're able to translate it using the "Translate interface" menu (it might take a visit to the "create" page of your cck type first though). It doesn't require any extra modules in fact, just basic D6 (and it probably works in D5 and D7 as well).
This method is a bit of a hack. Im not sure I would deploy this without really considering the consequences. For a simple usecase it MIGHT be ok.
Create a custom module, lets say def_translate. To def_translate.module, add a function
function def_translate_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
if($node->type == "sometype"
&& $op == "load"
&& $node->field_some_cck_field_type[0]['value'] == "your default value")
{
$node->field_some_cck_field_type[0]['value'] =
t($node->field_some_cck_field_type[0]['value']);
}
}
Ok - so what is this doing?
When a node is loaded, hook_nodeapi gets called, with $op set to "load". This gives us an opportunity to do manipulate the node before it is rendered. Before we do anything we check
Is this the right type of node?
Is our op = "load"?
Is the value our default value?
What we then do is pass the existing default value through the t() function. This will make the default string available to i18n translation table, and you can then use the normal way of translating strings.
*DISCLAIMER*
I have not tested this myself in production. Im not entirely sure what the effects will be. You probably want to think this through before implementing it, and you probably want to put some features in to look up the default values from the DB incase they are changed in the CCK UI.
Hope this helps - or possibly shakes a hint of a solution to your problem!
I don't know if I'm on the right track but I'm trying to let users of my web site create there own versions of pages on my web site.
Basically I'd like to make our documentation used as a starting point where they just add details and make a new page for themselves in the process.
I have a 'book' content type that I have changed with CCK and a 'client edits' content type that uses a nodereferencefromURL widget to link itself to the book node.
So simple version of what I'm saying is I have a link on my book pages that creates a node using client edits content type. I would like to put some fields on the client edits content type that take the values of some of the fields from the book page it is linked from.
I'm sure I'm missing something as I would have thought someone would have tried this before but I can't even find a hint on how to go about this.
All I really need is a point in the right direction if my current thinking is wrong.
Current thinking is that I use a php script to get the default value for a field on the new node add screen that drags the value for a field from the book I'm linking from.
I'm thinking this is the case because there is an option for default values for the field in cck manage fields that lets you put in a php value to return a default value for your field.
Am I on the right track or is there already a module or process that does what I'm talking about and I'm just too dumb to find it.
This sounds a little strange, are your client edits going to be a diff from the original node or just coppied data?
I would prehaps do it a more simple way, just have book nodes, and have different fields disaply depending on who edits it (enable the content_permissions module). That way you can use the node clone module to create the users copy.
You will need to make a module to contain your custom php code.
I ended up using rules to save information from the user and the cloned node into hidden fields.
One that saved the original node ID into a field when ever you create content of that type unless the url ends with Clone. This means that when you create the clone the original node ID is kept in the field.
That made it easy to use a views argument that took the node ID to make the clone appear along side the original when a user visits the original page.
The second rule trick was to compute a field that saved the "store name" from the profile of the user only when saving clone content.
This meant that there was a hidden field on the clone that stored the info so I could then use another views argument to restrict the view to only people with the same store name in their profile.
I am no good with PHP but I managed to find a snippet (can't remember where) that returns the store name of the current logged in user as the argument.
global $user;
profile_load_profile($user);
return $user->profile_store_name;
...or, in other words, how to create a simple join as I would do in SQL?
Suppose I want the following information:
Just as an example:
a person's full name
a person's hobbies.
His full name is in a (content profile) node type 'name_and_address' and his hobbies are in 'hobbies'.
In SQL, I would link them together by node.uid.
I've seen a bit about using relationships, but that goes with user-node-refs.
I just want the same user from one content-type and the other.
Now how could I get his name and his hobbies in 1 view?
There is a how to here does this do the job?
If not...
Views can be extended with custom joins, filters etc. If you are lucky there will be a module for this already. Some modules even provide their own views plugins.
You can write your own views plugins, although the documentation is a little fragmented.
The other thing that should be noted is that views isn't always the answer. Sometimes writing a custom query and display handler will do what you want with much less hassle.
Look at the relationships section of the view. This allows you to relate (ie join) different types of content (ie tables). It's not especially intuitive to someone used to SQL, but this video explains much of it. http://www.drupalove.com/drupal-video/demonstration-how-use-views-2s-relationships
You could use views_embed_view() in your template files to manually specify where they appear (and by extension render one view right below another).
You could override this function in a custom module (modulename_embed_view($name, $display_id)) in order to selectively edit what data is allowed out to the page.
Ex):
function modulename_embed_view($name, $display_id) {
if (strcmp($_GET['q'], 'node/123') === 0) {
$view = views_get_view($name);
$view2 = views_get_view('second view');
$output = $view['some element'] . $view2['element'];
}
return $output;
}
I know that this is very much a hack - I just wanted to show how one might use php to manually render and modify views in your template files.