Drupal Blog by graham.taylor http://www.drupaler.co.uk/blog/drupal/7/page en Importing Nodes Using The Batch API http://www.drupaler.co.uk/blog/importing-nodes-using-batch-api/480 <div class="field field-name-upload field-type-file field-label-hidden"><div class="field-items"></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/tags/drupal">drupal</a></div><div class="field-item odd"><a href="/tags/6x">6.x</a></div><div class="field-item even"><a href="/tags/drupal-planet">drupal planet</a></div><div class="field-item odd"><a href="/tags/batch-api">batch api</a></div><div class="field-item even"><a href="/tags/import">import</a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>For a recent custom module I was building I was faced with the challenge of having to create a bunch of nodes from data stored in an XML file. </p> <p>I decided not to use Feeds or Node Import modules for a couple of reasons – </p> <ol><li>The XML structure was fairly custom (it was coming out of one of our internal .net databases – euugh!)</li> <li>I wanted to do the import on a user action - The nodes should only be imported when an an admin user had gone through an administration form first, choosing a couple of config options, then on the form submit, the import from the XML file would be performed.</li> </ol><p>Faced with the task at hand i decided that a good approach would be to use the batch API <a href="http://api.drupal.org/api/group/batch">http://api.drupal.org/api/group/batch</a>. I had also never used the Batch API before, so this was a good chance to learn some more Drupal goodness.</p> <p>After looking at the handbook example here <a href="http://drupal.org/node/180528">http://drupal.org/node/180528</a> I decided to get down to business in my custom module. I went ahead and defined my admin form with the fields i needed as normal and had it display on a URL path via <code>hook_menu()</code>. In the submit function for the form which is where the Batch API magic happens i define the following –</p> <p></p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #FF8000">//define batch API process.<br /></span><span style="color: #0000BB">$batch </span><span style="color: #007700">= array(<br />  </span><span style="color: #DD0000">'operations' </span><span style="color: #007700">=&gt; array(),<br />  </span><span style="color: #DD0000">'finished' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'mymodule_batch_finished'</span><span style="color: #007700">,<br />  </span><span style="color: #DD0000">'title' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Processing nodes for @title'</span><span style="color: #007700">, array(</span><span style="color: #DD0000">'@title' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$feed</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">name</span><span style="color: #007700">)),<br />  </span><span style="color: #DD0000">'init_message' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Starting...'</span><span style="color: #007700">),<br />  </span><span style="color: #DD0000">'progress_message' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Batch @current out of @total'</span><span style="color: #007700">),<br />  </span><span style="color: #DD0000">'error_message' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'An error occurred and some or all of the batch has failed.'</span><span style="color: #007700">),<br />);<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div> <p>This $batch array is required and it tells the batch API what you are planning on do. The only required field is ‘operations’ and we’ll get on to that part in a bit, but just to briefly explain the rest –</p> <ul><li> 'finished' – this is the name of a callback function to call when the batch processing is finished.</li> <li>'title', 'init_message' and 'progress message' will all get displayed to the user on the batch processing screen to give them an indication of what is happening and how far we are through the batch import process. A full list of all available options are here - <a href="http://api.drupal.org/api/function/batch_set/6">http://api.drupal.org/api/function/batch_set/6</a> </li> </ul><p>Now onto 'operations' - the most important part. This is basically a function (or an array of functions to call when performing the batch processing). If you have one function, it will be called recursively until the batch processing is finished, otherwise the batch API will call function 1, then function 2, etc...</p> <p>For my example i decided that i was only going to need 1 function which would be called recursively until all my nodes were imported from the XML file so my 'operations' part of the array looked like this – </p> <p></p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$batch</span><span style="color: #007700">[</span><span style="color: #DD0000">'operations'</span><span style="color: #007700">][] = array(</span><span style="color: #DD0000">'_mymodule_save_nodes'</span><span style="color: #007700">, array(</span><span style="color: #0000BB">$items</span><span style="color: #007700">));<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div> <p>Now our $batch array is setup, we're ready to start batch processing. To invoke the batch API processing you simply need call <code>batch_set()</code> as follows –</p> <p></p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />batch_set</span><span style="color: #007700">(</span><span style="color: #0000BB">$batch</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div> <p>The batch api will kick in and call the function(s) in your 'operations' part of the array above. I'll simplify it here for example purposes but for my import nodes job the start of that function looks like so – </p> <p></p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">mymodule_save_nodes</span><span style="color: #007700">(</span><span style="color: #0000BB">$items </span><span style="color: #007700">= array(), &amp;</span><span style="color: #0000BB">$context</span><span style="color: #007700">) {      <br />  </span><span style="color: #0000BB">$limit </span><span style="color: #007700">= </span><span style="color: #0000BB">variable_get</span><span style="color: #007700">(</span><span style="color: #DD0000">'mymodule_nodes_to_process'</span><span style="color: #007700">, </span><span style="color: #0000BB">50</span><span style="color: #007700">);  <br /><br />  if (!isset(</span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'progress'</span><span style="color: #007700">])) {<br />    </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'progress'</span><span style="color: #007700">] = </span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />    </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'max'</span><span style="color: #007700">] = </span><span style="color: #0000BB">count</span><span style="color: #007700">(</span><span style="color: #0000BB">$items</span><span style="color: #007700">);<br />  }<br />    <br />  if(!isset(</span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'items'</span><span style="color: #007700">])) {<br />    </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'items'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$items</span><span style="color: #007700">;<br />  }<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div> <p>Notice the use of the $context argument. This is something that the batch API adds, and you will have to add it as an extra argument to any functions defined in the 'operations' part of the $batch array above. As the $context array is passed in by reference to the function it gets updated everytime this function gets called in the batch processing. </p> <p>This makes it ideal for storing some data about the batch process. </p> <p>First time round, I'm setting <code>$context['sandbox']['progress'] = 0</code> (i.e. We’re at the start of the batch) and the max number of items ($context['sandbox']['max']) we are processing is the total number of nodes to import, which are stored in the $items array passed into the function.</p> <p>I’m also setting the array of all the nodes ($items) to the 'sandbox' as we’ll be using the 'sandbox' $items during the processing rather than the $items array passed into the function. </p> <p>The reason for using the <code>$context['sandbox']['items']</code> instead of $items is because every time we come back into the function to process the next batch, $items will always carry the full number of nodes every time, whereas because $context gets continually updated throughout the process, we can reduce it (remove a node) every time we import one, and because it's stored in $context, the next time the function gets called, we will know how many nodes we have left to process.</p> <p>Next up we need to do the actual processing, which means creating a new node and saving it as follows – </p> <p></p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />  </span><span style="color: #FF8000">//begin saving xml feed item as node.<br />  </span><span style="color: #0000BB">$counter </span><span style="color: #007700">= </span><span style="color: #0000BB">0</span><span style="color: #007700">;    <br />  if(!empty(</span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'items'</span><span style="color: #007700">])) {<br />    if (</span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'progress'</span><span style="color: #007700">] != </span><span style="color: #0000BB">0</span><span style="color: #007700">){<br />      </span><span style="color: #0000BB">array_splice</span><span style="color: #007700">(</span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'items'</span><span style="color: #007700">], </span><span style="color: #0000BB">0</span><span style="color: #007700">, </span><span style="color: #0000BB">$limit</span><span style="color: #007700">);<br />    }<br />    foreach(</span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'items'</span><span style="color: #007700">] as </span><span style="color: #0000BB">$item_id </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$item</span><span style="color: #007700">) {<br />      if (</span><span style="color: #0000BB">$counter </span><span style="color: #007700">!= </span><span style="color: #0000BB">$limit</span><span style="color: #007700">) {<br />        </span><span style="color: #FF8000">//build the node object.<br />        </span><span style="color: #0000BB">$node </span><span style="color: #007700">= new </span><span style="color: #0000BB">StdClass</span><span style="color: #007700">();<br />        </span><span style="color: #0000BB">$node</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">uid </span><span style="color: #007700">= </span><span style="color: #0000BB">1</span><span style="color: #007700">;<br />        </span><span style="color: #0000BB">$node</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">type </span><span style="color: #007700">= </span><span style="color: #DD0000">'my_node_type'</span><span style="color: #007700">;<br />        </span><span style="color: #0000BB">$node</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">status </span><span style="color: #007700">= </span><span style="color: #0000BB">1</span><span style="color: #007700">;<br />        </span><span style="color: #0000BB">$node</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">title </span><span style="color: #007700">= </span><span style="color: #0000BB">$item</span><span style="color: #007700">[</span><span style="color: #DD0000">'title_field_from_xml'</span><span style="color: #007700">];<br />    </span><span style="color: #0000BB">$node</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">body </span><span style="color: #007700">= </span><span style="color: #0000BB">$item</span><span style="color: #007700">[</span><span style="color: #DD0000">'body_field_from_xml'</span><span style="color: #007700">];        <br />    <br />    </span><span style="color: #FF8000">//save the node<br />        </span><span style="color: #0000BB">node_save</span><span style="color: #007700">(</span><span style="color: #0000BB">$node</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div> <p>As you can see above, theres an internal counter which will run over the array and import any nodes up to the limit you have set per batch (in this case 50). So if we had a total of 250 nodes to import, and we’re on the first run, the above code would import 50 nodes, then the batch API would call the function again. </p> <p>Still inside the for loop, while we’re running through our first 50 nodes you need to update the progress (let the user see whats happening on the screen) – </p> <p></p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />  $counter</span><span style="color: #007700">++;<br />  </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'progress'</span><span style="color: #007700">]++;<br />  </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'message'</span><span style="color: #007700">] = </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Now processing node %node of %count'</span><span style="color: #007700">, array(</span><span style="color: #DD0000">'%node' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'progress'</span><span style="color: #007700">], </span><span style="color: #DD0000">'%count' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'max'</span><span style="color: #007700">]));<br />  </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'results'</span><span style="color: #007700">][</span><span style="color: #DD0000">'nodes'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'progress'</span><span style="color: #007700">];<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div> <p>Finally at the end of the function double check whether we’re at the end of our processing, or if we need to continue (in this example we’ve only done 50 out of 250, so we continue). </p> <p></p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">if (</span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'progress'</span><span style="color: #007700">] != </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'max'</span><span style="color: #007700">]) {<br />  </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'finished'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'progress'</span><span style="color: #007700">] / </span><span style="color: #0000BB">$context</span><span style="color: #007700">[</span><span style="color: #DD0000">'sandbox'</span><span style="color: #007700">][</span><span style="color: #DD0000">'max'</span><span style="color: #007700">];<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div> <p>To complete the batch process of 250 nodes, this function will get called another 4 times (processing 50 nodes x 4 = 200).</p> <p>On the final turn the batch has finished processing so the batch API calls the callback function defined in the ‘finished’ part of the $batch array. Mine looks something like this – </p> <p></p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #FF8000">/**<br />* Batch 'finished' callback<br />*/<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">mymodule_batch_finished</span><span style="color: #007700">(</span><span style="color: #0000BB">$success</span><span style="color: #007700">, </span><span style="color: #0000BB">$results</span><span style="color: #007700">, </span><span style="color: #0000BB">$operations</span><span style="color: #007700">) {<br />  if (</span><span style="color: #0000BB">$success</span><span style="color: #007700">) {<br />    </span><span style="color: #FF8000">// Here we do something meaningful with the results.<br />    </span><span style="color: #0000BB">$message </span><span style="color: #007700">= </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'%nodes nodes processed'</span><span style="color: #007700">, array(</span><span style="color: #DD0000">'%nodes' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$results</span><span style="color: #007700">[</span><span style="color: #DD0000">'nodes'</span><span style="color: #007700">]));<br />    </span><span style="color: #0000BB">watchdog</span><span style="color: #007700">(</span><span style="color: #DD0000">'mymodule'</span><span style="color: #007700">, </span><span style="color: #DD0000">'%nodes nodes processed'</span><span style="color: #007700">, array(</span><span style="color: #DD0000">'%nodes' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$results</span><span style="color: #007700">[</span><span style="color: #DD0000">'nodes'</span><span style="color: #007700">]), </span><span style="color: #0000BB">WATCHDOG_NOTICE</span><span style="color: #007700">);<br />  }<br />  else {<br />    </span><span style="color: #FF8000">// An error occurred.<br />    // $operations contains the operations that remained unprocessed.<br />    </span><span style="color: #0000BB">$error_operation </span><span style="color: #007700">= </span><span style="color: #0000BB">reset</span><span style="color: #007700">(</span><span style="color: #0000BB">$operations</span><span style="color: #007700">);<br />    </span><span style="color: #0000BB">$message </span><span style="color: #007700">= </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'An error occurred while processing %error_operation with arguments: @arguments'</span><span style="color: #007700">, array(</span><span style="color: #DD0000">'%error_operation' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$error_operation</span><span style="color: #007700">[</span><span style="color: #0000BB">0</span><span style="color: #007700">], </span><span style="color: #DD0000">'@arguments' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$error_operation</span><span style="color: #007700">[</span><span style="color: #0000BB">1</span><span style="color: #007700">], </span><span style="color: #0000BB">TRUE</span><span style="color: #007700">)));<br />    </span><span style="color: #0000BB">watchdog</span><span style="color: #007700">(</span><span style="color: #DD0000">'mymodule'</span><span style="color: #007700">, </span><span style="color: #DD0000">'An error occurred while processing %error_operation with arguments: @arguments'</span><span style="color: #007700">, array(</span><span style="color: #DD0000">'%error_operation' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$error_operation</span><span style="color: #007700">[</span><span style="color: #0000BB">0</span><span style="color: #007700">], </span><span style="color: #DD0000">'@arguments' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$error_operation</span><span style="color: #007700">[</span><span style="color: #0000BB">1</span><span style="color: #007700">], </span><span style="color: #0000BB">TRUE</span><span style="color: #007700">)), </span><span style="color: #0000BB">WATCHDOG_ERROR</span><span style="color: #007700">);<br />  }<br />  </span><span style="color: #0000BB">drupal_set_message</span><span style="color: #007700">(</span><span style="color: #0000BB">$message</span><span style="color: #007700">);<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div> <p>That’s it we’re done. Now we have a form which when submitted will import nodes retrieved from an XML file using Drupal's Batch API. Yay!</p> </div></div></div> Thu, 28 Jan 2010 11:09:37 +0000 graham.taylor 480 at http://www.drupaler.co.uk http://www.drupaler.co.uk/blog/importing-nodes-using-batch-api/480#comments Calling A Custom Or Panel Page From Code (Panels 3.x) http://www.drupaler.co.uk/blog/calling-custom-or-panel-page-code-panels-3x/432 <div class="field field-name-upload field-type-file field-label-hidden"><div class="field-items"></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/tags/drupal">drupal</a></div><div class="field-item odd"><a href="/tags/6x">6.x</a></div><div class="field-item even"><a href="/tags/panels">panels</a></div><div class="field-item odd"><a href="/tags/drupal-planet">drupal planet</a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>First of all, I’d like to say hello fellow drupalers! This is my first post here, (and also my first ever blog post!) since Greg opened up drupaler.co.uk as a collaborative blog for Drupal developers. </p> <p>I’ve been playing around a bit with Panels 3 since the early alpha releases. In the initial stages of my explorations I encountered some frustrations, as a lot of the code was still in heavy development, but I’m pleased to report that the latest beta (beta2) seems much more stable, and I havent had many issues with it so far (fingers crossed). </p> <p>It came to a point in the development of our site where we were happy with the layout and content in our panels and we wanted to move them out of the database and into code using the export feature - A similar feature which is also available in the views module. This post is going to cover exporting a custom panel page and a panel page and calling them from code. The methods for the two are slightly different so I’ll explain both. </p> <p>Initially I spent a fair bit of time digging around drupal.org , but couldnt find much in the way of examples on how to go about calling panels from code. I did however stumble across this great tutorial from Michelle which was an excellent starting point, and I’ll use part of that tutorial in this example.</p> <p>As a first step, prepare a module ready to accept the panel export code. To do this, First of all follow Step 1 from Michelle’s tutorial - create a new module, and inside your module’s directory create a file called MODULE_NAME.delegator_default.inc.</p> <p>Next, We’ll also need Step 2 from Michelles tutorial – Go ahead and paste the following code into your .inc file –</p> <p></p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #FF8000">/**<br />* Implementation of hook_default_delegator_handlers()<br />*/<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">MODULE_NAME_default_delegator_handlers</span><span style="color: #007700">() {<br /></span><span style="color: #0000BB">$handlers </span><span style="color: #007700">= array();<br /></span><span style="color: #FF8000">// BEGIN HANDLER EXPORT ******************************************************/<br />  // PASTE YOUR HANDLER EXPORT IN HERE<br />// END HANDLER EXPORT ******************************************************/<br />  <br /></span><span style="color: #0000BB">$handlers</span><span style="color: #007700">[</span><span style="color: #0000BB">$handler</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">name</span><span style="color: #007700">] = </span><span style="color: #0000BB">$handler</span><span style="color: #007700">; <br />return </span><span style="color: #0000BB">$handlers</span><span style="color: #007700">;<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div><br /> We’re going to skip Step 3 of Michelle’s tutorial for now and go straight to step 4. Next add the following code to your .module file <p></p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">MODULE_NAME_ctools_plugin_api</span><span style="color: #007700">(</span><span style="color: #0000BB">$module</span><span style="color: #007700">, </span><span style="color: #0000BB">$api</span><span style="color: #007700">) {<br />  if (</span><span style="color: #0000BB">$module </span><span style="color: #007700">== </span><span style="color: #DD0000">'delegator' </span><span style="color: #007700">&amp;&amp; </span><span style="color: #0000BB">$api </span><span style="color: #007700">== </span><span style="color: #DD0000">'delegator_default'</span><span style="color: #007700">) {<br />    </span><span style="color: #0000BB">$module_path </span><span style="color: #007700">= </span><span style="color: #0000BB">drupal_get_path</span><span style="color: #007700">(</span><span style="color: #DD0000">'module'</span><span style="color: #007700">, </span><span style="color: #DD0000">'MODULE_NAME'</span><span style="color: #007700">);<br />    return array(</span><span style="color: #DD0000">'version' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">1</span><span style="color: #007700">, </span><span style="color: #DD0000">'path' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$module_path </span><span style="color: #007700">. </span><span style="color: #DD0000">'/path/to/include/file'</span><span style="color: #007700">);<br />  }<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div> <p>The next step is to implement hook_default_delegator_pages() in your .inc file. Paste the following code:</p> <p></p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php <br /></span><span style="color: #FF8000">/**<br /> * Implementation of hook_default_delegator_pages();<br /> */<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">MODULE_NAME_default_delegator_pages</span><span style="color: #007700">(){<br />  </span><span style="color: #0000BB">$pages </span><span style="color: #007700">= array();<br />  </span><span style="color: #FF8000">//include pages<br />  // BEGIN HANDLER EXPORT ******************************************************/<br />  // PASTE YOUR HANDLER EXPORT IN HERE<br />// END HANDLER EXPORT ******************************************************/<br /><br /><br />  </span><span style="color: #007700">return </span><span style="color: #0000BB">$pages</span><span style="color: #007700">;<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div><br /> Our module now has the base ready to handle the exported panel code. <p><strong>Panel Page Export</strong><br /> On the Panel Page you wish to export click Operations and then Export. Copy the code from the following screen and paste it into MODULE_NAME_default_delegator_pages(). That’s it for normal panel pages! If you clear caches and refresh the panels admin page (admin/build/pages), if everything worked you should see the ‘Storage’ change from ‘Normal’ to Overridden’.</p> <p><strong>Custom Page Export</strong><br /> Custom pages are slightly different in that they also require you to export each task handler for the page as well as the page code. This is because a custom page may have multiple task handlers, whereas a normal panel page only has one.</p> <p>To export a custom page you should follow the same steps as above (Panel Page Export) to export the page code and paste it into MODULE_NAME_default_delegator_pages().</p> <p>To export the handler code, on the custom page you wish to export, click Operations then Task Handlers. This should take you to a page which shows a list of handlers for the current panel. </p> <p><strong>Note*</strong> - if you only initially specified the panel to have a single handler, you might be displayed with a screen that gives you 2 options – allow multiple handlers, or create a singler handler. In order to export the handler code, you must choose allow multiple and select finish.</p> <p>If you had to choose allow multiple, go back in to the task handlers for your panel. Now you should see the list of handlers. </p> <p>Now export each handler. Copy the code and paste it into MODULE_NAME_default_delegator_handlers() , and that’s you done! Again, on admin/build/pages the ‘Storage’ should change from Normal to Overridden. In task handlers for the panel, each task handler ‘type’ should also change from Normal to Overridden.</p> <p>As a final step, if you want to delete the copies from the database for each page / handler click on Operations then Revert, and delete the copy in the database. This will mean that your panel page is now being called from Code. If you did this the ‘Storage’ and ‘type’ fields on the pages should change to Default.</p> </div></div></div> Fri, 03 Jul 2009 13:22:21 +0000 graham.taylor 432 at http://www.drupaler.co.uk http://www.drupaler.co.uk/blog/calling-custom-or-panel-page-code-panels-3x/432#comments