drupal 7 import book set parent/book id - drupal

I need to migrate a book (some sort of manual) from an expressionengine website to drupal 7. I will be using the core book module to put the book in. Since this is a one time import I used a simple custom import script based on this one: http://www.group42.ca/creating_and_updating_nodes_programmatically_in_drupal_7.
I want to be able to set the parent id of each book page but I can't find how to do this. I already tried some intuitive things like
`$node->pid = $parentId;`
and others...
However I'm totally lost where I should look for this information on api.drupal.org . Anyone can point me in the right direction?
I don't know if you also need to set the book this page to explicitly or if setting a parent is enough...
Thanks,
Joris

Check this http://api.drupal.org/api/drupal/modules%21book%21book.module/function/book_node_insert/7
and this
http://api.drupal.org/api/drupal/modules%21book%21book.module/function/book_node_update/7

Sergey Litvinenko pointed to important part of code
<?php
define('DRUPAL_ROOT', dirname(__FILE__).'/../../../..');
chdir(DRUPAL_ROOT);
require_once "./includes/bootstrap.inc";
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
$node = entity_create(
'node',
array(
'type' => 'book_name',
'title' => 'test',
'body' => array(
'und' => array(
array(
'value' => 'body text here',
'format' => 2, // Full html
),
),
),
'field_name' => ...
)
);
$node->uid = 2; // user id for author
node_save($node);
// book:
$node->book['bid'] = 21; // nid of the Top-Level Element or 'new' to create new top Level Book
$node->book['plid'] = 2607; // mlid of the parent book-page from table 'book' in db
_book_update_outline($node);

Related

Get table header to use pager url drupal 7

I have got a unique issue. In my drupal site, I have got a lot of nodes displayed in a teaser and for each node, I am using a table with a pager. The problem is, on initial load of the page, the table sort doesn't work. However, if I use the pager and move to a different page and then back, then the sorting works.
I investigated this issue and found out that on initial load, the url for the header links use the primary link, which is: mysite.com/node?sort=asc&order=Name. After I click on the pager, then the url for the header links, changes to this: mysite.com/mycallbackfunction?_=1348208999187&page=1&nid=13&pager_id=1&sort=desc&order=Name
If you notice, the url obviously are different, which is okay, but the main thing is, the nid is missing in the initial load. I would like the table headers to use the pager url, or some url that I specify, so the nid would appear in both cases as the function returns nothing if there is no nid.
This is the relevant code in mycallbackfunction which displays the table:
//Attach a theme table
$html = theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array(
"class" => array(
"my_table_box"
),
"cellspacing" => '0',
"cellpadding" => '0'
)));
//Pager theme
$html .= theme('pager', array(
'element' => $pager_id,
'parameters' => array(
'nid' => $nid,
'pager_id' => $pager_id),
'quantity' => ceil($count/5)
));
Hope someone might have an insight into this weird problem.
You can pass the custom parameter in theme('pager') function.
<?php
// e.g.
theme('pager', array('parameters' => array('nid' => $nid))
?>);
Let me know if you are looking for something else.
Good Luck!
-Imran

Create content in Drupal based on options in a drop down

I am working on a Drupal site that needs to have a 'careers' page. I have a list of twenty or so jobs, and 30 or so locations where these jobs may be available.
What I am looking to do is make it so, when a job becomes available, all that needs to be done is the user selects the job title and the location where it is available and it will create the posting with the job description and other info I have along with the info for that location.
Another hurtle I am running into is making it so I can have multiple instances... ex. If the same job is available at two or more locations.
I have been trying to wrap my mind around how I am going to make this work and am coming up blank. If anyone has an idea to point me in the right direction, it would be appreciated.
Sounds like a pretty common use case; if it was me I'd approach it like this:
Create a 'Job' content type
Add a new 'Location' Vocabulary
Add a term reference field on the 'Job' content type to the 'Location' vocabulary, with unlimited values (or the maximum no. of locations you want to allow per job).
Create a custom form for your admins, something like:
function MYMODULE_add_job_form($form, &$form_state) {
$form['title'] = array(
'#type' => 'textfield',
'#title' => t('Title'),
'#maxlength' => 255,
'#required' => TRUE
);
// Load the vocabulary (the machine name might be different).
$vocabulary = taxonomy_vocabulary_machine_name_load('location');
// Get the terms
$terms = taxonomy_get_tree($vocabulary->vid);
// Extract the top level terms for the select options
$options = array();
foreach ($terms as $term) {
$options[$term->tid] = $term->name;
}
$form['locations'] = array(
'#type' => 'select',
'#title' => t('Locations'),
'#options' => $options,
'#multiple' => TRUE,
'#required' => TRUE
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Add job')
);
return $form;
}
Create a custom submit handler for the form to add the new node programatically:
function MYMODULE_add_job_form_submit($form, &$form_state) {
$location_tids = array_filter($form_state['values']['locations']);
$node = new stdClass;
$node->type = 'job';
$node->language = LANGUAGE_NONE;
node_object_prepare($node);
$node->title = $form_state['values']['title'];
$node->field_location_term_ref[LANGUAGE_NONE] = array();
foreach ($location_tids as $tid) {
$node->field_location_term_ref[LANGUAGE_NONE][] = array(
'tid' => $tid
);
}
node_save($node);
$form_state['redirect'] = "node/$node->nid";
}
You'll need to add a page callback for that form obviously, and there'll likely be some small changes you'll need to make (names of fields etc), but it should give you a good starting point. You'll also need to load the location taxonomy terms at some point to extract the description info you mentioned...you can use taxonomy_term_load() to do that.

Drupal 7 .10 hook_menu implementation error

I am trying to figure out why hook_menu implementation is not working anymore after upgrade from 7.4 to 7.10 for a custom module Menu links were working properly until update to latest version. after update all custom module links are deleted from table menu_links and menu_router.
After many attempts, I also installed a fresh version for D7.10 and created a simple custom module with one item link only (see code below) for testing purpose only. The link is not implemented once the module is enabled. Tables menu_links and menu_routers are not updated.
I have been looking around many possible errors and solution without success.
Really stacked now. What makes me doubt is that I do not see anybody else having the same issue... Any suggestion? Thank you
function misite_menu() {
$items = array();
$items['a/main'] = array(
'title' => 'main',
'page callback' => 'main',
'description' => t('Main front page'),
'access callback' => TRUE,
);
return $items;
}
function misite_theme() {
return array(
'main' => array
(
'template' => 'main',
'variables' => array('title' => NULL),
),
);
}
function main() {
$path = drupal_get_path('module', 'a');
$title = t('');
$build['mainelement'] = array(
'#theme' => 'main',
'#title' => $title,
);
$output = drupal_render($build);
return $output;
}
From the looks of this line:
$path = drupal_get_path('module', 'a');
Your module is called a.
In Drupal, the convention for hook naming is MODULE_NAME_name_of_hook() (see http://api.drupal.org/api/drupal/includes--module.inc/group/hooks/7).
This is true for both hook_menu() and hook_theme() so in your case if the module is called a your functions should be names a_menu() and a_theme().
If you make changes to any hooks make sure you clear Drupal's cache so the relevant registrys are updated.

How does hook_theme() work?

I am having a hard time understanding what hook_theme() does.
My understanding is that it has something to do with making it possible to override templates.
I was looking at:
$theme_hooks = array(
'poll_vote' => array(
'template' => 'poll-vote',
'render element' => 'form',
),
'poll_choices' => array(
'render element' => 'form',
),
'poll_results' => array(
'template' => 'poll-results',
'variables' => array('raw_title' => NULL, 'results' => NULL, 'votes' => NULL, 'raw_links' => NULL, 'block' => NULL, 'nid' => NULL, 'vote' => NULL),
),
'poll_bar' => array(
'template' => 'poll-bar',
'variables' => array('title' => NULL, 'votes' => NULL, 'total_votes' => NULL, 'vote' => NULL, 'block' => NULL),
),
);
Could you provide an example of how it works?
It provides a place for a module to define its themes, which can then be overridden by any other module/theme. It will also provide the opportunity for any module to use a hook such as mymodule_preprocess_theme_name to change the variables passed to the eventual theme function or template file.
There are basically two ways to initialise a theme function:
theme('poll_results', array('raw_title' => 'title', 'results' => $results, etc...));
and
$build = array(
'#theme' => 'poll_results',
'#raw_title' => 'title',
'#results' => $results,
etc...
); // Note the '#' at the beginning of the argument name, this tells Drupal's `render` function that this is an argument, not a child element that needs to be rendered.
$content = render($build); // Exact equivalent of calling the previous example now that you have a render array.
Please keep in mind, you should avoid calling theme() directly (per the documentation in theme.inc) since it:
Circumvents caching.
Circumvents defaults of types defined in hook_element_info(), including attached assets
Circumvents the pre_render and post_render stages.
Circumvents JavaScript states information.
In Drupal 8, theme() is a private function, _theme(). For more detail, please see www.drupal.org/node/2173655.
When you compare the two of these to the poll_results element in the example you give above you can probably work out what's happening...since PHP is not a strongly typed language Drupal is providing 'named arguments' through either a keyed array passed to the theme function, or as hashed keys in a render array.
As far as 'render element' is concerned, this basically tells the theme system that this theme function will be called using a render array, with one named argument (in this case form). The code would look something like this:
$build = array(
'#theme' => 'poll_choices',
'#form' => $form
);
This will pass whatever's in the $form variable to the theme function as it's sole argument.
Regarding the template key:
'poll_vote' => array(
'template' => 'poll-vote',
'render element' => 'form',
)
defines a theme called poll_vote which uses a template file (hence the template key) with a name of 'poll-vote.tpl.php' (this is by convention). The path to that template file will be found by using the path to the module that implements it (e.g. modules/poll/poll-vote.tpl.php), so it's fine to put template files in sub-folders of the main module folder.
There are two ways to actually return the output for a theme function, by implementing the physical function name (in this case it would be theme_poll_vote) or by using a template file. If the template key is empty Drupal will assume you've implemented a physical function and will try to call it.
Template files are preferable if you have a fair bit of HTML to output for a theme, or you simply don't like writing HTML in strings inside PHP (personally I don't). In either case though, the variables passed when you call the theme (either using theme() or a render array as described above) are themselves passed through to the template file or theme function. So:
function theme_poll_results(&$vars) {
$raw_title = $vars['raw_title'];
$results = $vars['results'];
// etc...
}
If you were using a template file instead for the same method the variables would be available as $raw_title, $results, etc, as Drupal runs extract on the $vars before parsing the template file.
I'm sure there's a lot I've missed out here but if you have any more specific questions ask away and I'll try to help out.
Drupal 6
I was stuck all day with this and now successfully implemented, so sharing my finding here, may it will help understand hook_theme.
There are 3 steps involved:
hook_theme
function YOURMODULENAME_theme() {
return array(
'xxx_xxx' => array(
'template' => 'xxx-xxx', // define xxx-xxx.tpl.php inside module
'arguments' => array('xxx' => null), //define $xxx so it will available in your xxx-xxx.tpl.php
),
);
}
echo/return the theme in your .tpl or any .module
$output = theme('xxx_xxx', $xxx);
Now variable are magically available in you xxx-xxx.tpl.php.
<?php echo $xxx ?>
Note: you can pass $xxx as array,object or anything :)
There is yet another way: (can be found in Bartik theme)
The scenario here is that we have created our own module and want to override the default output for let's say a node with title 'zzz' only.We don't know and don't really care how the default output is generated. All we need is to tell Drupal to use our own custom template file (node--custom--name.tpl.php) to render that specific node.
These are the steps:
Tell Drupal where our template file lives. (Keep in mind that this function will take effect only once and after clearing Drupal's cache):
// Implements hook_theme()
function mymodulename_theme() {
$theme = array();
$theme['node__custom__name'] = array(
'render element' => 'node',
'template' => 'path_from_mymodule_root/node__custom__name',
);
return $theme;
}
Tell Drupal where and when to use it
//Implements hook_preprocess_node()
function mymodulename_preprocess_node($vars) {
if($vars['node']->title == 'zzzz') {
$vars['theme_hook_suggestions'][] = 'node__custom__name';
... your other code ...
}
}
Now Drupal will use our template file for that specific case only, provided that 'node--custom--name.tpl.php' file is in the declared path, otherwise it will keep searching according to the suggestions naming conventions for a fallback template.

Overriding the user registration form in Drupal 6

I want to be able to customise the user registration form in Drupal 6
I have found thousands of tutorials that show me how to override the structure in which you can output the form as a whole, but I want to move form elements around etc and I cant quite seem to see the best way to do this
To expand on Jeremy's answer, you're going to want to study Drupal's Form API and user_register(). In short, you build an associated array; each element in the array corresponds to one form element.
Each form element in the array is its own associated array. They can have a type: textfield, select menu, checkboxes, etc.: see the Form API reference for all the types.
Each form element can also have a weight: this is how you order elements around. Lower numbered weights show up before higher numbered weights in the form.
One of the element types available to you is fieldset: this is what will allow you to group elements together. When you use a fieldset, it creates a section of the form with its own weight values.
So, let's say you have a form with three fields: Name, Company, and E-mail address. The Name should show up first, Company second, E-mail address third. You could specify the form like so:
$form['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#weight' => 1,
);
$form['company'] = array(
'#type' => 'textfield',
'#title' => t('Company'),
'#weight' => 2,
);
$form['email'] = array(
'#type' => 'textfield',
'#title' => t('E-mail address'),
'#weight' => 3,
);
Note the #weight key. If you wanted Company to appear after E-mail address, you'd set $form['company']['#weight'] to something higher than 3.
Now let's say you wanted to group Name and Company into a fieldset called Personal Information. Your form would now look something like this:
$form['personal'] = array(
'#type' => 'fieldset',
'#title' => t('Personal information'),
'#weight' => 1,
);
$form['personal']['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#weight' => 1,
);
$form['personal']['company'] = array(
'#type' => 'textfield',
'#title' => t('Company'),
'#weight' => 2,
);
$form['email'] = array(
'#type' => 'textfield',
'#title' => t('E-mail address'),
'#weight' => 3,
);
Note that Name and Company are now array elements of $form['personal'].
If you want to make Name show up after Company in the fieldset, set its #weight higher than 2. Because the Name is now part of a fieldset that has a lower #weight than the E-mail address field, even if you set $form['personal']['name']['#weight'] to 4, it wouldn't make the Name show up after E-mail address.
So what you're going to attempt to do is use hook_form_alter() to alter the user_register form to change the weights of certain form elements, create your own fieldsets, and move certain form elements into your newly created fieldsets.
There are ways to do this within your theme, but I prefer creating a custom module for this. Create your custom module, and implement hook_form_alter():
function test_form_alter(&$form, $form_state, $form_id) {
if ($form_id === 'user_register') { // Only modify the user registration form
// Before you can get down to business, you need to figure out the
// structure of the user registration form. Use var_dump or kpr to dump
// the $form array.
// Note: if you want to use kpr on the user registration form, give
// anonymous permission to see devel information.
// kpr($form);
// Move Name field to after E-Mail field
$form['name']['#weight'] = 2;
$form['mail']['#weight'] = 1;
// Group Name and E-mail together into a fieldset
$form['personal_info'] = array(
'#type' => 'fieldset',
'#title' => t('Personal information'),
);
$form['personal_info']['name'] = $form['name'];
$form['personal_info']['mail'] = $form['mail'];
// The last block only copied the elements: unset the old ones.
unset($form['name']);
unset($form['mail']);
}
}
In more complex forms, moving things from one fieldset to another might yield unexpected results when submitting the form. This is because $form['name'] isn't the same as $form['group']['name'], which isn't the same as $form['other_group']['name']. You don't have to worry about that on the user_register form for the most part, but check out the handbook page on #tree and #parents for more information about this.
This covers modifying existing fields in the user registration form: if you want to add new fields, I highly recommend using Content Profile. If you want to create custom fields on your own, it's going to get a lot more complex as you're going to have to implement your own validate and submit handlers. Content Profile handles this for you: check out its README to see how to activate it for registration forms.
Using hook_form_alter you can do whatever you want with a form.
For example changing the weight can change the position on the page.
If you try:
MYMODULE_form_user_profile_form_alter(&$form, $form_state) {
// do your processing here
var_dump($form);
}
replacing MYMODULE with the name of your module.
You will see the structure of the form, you can change values in there to alter, labels weights descriptions etc.
In a module, first use hook_theme() , now assuming the name of your module is 'd6_forms' :
function d6_forms_theme() {
return array(
'user_register' => array(
'template' => 'templates/user-register-form',
'arguments' => array('form' => NULL),
),
);
}
This will make the user_register form look for a template, in the specified folder.
So make sure that in your module folder, there is a folder called 'templates', with a file 'user-register-form.tpl.php'.
You notice that in the hook_theme() , the extenstion of the template file ( .tpl.php ) is not supplied. That's normal, you don't need to specify it there.
Do make sure however, that the template has that extension, and that it's not just named 'user-register-form.php' !
In that template file, you have access to the $form variable , so print it there to see what fields are in there.
The devel module is recommened, since it's able to print big Drupal arrays in a fancy way ( using dpm() ).
If you do not have Devel module, or don't want to use it, this also works : <?php print '<pre>' . print_r($form, 1) . '</pre>'; ?>.
To print a field, just use <?php print drupal_render($form[field_name]); ?>, this will print the field and make sure that it works as intended.
So for example, if you want to print the 'name' field in the $form array, just use <?php print drupal_render($form['name']); ?>.
You don't have to print every field ! Just print the fields that you want to move somewhere ( which, with a basic Drupal register form, are about 3 : name, email & submit ).
To print all the remaining fields, just end your template with <?php print drupal_render($form); ?>.
It is important that you don't forget this, since the $form var contains stuff that is absolutely needed for your form to work ( like a token, etc .. ).
So good standard behaviour when templating a form, is to print that piece of code first at the bottom of your template.
This is an entire example of a small register form template, with some basic html :
<?php
// What is in that $form var ? To check, uncomment next line
// print '<pre>' . print_r($form, 1) . '</pre>';
?>
<div style="background-color:#ddd;padding:10px;">
<?php print drupal_render($form['name']); ?>
<?php print drupal_render($form['mail']); ?>
</div>
<div>
<?php print drupal_render($form['submit']); ?>
</div>
<?php print drupal_render($form); ?>
maybe this will help:
http://drupal.org/node/44910
You just need to Enable the Profile Module which would give access to place more fields in sign up form.
Go through this Simple Video tutorial which would be very helpful for beginners in Drupal .
http://planetghost.com/add_more_fields_to_sign_up

Resources