Programatic CCK Now Possible!
public
joshk - Mon, 2007-07-23 20:40
I just wanted to point out a very important change to content_copy.module that makes it much more fasible to create CCK field programatically as part of an install profile. As of last week, the DRUPAL-5 CVS version of content_copy.module no longer ends content_copy_import_form_submit() with a drupal_goto().
Previously, if you attemted to import a CCK node-type using drupal_execute(), your script would redirect to an admin page, which is problematic during an install profile as it short-cirtuits the process. This is no longer the case.
You can now run code similar to the following:
<?php
include_once './'. drupal_get_path('module', 'node') .'/content_types.inc';
include_once('./'. drupal_get_path('module', 'content') .'/content_admin.inc');
$values = array();
$values['type_name'] ='<create>';
$values['macro'] = /** YOUR CCK EXPORT DUMP HERE **/
drupal_execute("content_copy_import_form", $values);
?>And continue with your install script. Happy profiling!
Sitewide tags: CCK · install profiles



SWEEEET!
Thanks for the heads up.
Very exciting
Josh, if you have some simple examples I am sure we could start building snippets.
Kieran
To seek, to strive, to find, and not to yield
New Drupal career! Drupal profile builders.
Try pre-configured and updatable profiles on CivicSpaceOnDemand
Real soon
We'll be making an initial check in of our conference organizing distribution in the next two or three days. This will show how we're using the above code in conjunction with flat text files containing the CCK information.
http://www.chapterthreellc.com | http://www.outlandishjosh.com
Will add to install profile api
Something like:
<?phpfunction install_create_content($macro) {
include_once './'. drupal_get_path('module', 'node') .'/content_types.inc';
include_once('./'. drupal_get_path('module', 'content') .'/content_admin.inc');
$values = array();
$values['type_name'] ='<create>';
$values['macro'] = $macro;
drupal_execute("content_copy_import_form", $values);
}
?>
Except those include_once's need some love depending on where you have your code, methinks.
Used in an install profile as:
install_create_content($macro);Where the best way to maintain the macro would likely be to suck this in from an external file -- e.g. cck_userprofile.inc, etc.
are includes needed?
I may be missing something here, but from my testing a few months back, no includes are needed since the form being called is in content_copy.module and an install profile only executes after a full bootstrap.
Would it be considered bad form to just call content_copy_import_form_submit with the values requried? It wouldn't really be bypassing any submit handlers, just avoiding an extra call to drupal_execute (which is what content_copy_import_form_submit calls anyway).
I'll work on some code to parse an external file if I get a chance. I think there is some applicable code in panels that could be reused ;)
There are a few gotchas here
I guess this bug had been submitted many times, but my last submission of it finally got it fixed (http://drupal.org/node/160130). When you do an export of a cck type you have to change the exported code a little bit. Most notably, the export will use single quotes so you cant wrap your string in single quotes, so you can use either double quotes or heredoc syntax. Also in PHP when using variables inside a heredoc statement or double quotes, the variable will get replaced and not be taken as the literal string, for example:
<?php$var = 1;
print "$var"; // 1
print '$var'; // $var
?>
So we have to escape our variables. So a dump of a simple cck type named 'topics', which has 'title' and 'description' would be:
$content[type] = array ('name' => 'Topic',
'type' => 'topic',
'description' => 'A Topic is the overarching category which contains Goals.',
'title_label' => 'Title',
'body_label' => 'Description',
'min_word_count' => '0',
'help' => '',
'node_options' =>
array (
'status' => true,
'promote' => false,
'sticky' => false,
'revision' => false,
),
'comment' => '2',
'upload' => '1',
//'event_nodeapi' => 'never',
'upload_inline' => 0,
'old_type' => 'topic',
'orig_type' => '',
'module' => 'node',
'custom' => '1',
'modified' => '1',
'locked' => '0',
);
And the code to submit this programatically:
<?php//////// define the 'topic' node type ///////
$form_values['type_name'] = '<create>';
$form_values['macro'] = <<<TOPICS
\$content[type] = array (
'name' => 'Topic',
'type' => 'topic',
'description' => 'A Topic is the overarching category which contains Goals.',
'title_label' => 'Title',
'body_label' => 'Description',
'min_word_count' => '0',
'help' => '',
'node_options' =>
array (
'status' => true,
'promote' => false,
'sticky' => false,
'revision' => false,
),
'comment' => '2',
'upload' => '1',
//'event_nodeapi' => 'never',
'upload_inline' => 0,
'old_type' => 'topic',
'orig_type' => '',
'module' => 'node',
'custom' => '1',
'modified' => '1',
'locked' => '0',
);
TOPICS;
drupal_execute('content_copy_import_form', $form_values);
?>
Note: if your content type has additional fields it would have a 2 variables that need to be escaped, $content[type] and $content[fields]
I didn't know how to do heredoc syntax until chx showed me a snip with some heredoc in it, and I got caught up because i was indenting the the close tag "TOPICS;" and that needs to be on its own line and NOT indented.
-Steve
Yes
Gotta watch out handling text. I am actually pursuing the method of keeping the cck export data as a flat text files and packaging that as part of the install profile.
http://www.chapterthreellc.com | http://www.outlandishjosh.com
Can I help?
I've been trying to get into to development for the community for a while. I have been doing private development for my job, but nothing I am allowed to contribute back ( I know.... I don't like it either ). I've already got a few ideas of how to accomplish this.
- With cck in core, we could think about adding an additional profile hook. Something like _profile_content_types() which would search the profile folder for cck text file exports and import those types.
- Another idea I had was to check the array returned by _proifle_modules() and use this to define content types as well. So while going through the returned array turning on modules, if the modules wasn't found via standard module means, check the profile folder for a cck text file that would create the type.
-Steve
Can't get this to work
Okay, I've been fighting with this for a couple weeks now and have been trying to follow this, but I can't get it to work. If I had much hair left, I'd have pulled it out by now. I'm trying to create a CCK content type as part of a module install, but no matter which way I go and how I follow this example, I get an error.
Here's what I have to this point:
<?phpfunction imagelist_install() {
drupal_set_message('Installing imagelist');
$form_values['type_name'] = '<create>';
$form_values['macro'] = <<<IMAGES
\$content[type] = array (
'name' => 'Image',
'type' => 'image',
'description' => 'Image to be displayed',
'title_label' => 'Title',
'body_label' => 'Description',
'min_word_count' => '0',
'help' => 'Size must be less than 1.5 MB',
'node_options' =>
array (
'status' => true,
'promote' => false,
'sticky' => false,
'revision' => false,
),
'comment' => '2',
'old_type' => 'image',
'orig_type' => '',
'module' => 'node',
'custom' => '1',
'modified' => '1',
'locked' => '0',
);
\$content[fields] = array (
0 =>
array (
'widget_type' => 'image',
'label' => 'Photo',
'weight' => '0',
'max_resolution' => 0,
'image_path' => 'photos',
'custom_alt' => 0,
'custom_title' => 1,
'description' => '',
'group' => false,
'required' => '1',
'multiple' => '0',
'field_name' => 'field_photo',
'field_type' => 'image',
'module' => 'imagefield',
),
);
IMAGES;
drupal_execute('content_copy_import_form', $form_values);
}
If I run it like this, I get the following error when I submit the Module admin page with my module checked:
* Installing imagelist* The configuration options have been saved.
* Installing imagelist
* The configuration options have been saved.
* Installing imagelist
* An error has occured adding the content type image.
Please check the errors displayed for more details.
* The configuration options have been saved.
* The import data is not valid import text.
* warning: Cannot modify header information - headers already sent by (output started at C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\sites\all\modules\cck\content_copy.module(251) : eval()'d code:1) in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\includes\common.inc on line 309.
* The import data is not valid import text.
* warning: Cannot modify header information - headers already sent by (output started at C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\sites\all\modules\cck\content_copy.module(251) : eval()'d code:1) in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\includes\common.inc on line 309.
* warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'node_type_form' was given in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\includes\form.inc on line 217.
Everything within the heredoc tags is a straight export from a working CCK type. Can anyone explain what I could be missing that is causing the error?
Thanks.
I'm liking it!
As I posted over at 2bits:
Now I've put in my four cents twice, but I can't be alone in wanting more, more, more ;-)
~ ben melançon
member, Agaric Design Collective
http://AgaricDesign.com - "Open Source Web Development"
lol - you proved us wrong
Today we had a meetup and we were talking about CCK. Apparently we couldn't do this... now we can ;)... yay!
Uninstall hook
Anyone know of a good example of how these content types can be removed in a module's uninstall hook?
Is this possible outside an
Is this possible outside an install script? When I run the function from my module's functions, the content types don't get created.. but it works fine in an install script.
Reason I want to do it in a module is to create a content-type that represents the fdf fields of an uploaded PDF, so it's done on a regular basis not just on install.
programmatically create CCK fields
This function does it for me:
<?php/**
* Programmatically create CCK fields and types using the content copy module
* @param $type string
* content type to create, defaults to new type, if type exists, only fields will be added
* @param $macro array
* exported array from content types -> export. If file is not specified, macro will be used
* @param $file string
* path to file containing content copy exported macro data structure. no escaping needed.
*/
function base_create_content($type = '<create>', $macro = '', $file = '') {
if(!module_exists("content_copy")){
drupal_set_message('Programmatically creating CCK fields requires the Content Copy module. Exiting.');
return;
}
$values = array();
$values['type_name'] = $type;
//get macro import data, prefer file first
if($file){
if(file_exists($file)){
$values['macro'] = file_get_contents($file);
}else{
drupal_set_message('Unable to read input file for import. Exiting.');
return;
}
}elseif($macro){
$values['macro'] = $macro;
}
//include required files
include_once './'. drupal_get_path('module', 'node') .'/content_types.inc';
include_once('./'. drupal_get_path('module', 'content') .'/content_admin.inc');
//import content by executing content copy import form and passing macro
drupal_execute("content_copy_import_form", $values);
} ?>
I then call it like:
<?php//use absolute path to include file
base_create_content($type = 'my_type', $macro = '', $file = realpath('.') . '/sites/all/modules/my_module/cck/fields.inc');
?>
where
fields.inccontains the exported macro andmy_moduledefines themy_typetype inhook_node_info. You could also make'my_type'into'<create>'and create a new type.hope that helps.
It's a good feature :-)
DT
can any one help me to do this in D6
Hello Experts..
I am developing installer profile in Drupal 6 , i want to import my CCK's from the text file
i have tried this code but its not working for me,
<?phpinclude_once('./'. drupal_get_path('module', 'node') .'/content_types.inc');
include_once('./'. drupal_get_path('module', 'content') .'/includes/content.admin.inc');
$values = array();$values['type_name'] ='<create>';
$values['macro'] = implode("\n", file(dirname(__file__)."/cck_import.txt"));
drupal_execute("content_copy_import_form", $values);
?>
so please help me....