Berichten

Drupal Entities – Part 3 – Programming Hello Drupal Entity

Source:  http://www.istos.it/blog/drupal-entities/drupal-entities-part-3-programming-hello-drupal-entity

We had a look at the why, what, where and when of entities in a couple of past blogs. We now look at the how, by setting up the bare minimum to view and create entities and attach fields to them.

Posted on 23-Dec-2010

After way too long a time I finally get back to the series of posts (check out Part I and Part II) on Entities to present the third in the series – how to actually create an entity. Part of the challenge of writing a post like this is that there are so many different aspects to entities that it is really hard to distill things into a single post that gives you something useful at the end. What we will do will be the equivalent of a “Hello World” for entities. It is not very useful in and of itself but it does get you started and introduces the main concepts.

We are going to create a single entity that has just two fields, an id and some content. For the sake of reference I will call it the PostIt entity. Imagine you wanted to create a simple PostIt system or shoutbox for your Drupal site – this would be part of the way of getting there.

First thing – we need to describe a table to Drupal which will be our “base” table – very much like the Node table, this will be where things start. This description will go into postit.install in a module directory called postit

function postit_schema() {
  $schema['postit'] = array (
    'description' => 'The main store for our entity',
    'fields' => array(
      'pid' => array(
        'description' => 'Primary key for our table of postit notes',
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'note' => array(
        'description' => 'The actual note',
        'type' => 'varchar',
        'length' => '255',
        'not null' => TRUE
      ),
    ),
    'primary key' => array('pid'),
  );

  return $schema;
}

All we are doing here is telling Drupal to create a table with two fields, one of which is the primary key. The table will be created as soon as the module is enabled.

Ok – so we have a starting point. Next up, we need to go tell Drupal that this is the base table of our entity and set up a few things about how it should treat the entity. There is, naturally, a hook for this – aptly called hook_entity_info() and, as with most things Drupal, you construct a huge array with all the configuration information.

function postit_entity_info(){
  $postit_info['postit'] = array(
    'label' => t('PostIt Note'),
    'controller class' => 'PostItController',
    'base table' => 'postit',
    'uri callback' => 'postit_uri',
    'fieldable' => TRUE,
    'entity keys' => array(
      'id' => 'pid',
    ),
    'static cache' => TRUE,
    'bundles' => array(
      'postit'=> array(
        'label' => 'PostIt',
        'admin' => array(
          'path' => 'admin/structure/postit/manage',
          'access arguments' => array('administer postits'),
        ),
      ),
    ),
    'view modes' => array(
      'full' => array(
        'label' => t('Full PostIt'),
        'custom settings' =>  FALSE,
      ),
    )
  );

  return $postit_info;
}

Ok – so let us step through this. We provide a label to have a human readable reference to our entity and define a class, the PostItController class, that will be responsible for our postit. This class will actually subclass the DrupalDefaultEntityController class (which lives in entity.inc) and worries about such things such as caching, querying, attaching to fields, etc.

You don’t strictly need to define this class (it will automatically use the default one), but if you did want to override some of the existing functionality this would be the way to do it. The class can go in a separate file called postit.controller.inc with just this code for the time being.

class PostItController extends DrupalDefaultEntityController{}

We then let Drupal know what the base table will be for our entity and what function should be called to create URIs for this entity. The Entity API will use this function when trying to figure out URIs for entities.

The next one is the biggie, our entity is fieldable which means that the Field API can now hook into our entity and we can easily extend it with fields to our hearts content. We then define what the main identifier for our entity is and we turn on caching.

We now move on to the bundle part, which is really where we practically stitch together the FieldAPI with our entity. A way to think of bundles is as a type of entity (in this case a postit entity) “bundled” together with fields to forms a particular subtype. For example, different types of nodes are different bundles. The Entity API in Drupal can support multiple bundles but in our case we are just defining one and providing a URL where one can go to manage this specific bundle.

Finally, we define view modes – in this case just one.

And that is pretty much it. It could be a bit simpler, but it can also get much more complicated. As I mentioned this is enough for “hello entity!”.

Let us now move on to provide the bare minimum functionality to be able to enable our entity module, view an entity and attach fields to it.

First up, taking care of the URI:

function postit_uri($postit){
  return array(
    'path' => 'postit/' . $postit->id,
  );
}

Then a couple of functions that will load our entities for us:

function postit_load($pid = NULL, $reset = FALSE){
  $pids = (isset ($pid) ? array($pid) : array());
  $postit = postit_load_multiple($pids, $reset);
  return $postit ? reset ($postit) : FALSE;
}

function postit_load_multiple($pids = array(), $conditions = array(), $reset = FALSE){
  return entity_load('postit', $pids, $conditions, $reset);
}

The first function simply takes care of whether it is going to load just one or multiple entities and the second function actually goes ahead and loads the entities calling entity_load().

The code below setups the various pages we will use to view our entities. We have a manage page that just provides an access point and link for the Field API to attach itself to our entity via the UI. If you visit “admin/structure/postit/magage” you should see tabs for adding and editing fields.

The other url is where we will view our entity.

function postit_menu(){
  $items['admin/structure/postit/manage'] = array(
    'title' => 'PostIt Admin',
    'description' => 'Manage PostIT structure',
    'page callback' => 'postit_info',
    'access arguments' => array('administer postits'),
  );
  $items['postit/%postit'] = array(
    'title callback' => 'postit_page_title',
    'title arguments' => array(1),
    'page callback' => 'postit_page_view',
    'page arguments' => array(1),
    'access arguments' => array('view postits'),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

function postit_permission(){
    return array(
    'administer postits' =>  array(
      'title' => t('Administer postits'),
      'restrict access' => TRUE,
    ),
    'view postsits' => array(
      'title' => t('View PostIts'),
    )
  );
}

function postit_info() {
  return ('Welcome to the administration page for your Postits!');
}

function postit_page_title($postit){
  return $postit->pid;
}

function postit_page_view($postit, $view_mode = 'full'){
  $postit->content = array();

  // Build fields content.
  field_attach_prepare_view('postit', array($postit->pid => $postit), $view_mode);
  entity_prepare_view('postit', array($postit->pid => $postit));
  $postit->content += field_attach_view('postit', $postit, $view_mode);

  return $postit->content;
}

function postit_field_extra_fields() {
  $return = array();
  $return['postit']['postit'] = array(
    'form' => array(
      'note' => array(
        'label' => t('Note'),
        'description' => t('PostIt Note'),
      ),
    ),
  );

  return $return;
}

Now, with all these in place you are able to attach fields to the entity but there is no UI to actually create an entity.

If you visit admin/structure/postit/manage you should be able to see tabs that enable you add and remove fields to your entity.

We will now quickly create a basic UI to add entities so we have just enough to prove everything works together:

We will add another path to hook_menu:

  $items['postit/add'] = array(
    'title' => 'Add PostIT!',
    'page callback' => 'postit_add',
    'access arguments' => array('create postit'),
  );

and create the function that is called back.

function postit_add() {
  $postit = (object) array (
    'pid' => '',
    'type' => 'postit',
    'note' => '',
  );

  return drupal_get_form('postit_add_form', $postit);
}

function postit_add_form($form, &$form_state, $postit) {
  $form['note'] = array(
    '#type' => 'textfield',
    '#title' => t('Note'),
    '#required' => TRUE,
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );

  field_attach_form('postit', $postit, $form, $form_state);

  return $form;
}

What we are doing here is creating a form with the note field and then via field_attach_form we are adding any other widgets that are coming via the Field API. The form submission goes through the usual validation steps:

function postit_add_form_validate($form, &$form_state) {
  $postit_submisttion = (object) $form_state['values'];
  field_attach_form_validate('postit', $postit_submisttion, $form, $form_state);
}

function postit_add_form_submit($form, &$form_state) {
  $postit_submission = (object) $form_state['values'];
  field_attach_submit('postit', $postit_submission, $form, $form_state);
  $postit = postit_save($postit_submission);
  $form_state['redirect'] = "postit/$postit->pid";
}

The pattern here is pretty much “Take care of your own fields and then let the Field API do its own thing for the attached fields.

The one function that is missing is the postit_save function which is below:

function postit_save(&$postit) {
  return entity_get_controller('postit')->save($postit);
}

For illustration sake (given that we could do the job without the controller), we delegate the work to our entity controller that has one more function added to it:

  public function save($postit) {
    drupal_write_record('postit', $postit);
    field_attach_insert('postit', $postit);
    module_invoke_all('entity_insert', 'postit', $postit);
    return $postit;
  }

Similar pattern as before, we first save to our own entity table, and then save all the associated fields. Finally, give all the other modules a shout via a hook that an entity has been inserted and we are done.

Visit postit/add you will be able to create the postit and if you’ve attached any fields to it you will see their widgets there as well. Check the db and you will see your postit table getting updated.

There is still a bit to do, such as deleting and editing entities – offering a page to view a list of all entities, etc – but as I said this is a “Hello Entity!” example. Check out the excellent work that is being done with the Entity project for examples of a full blown CRUD controller for entities.

As you can imagine the possibilities with entities are endless and this has only touched the surface. Hopefully, examples will soon start popping up in the wild and patterns and best practices will start emerging on how to create and handle entities.

 

Drupal Entities – Part 2 – The what, where and when of Entities

Source:  http://www.istos.it/blog/drupal-entities/drupal-entities-part-2-what-where-and-when-entities

The second post in a series that explores Drupal entities. While in the first post we look at how we got to where we are in this post we try to give some more depth to the definition of what is an entity and discuss where and when they should be used.

Posted on 11-Aug-2010

In a previous post I had a look at how Drupal moved from nodes as its main unit of abstraction to entities. That trip through Drupal history tried to explain why entities exists but only partly touched on exactly what they are.

Here we are going to answer in some more detail what they are, as well as, where and when to use them. I am not going to get too technical (i.e. no code) – the aim is to allow everyone to figure out what entities are and what they can do. In a follow-up, and final in the series, post we are going to get really technical (i.e. mostly code) and look at the how.

What are Drupal Entities

The word entity can take on many meanings in computer science. The most commonly referred to meaning, and the one that seems to popup very often when first mentioning Drupal entities, comes from the database world. In DB-speak entities are the “things” we wish to represent in our application domain. Typically, this is explained in the flow of explaining Entity-Relationship diagrams – the bane of many a first year computer science undergrad.

Drupal entities are, in a loose way, similar. Entities are the things, the data, the information, the “stuff”, that we want to deal with in our Drupal application. The similarities, however, pretty much end there. When you think of Drupal entities you really should think of them exclusively within the Drupal way of doing things. As with nodes, entities in Drupal take on a new meaning and life and become a term native to and truly definable only within the context of Drupal.

So what is the “stuff” that we want to represent in a Drupal application? Well we have nodes, taxonomy terms, users, comments. These are our main building blocks and they are all entities in Drupal 7.

Now, that is fine – but it’s the same stuff we had in Drupal 6 right? So what’s the big bruhaha all about? Just that we are now calling all these things entities?

Well, not quite. Entities are all dealt with in the same way in Drupal 7 while in Drupal 6 they each did their own thing (or repeated similar things in different ways). Entities have a common programmatic interface through which (most) of their behaviour is defined.

So the first thing Drupal entities are is means to streamline how we deal with the basic Drupal “stuff” of nodes, comments, terms and users.

Now comes the really interesting part to people that don’t worry so much about how the core of Drupal does things.

1. You can define your own entities that plug into the whole Drupal way of doing stuff.

2. Any entity can have fields attached to it.

Remember CCK? How great that is for Drupal 6? How you can turn nodes into anything you want just by adding fields to them? Well In Drupal 7 you have all that goodness for all entities – which means nodes, users, terms and comments. Also, and here is the beauty of it, you also get this functionality for any entities you define yourself. This makes it a whole new ballgame.

You can now actually create data structures specific to your application domain with their own database table (or any other storage mechanism really) plus a standardised way to add fields to them. No need to turn nodes into something they are not.

A few examples:

  • The Drupal 7 Commerce solution uses Entities to describe a line item in an invoice. As ChX explained to me in IRC they found this a convenient way to group all the fields related to a line item without having to re-purpose nodes for the job but also without having to introduce a completely custom way to deal with data.
  • The team over at Examiner.com use entities to store user profile revisioning information (functionality they are hoping to release soon).
  • The Drupal 7 Rules module uses entities to store Rules configurations.

So Drupal entities are:

  • A way to describe to the rest of your Drupal application something that is relevant and unique to your domain, that can have its own database table, but at the same time…
  • …use Drupal APIs to add fields to it and interact with it in a variety of ways, which means…
  • …that you get lots of stuff for free such as Views integration or the ability to use MongoDB for storage.

But how do you make the choice of when to create a new entity, whether you just attach fields to it or keep all the data in its own table, or simply do it the old way and re-purpose nodes?

When and why should one use entities

Entities are still a pretty new concept so best practice will still take some defining. However, ChX and DamZ gave some good advice on IRC.

Essentially, if you are faced with having to put information into a custom table consider whether defining an entity and attaching fields to it through the Drupal APIs might be worthwhile. And let me give you a hint – the answer is: yes, it probably makes more sense to use entities. There is practically no drawback to exposing a custom table as an entity.

While in Drupal 6 re-purposing nodes to do your bidding is very useful, there is something inherently inelegant about it because after all nodes are really designed to do one very specific thing – store articles. In Drupal 7, however, you can create your own lean entity and attach to it just the fields you need. You don’t need to carry along node functionality (e.g. author, publish date, etc) that you don’t really need.

According to both ChX and DamZ the base table representing your entity in the database should generally be kept simple and you can attach fields to entities to define your data structure.

The only reasons to consider adding data attributes directly to the entity and not through the Drupal Field API is if the data is quite specific and is not well served by any available field type or if performance-wise it makes more sense to query only the base table (for example if you plan to frequently query it) to get information out rather than having to query both the base table and the table where the field information is saved.

Keep in mind, however, that a major driving force behind the architecture of entities and fields is scalability – so if you arereally concerned about performance you probably still want to use fields where you can decide exactly how they are stored (e.g. in a MongoDB database rather than MySQL).

When not to use entities? Well, there isn’t any user interface for defining and dealing with entities (yet). So right now if you want a quick way to get something done without writing any code re-purposing nodes it still the best way to do it. But, if you are willing to write a bit of code (and as we will see in the next post it really is not complicated) you can have a more elegant web app at your disposal that can still call itself a fully-qualified member of the Drupal way of doing things.

Not all roses…

As I mentioned before entities are still pretty new. And the overhaul to get them into Drupal 7 was huge – so there are still a few things missing.

While you have a unified interface to define and load entities there isn’t (in core) a means to do all entity operations (Create, Read, Update, Delete) but work is taking place in the contrib module space to get there.

Another issue is how to define relationships between entities. Nodes, comments, taxonomy terms and users are all related between them. But these relationships are hard-coded. Again, there is work underway in the contrib space to explore how to deal with this issue as well.

…but it definitely exciting!

While things aren’t perfect yet they are really on a very good path to Drupal nirvana. As ChX mentioned to me on IRC it is going to take a couple of years before we figure out all the things that we can do with Drupal 7.

Which sounds just about right – as hopefully Drupal 8 will be coming out then and will be even more awesome!

Drupal Entities – Part 1 – Moving beyond nodes

One of the biggest changes at the architecture level of Drupal 7 is the introduction of entities as an abstraction for content. In these series of blog posts I take a look at how Entities came to be, what are they exactly and how they can be used in modules. This first post goes looks at how entities landed in Drupal 7.

Posted on 08-Aug-2010

Drupal 7 introduces a lot of big changes at all levels. Amongst these, the use of entities as the primary abstraction for content represents one of the biggest shifts in the underlying architecture.

A telling sign of how deeply embedded entities are is that they don’t even get a mention in the changelog for Drupal 7 – they are not a user-facing tool or abstraction in any way – purely an architectural tool to deal with content.

I originally intended to write one single post as a means to help me clear my understanding of entities and hopefully help others as well. However, one post is just not enough! So in what has now turned into a series of posts I am first going to do some historical digging to see how entities came about, then explain what entities exactly are and finally try to figure out how and where entities can be used in coding to build better modules.

So first let us try and figure out how things got to where they are now.

In the beginning there were nodes

Up to Drupal 6 nodes, as the main unit of content, could be considered Drupal’s primary abstraction, with every other piece building or relating to nodes.

A lot has already been said about what a powerful tool that is. You add some functionality for nodes and suddenly any content on your site (as long as it is a node) gains that ability. From versioning, voting, translation, presentation fanciness as long as you wrote your extension to work with nodes you were sure it would work in all sorts of situations.

With Flexinode and later on the Content Construction Kit, nodes gained the ability to have fields added to them. This pretty much took Drupal to a whole new level of flexibility – so much so the ability to add fields to nodes became one of the main goals of Drupal 7.

Let us make everything a node!

At the same time, the Drupal 6 contributed module space provided proof of how people needed to add fields to more things than just nodes. You have modules that turn user profiles to nodes – for the explicit purpose of then being able to add fields to user profiles via CCK. Modules that turn comments into nodes, again just so you can add fields to them. Even modules that link taxonomy to nodes.

In fact, the “everything as a node” meme has a long history. A google search reveals that Robert Douglass as early as May 2006 suggested that everything in Drupal could be made a node and outlined the potential benefits of that.

This idea pops up in various other occasions and really I guess it can be considered the progenitor of entities.

Let’s introduce a new concept

So, one the one hand you have a lot of people arguing about why it is great to have everything as a node so that CCK can be used to add fields to things. One the other hand, you have a huge effort under way to add CCK to the core of Drupal 7.

In a great demonstration of how the Drupal contrib space can act as a laboratory of what should happen in new versions of Drupal, and after some pretty amazing work by the Drupal 7 Field in Core developers the two ideas meet.

The “everything is a node” meme, takes shape in Drupal 7 as “everything is an entity” and a type of entity is a node. However, also users, taxonomy terms and comments are entities and entities can immediately plug-in to the Field API and have fields added to them.

However, the exact architectural solution to this didn’t come about in one simple step. First things became fieldable (i.e. more like nodes). Then the need to streamline the functionality required to deal with things such as taxonomy terms, users, comments and nodes led to the introduction of entities as a means to group together all the code that was repeated in different places and standardize terminology.

If you go digging in the Drupal issue queue you find a great issue called “Standarized, pluggable entity loading (nodes, users, taxonomy, files, comments)” – there Frando makes the case for streamlining how to deal with “loadable thingies, that can optionally be fieldable”.

Another interesting discussion is “Use the term entity instead of object, where the exact definition of Entities is discussed andthis patch shows that even just a few months ago the code in Drupal was still not consistently using the right terminology (entities where referred to as objects) – but a some great efforts by Chx and yched fixed a lot of that.

Say hi to Entities

So now, just a couple of months away (fingers crossed!) from the release of Drupal 7, Entities are the new nodes.

If you want to introduce some new fancy way of dealing with things and take full advantage of the power of Drupal you don’t need to write a module that turns X into a node, rather you create your own entity (take a look at the Awesome Relationshipsmodule for a great example).

Source: http://www.istos.it/blog/drupal/drupal-entities-part-1-moving-beyond-nodes

This also means that one can now at least imagine a Drupal without nodes because the architectural tools to allow you to that are there. Nodes are just one type of entity. Of course, while you can imagine it actually getting that done at the code level is still not that simple since quite a few things are hardwired. But the first vital step has been taken.

With the historical synopsis out of the way in a couple of days we are going to look at what entities are exactly and then explore how you can make use of them in modules.

 

Drupal 7 – .info file contents

The syntax of the .info file is similar to INI files. The .info file is basically a static text file for configuring the theme. Each line in the text file is a key-value pair with the key on the left and the value on the right, with an “equals sign” between them. (example: key = value) Semicolons are used to comment out a line. Some keys use a special syntax with square brackets for building a list of associated values, referred to as an “array”. If you are unfamiliar with arrays, using them should be apparent enough by following the example of the default .info files that come with Drupal and reading the explanations of the examples that follow.

Theme name requirements

The name should start with an alphabetic character, can contain numbers and underscores, but not hyphens, spaces or punctuation. The name will be used by Drupal in forming variousfunctions in PHP and therefore it has the same limitations. Warning! Do not choose the same name as a module, as all installed components must have unique names. For locally created themes using a prefix that is likely to be unique is good for theme naming. A site example.com might call its themes ex_themename.

Because the .info file is cached, you must clear the cache before any changes are displayed in your site.

The .info file can also specify which theme settings should be accessed from the Drupal administration interface, as you will soon see.

Drupal understands the keys listed below. Drupal will use default values for the optional keys not present in the .info file. See the examples set for core themes.

name (required)
The human readable name can now be set independently from the internal “machine” readable name. This imposes fewer restrictions on the allowed characters. 

name = A fantasy name

 

description (recommended)
A short description of the theme. This description is displayed on the theme select page at “Administer > Site building > themes”. 

description = Tableless multi-column theme designed for blogs.

 

screenshot
The optional screenshot key tells Drupal where to find the theme’s thumbnail image, used on the theme selection page (admin/build/themes). If this key is omitted from the .info file, Drupal uses the “screenshot.png” file in the theme’s directory.Use this key only if your thumbnail file is not called “screenshot.png” or if you want to place it in a directory outside of your theme’s base directory (e.g. screenshot = images/screenshot.png).

 

screenshot = screenshot.png

 

version (discouraged)
The version string will automatically be added by drupal.org when a release is created and a tarball packaged. So you may omit this value for contributed themes. However, if your theme is not being hosted on the drupal.org infrastructure, you can give your theme whatever version string makes sense. 

version = 1.0

 

core (required)
From 6.x onward, all .info files for modules and themes must indicate what major version of Drupal core they are compatible with. The value set here is compared with theDRUPAL_CORE_COMPATIBILITY constant. If it does not match, the theme will be disabled. 

core = 6.x

 

The drupal.org packaging script automatically sets this value based on the Drupal core compatibility setting on each release node. So people downloading packaged themes from drupal.org will always get the right thing. However, for sites that deploy Drupal directly from git, it helps if you commit this change to the .info file for your theme. This is also a good way to indicate to users of each theme what version of core the HEAD of git is compatible with at any given time.

engine (required in most cases)
The theme engine, which is used by the theme. If none is provided, the theme is assumed to be stand alone, i.e., implemented with a “.theme” file. Most themes should use “phptemplate” as the default engine.PHPTemplate’s job is to discover theme functions and templates for the behavior of the theme. Omit this entry only if you know what you are doing.

 

engine = phptemplate

 

base theme
Sub-themes can declare a base theme. This allows for theme inheritance, meaning the resources from the “base theme” will cascade and be reused inside the sub-theme. Sub-themes can declare other sub-themes as their base, allowing multiple levels of inheritance. Use the internal “machine” readable name of the base theme. The following is used in Minnelli, the sub-theme of Garland. 

base theme = garland

 

More details are available on the page Sub-themes, their structure and inheritance.

regions
The block regions available to the theme are defined by specifying the key of ‘regions‘ followed by the internal “machine” readable name in square brackets and the human readable name as the value, e.g., regions[theRegion] = The region name.If no regions are defined, the following values are assumed.

Drupal 6 default regions:

 

regions[left] = Left sidebar
regions[right] = Right sidebar
regions[content] = Content
regions[header] = Header
regions[footer] = Footer

 

Drupal 7 default regions:

 

regions[header] = Header
regions[highlighted] = Highlighted
regions[help] = Help
regions[content] = Content
regions[sidebar_first] = Left sidebar
regions[sidebar_second] = Right sidebar
regions[footer] = Footer

 

You can override the values for your specific needs.

More details are available on the page Blocks, content and their regions.

features
Various page elements output by the theme can be toggled on and off on the theme’s configuration page. The “features” keys control which of these check boxes display on the theme’s configuration page. This is useful for suppressing check boxes for elements not defined or used by a theme. To suppress a check box, omit the entry for it. However, if none are defined, all the check boxes will display due to the assumed defaults.The example below lists all the available elements controlled by the features key.

Drupal 6 features

By commenting out the primary_links and secondary_links elements, their check boxes are suppressed and are not seen by site administrators.

features[] = logo
features[] = name
features[] = slogan
features[] = mission
features[] = node_user_picture
features[] = comment_user_picture
features[] = search
features[] = favicon
; These last two disabled by redefining the
; above defaults with only the needed features.
; features[] = primary_links
; features[] = secondary_links

 

Drupal 7 features

 

features[] = logo
features[] = name
features[] = slogan
features[] = node_user_picture
features[] = comment_user_picture
features[] = favicon
features[] = main_menu
features[] = secondary_menu

 

More details are available on the page Custom theme settings.

stylesheets
Traditionally, themes default to using style.css automatically and could add additional stylesheets by calling drupal_add_css() in their template.php file. Starting in Drupal 6, themes can also add style sheets through their .info file. 

stylesheets[all][] = theStyle.css

 

Starting in Drupal 7, themes no longer default to using style.css if it is not specified in the .info file.

More details are available in the style sheets section.

scripts
Traditionally, themes could add Javascripts by calling drupal_add_js() in their template.php file. Starting in 6.x, if a file named script.js exists in the theme directory then it is automatically included. However, in Drupal 7, this behavior has been changed again so that script.js is only included if it has been specified in the .info file. Themes can also add specific javascript files by adding lines to their .info file: 

scripts[] = myscript.js

 

More details are available in the JavaScript & jQuery section.

php
This defines the minimum PHP version the theme will support. The default value is derived from the DRUPAL_MINIMUM_PHP constant, which is the minimum required version for the rest of core. This can be redefined for a newer version if needed. For most themes, this should not be added. 

php = 4.3.3

 

 

Example .info files from core themes

Garland:

 

name = Garland
description = Tableless, recolorable, multi-column, fluid width theme (default).
version = VERSION
core = 6.x
engine = phptemplate
stylesheets[all][] = style.css
stylesheets[print][] = print.css
; Information added by drupal.org packaging script on 2008-02-13
version = “6.0”
project = “drupal”
datestamp = “1202913006”

 

Minnelli sub-theme of Garland.:

name = Minnelli
description = Tableless, recolorable, multi-column, fixed width theme.
version = VERSION
core = 6.x
base theme = garland
stylesheets[all][] = minnelli.css
; Information added by drupal.org packaging script on 2008-02-13
version = “6.0”
project = “drupal”
datestamp = “1202913006”

 

Note that everything from the line “; Information added by drupal.org packaging script on 2008-02-13” and down is added by the drupal.org packaging script. You should never manually add the project and datestamp keys. The version key added manually (in the first section) allows sites to use your theme when taken directly from git.

Login or register to post comments

Comments

 

Naively, I assumed that I could add a link to the Google Analytics script by adding this line to my theme’s .info file:

scripts[] = http://www.google-analytics.com/urchin.js

Sadly, this will not work. It took me a long time to track down the problem, but it appears that when Drupal loads the .info file into a theme object during initialization, it renders the above line like this:

["http://www.google-analytics.com/urchin.js"] => "themes/Nefertari/http://www.google-analytics.com/urchin.js"

Note the “themes/Nefertari/” part in front of the URL. Subsequently, Drupal recognizes that the URL is malformed and drops it, so that no trace of the line from the info file winds up in the completed HTML. It took me over an hour to wade through the execution flow to find this out.

Furthermore, it appears that you can’t use drupal_add_js() in your template.php file either, because it can’t handle external JavaScript files in 6.x. People have been working on this issuefor about 13 months now, and it looks as though they might conceivably get it fixed in Drupal 7.

In the meantime, your options for linking to external JavaScript files are limited. You can:

  1. Download a copy of the file, put it in your theme folder, and then you can use your .info file to link to it. Of course, you’ll then be stuck updating the script every time the original one on the other domain changes.
  2. Hard code it into your theme.
  3. Create a custom template file for your theme and load it using a preprocess function.

I’ve opted for the third method. First I created a file called external-js.tpl.php in my theme directory, containing this:

 

<?php
<script type="text/javascript" src="http://www.google-analytics.com/urchin.js"></script>
?>

 

Then, in my template.php file, I created a pre-process function that loads that into a variable and adds the appropriate JS function call to $footer:

 

<?php
function Nefertari_preprocess_page(&$vars){
$path = drupal_get_path('theme', 'Nefertari');
$vars['external_js'] = theme_render_template($path.'/external-js.tpl.php', $vars);
$vars['footer'] .= '<script type="text/javascript">    _uacct = "UA-GOOGLE-ID"; urchinTracker(); </script>';
}
?>

 

Lastly, I modified page.tpl.php to print the variable $external_js right after $script in the header. I could also have printed it right before the footer, and that might have been better for performance. There’s actually a module for Google Analytics already, but it doesn’t fit my needs very smoothly (it’s designed for single sites, when I’m working with a multi-site install of nearly a hundred distinct Drupals).

 

Drupal 7 expand menu is removed from list

Drupal 7 has removed the ‘expand’ column from the menu grid. For most people ok, but for some not. However, a man called himerus took the liberty to create a module in which to enable this one again. This saves hours of work.

The post: http://himerus.com/blog/himerus/menu-expanded-restoring-sanity

And the module: http://drupal.org/project/menu_expanded