Listing Your Module on the Administration Page

Drupal's administration page presents the various site configuration options to the site administrator. You want your module to have a place on this configuration page, so that the site administrator can adjust the settings for your module. Let's add some more configuration options to the node annotation module we built in the previous chapter. We need to provide a link on the administration page so that the site administrator can get to the screen where our settings can be changed. We put the...

Creating Tables

A global variable called db_type determines the database type currently in use. In the following example, a hook_install function includes different CREATE TABLE statements for MySQL and PostgreSQL. Here's an example from the book.install switch GLOBALS 'db_type' case 'mysql' Use same as mysqli. case 'mysqli' db_query CREATE TABLE book vid int unsigned NOT NULL default '0', nid int unsigned NOT NULL default '0', PRIMARY KEY vid , KEY nid nid , 40100 DEFAULT CHARACTER SET UTF8 break case 'pgsql'...

Authentication Hooks for Downloading

Module developers can implement hook_file_download to set access permissions surrounding the download of private files. The hook is used to determine the conditions on which a file will be sent to the browser, and returns additional headers for Drupal to append in response to the file HTTP request. Note that this hook will have no effect if your Drupal installation is using the public file download setting. Figure 13-4 shows an overview of the download process using the implementation of...

D

d option, checkout command, 326 d option, cvs command, 326 d option, update command, 329 d placeholder, 52 dynamic queries, 312 storing data in database table, 20 data column, cache table, 244 data component, user object, 65 data entry form, adding, 16-21 data parameter, cache_set function, 251 data types handling security of user input, 302-303 HTML text, 303 plain text, 302 rich text, 303 URL, 303 database abstraction layer, 49-51 allowing MySQL PostgreSQL database bottlenecks, 344-348...

Connecting to Multiple Databases Within Drupal

While the database abstraction layer makes remembering function names easier, it also adds built-in security to queries. Sometimes we need to connect to third-party or legacy databases, and it would be great to use Drupal's database API for this need as well and get the security benefits. The good news is, we can In the settings.php file, db_url can be either a string as it usually is or an array composed of multiple database connection strings. Here's the default syntax, specifying a single...

Modifying Nodes of Our Type with hookload

The last node-related hook you need for your basic joke module is the ability to add your custom node attributes into the node object as it's constructed. We need to inject the punchline into the node loading process so it's available to other modules and the theme layer. For that you use hook_load . This hook is called just after the core node object has been built, and is only called for the current node type being loaded. If the node type is joke, then joke_load is called. Implementation of...

Access Control

In our examples so far, we've simply set the access key of the menu item to TRUE, meaning that anyone can access our menu. Usually menu access is controlled by defining permissions inside the module using hook_perm and testing those permissions using user_access . Let's define a permission called receive greeting, if a user does not have a role that has been granted this permission, the user will receive an Access denied message if he or she tries to go to http example. Implementation of...

Where Profiles Are Stored

Your Drupal site already contains an installation profile. It's the default installation profile that ships with Drupal, and you'll find it at profiles default default.profile. We want to create a new profile called university, so we'll create a new file at profiles university university.profile. For now, we'll just add a single function to the file Return a description of the profile for the initial installation screen. An array with keys 'name' and 'description' describing this profile....

Getting pot Files for Drupal

The definitive .pot files for Drupal can be downloaded from http drupal.org project drupal- pot. After downloading and extracting the .tar.gz file for the branch of Drupal you are interested in, you should have a directory full of .pot files corresponding to Drupal files. For example, aggregator-module.pot contains the translatable strings from Drupal's aggregator module. gunzip drupal-pot-5.x-1.x-dev.tar.gz tar -xf drupal-pot-5.x-1.x-dev.tar ls drupal-pot You'll notice a few other files in the...

Not Everything Is a Node

Users, blocks, and comments are not nodes. Each of these specialized data structures has its own hook system geared towards its intended purpose. Nodes usually have title and body content, and a data structure representing a user doesn't need that. Rather, users need an e-mail address, a username, and a safe way to store passwords. Blocks are lightweight storage solutions for smaller pieces of content such as menu navigation, a search box, a list of recent comments, and so on. Comments aren't...

clientsystem drupal module

Programmatically Modifying Existing Menus

When you implement the menu hook in your module, there's nothing to prevent you from adding entries to other modules' paths, or even from overriding them. Typically this is done using the handy web interface provided by menu. module, which ships as part of Drupal, but you may have reasons to do this programmatically. For example, devel.module which you're probably using if you're doing serious Drupal development has a menu item that clears Drupal's cache tables. Let's wrap that function so our...

Building a Block

For this example, you'll create two blocks that make content moderation easier to manage. First, you'll create a block to list comments being held pending approval, then you'll create a block to list unpublished nodes. Both blocks will also provide links to the edit form for each piece of moderated content. Let's create a new module named approval. module to hold our block code. Create a new folder named approval within sites all modules custom you might need to create the modules and custom...

Administration Variables and Module Settings

Drupal stores most administrative settings in the variables table, and caches that data to the cache table to speed the lookup of configuration data. Examples of such variables include the name of your site, settings for comments and users, and the location of the files directory. These variables are cached to a single row in the cache table, so they can be quickly retrieved, rather than making a database query for each variable value as it is needed. They are stored as a PHP array, so the...

Writing a Validation Function

Drupal has a built-in mechanism for highlighting form elements that fail validation and displaying an error message to the user. Examine the validation function in our example to see it at work function formexample_nameform_validate form_id, form_values if form_values 'user_name' 'King Kong' We notify the form API that this field has failed validation. form_set_error 'user_name ', t 'King Kong is not allowed to use this form.' Note the use of form_set_error . When King Kong visits our form and...

Limiting Access to a Node Type with hookaccess

Node modules can also limit access to the node types they define using hook_access . The superuser user ID 1 will always bypass any access check, so this hook isn't called in that case. If this hook isn't defined for your node type, all access checks will fail, so only the superuser and those with administer nodes permissions will be able to see content of that type. Implementation of hook_access . function joke_access op, node global user if op 'create' return user_access 'create joke' if op...

Rendering the Form

To convert the form tree from a nested array to HTML code, the form builder calls drupal_render . This recursive function goes through each level of the form tree, and with each, it performs the following actions 1. Determine if the children element has been defined synonymous with content having been generated for this element if not, render the children of this tree node as follows Determine if a theme function has been defined for this element. If so, temporarily set the type of this element...

Checking Your Coding Style Programmatically

Inside the scripts directory of your Drupal root directory, you'll find a Perl script named code-style.pl, which checks your Drupal coding style. Here's how to use it. First, change the permissions in order to make the file executable otherwise, you'll get a Permission denied error. This can be done from the command line using chmod as follows -rw-r--r-- 1 mathias mathias 4471 Oct 23 21 10 code-style.pl -rwxr--r-- 1 mathias mathias 4471 Oct 23 21 10 code-style.pl Windows users don't need to...

termdata taxonomy module

Using a CSS Class Selector

Here's a similar example using a CSS class selector instead of using a CSS ID as we did in the preceding section. The HTML would be as follows lt p class intro gt Welcome to the World of Widgets lt p gt The following would also work, and is a slightly more specific rule Here's how the CSS translates to jQuery code In the first of the preceding examples, you're asking jQuery to find any HTML element that has the intro class, while the second example is subtly different. You instead ask for any...

Keeping Private Data Private with dbrewritesql

The preceding example of listing nodes is a common task for contributed modules though less so now that the views module makes it so easy to define node listings through the web . Question if a node access control module is enabled on the site, where is the code in the preceding example that makes sure our user sees only the subset of nodes that is allowed You're right . . . it's completely absent. The preceding code will show all nodes of a given type, even those protected by node access...

Standalone PHP

Occasionally, you might need to write a stand-alone .php file instead of incorporating the code into a Drupal module. When you do, be sure to keep security implications in mind. Suppose, when you were testing your web site, you wrote some quick and dirty code to insert users into the database so you could test performance with many users This script generates users for testing purposes. These two lines are all that is needed to have full access to Drupal's functionality. include_once 'includes...

Adding the Data Entry Form

In order for the user to enter notes about a web page, we're going to need to provide a place for the notes to be entered. Let's add a form for notes function annotate_nodeapi amp node, op, teaser, page switch op case 'view' global user If only the node summary is being displayed, or if the user is an anonymous user not logged in , abort. if teaser user- gt uid 0 break types_to_annotate variable_get 'annotate_nodetypes', array 'story' if in_array node- gt type, types_to_annotate break Add our...

jQuery Within Drupal

Using jQuery within Drupal is easy because jQuery is preinstalled with Drupal. Log into your Drupal site as user 1 the administrative account and create a new node of type page. On the node creation form select PHP code under the Input formats section. Enter Testing jQuery as the title and add the following to the body section of the form ' document .ready function lt p id one gt Paragraph one lt p gt lt p gt Paragraph two lt p gt lt p gt Paragraph three lt p gt Hit Submit and then reload the...

Callback Mapping

When a web browser makes a request to Drupal, it gives Drupal a URL. From this information, Drupal must figure out what code to run and how to handle the request. This is commonly known as dispatching. Drupal trims off the base part of the URL and uses the latter part, called the path. For example, if the URL is http example.com q node 3, the Drupal path is node 3. The general approach taken is as follows Drupal asks all its modules to provide an array of menu items that is, a path and some...

The Menu System

D rupal's menu system is one of those dark places where few have the courage to tread. Put on your armor we're going in The term menu system is somewhat of a misnomer. It may be better to think of the menu system as having three primary responsibilities callback mapping, access control, and menu customization. Essential code for the menu system is in includes menu .inc, while optional code that enables such features as customizing menus is in menu.module. In this chapter, we'll explore what...

Storing Data in the Session

Storing data in a user's session is convenient, because the data is automatically stored by the sessions system. Whenever you want to store data that you want to associate with a user during a visit or multiple visits up to session.cookie_lifetime , use the _SESSION superglobal _SESSION 'favorite_color' favorite_color Later, on a subsequent request, do the following to retrieve the value favorite_color _SESSION 'favorite_color' If you know the user's uid and you want to persist some data about...

Passing Data Along with formsetvalue

If your validation function does a lot of processing and you want to store the result to be used in your submit function, you can sneak it into the form data by using form_set_value . First, you'll have to create a place to stash the data when you create your form in your form definition function form 'my_placeholder' array ' type' gt 'value', ' value' gt array Then, during your validation routine, you store the data Lots of work here to generate my_data as part of validation. my_data And you...

Replacing Builtin Strings with Custom Strings

Suppose the term blog bothers you, so you want to change it to journal without modifying any code. You can use the locale module to change it. The approach is to create a language containing only the string s we want replaced. First, let's add a custom language to hold our custom strings. The interface for doing that is shown in Figure 18-2. We'll call it English-custom and use en-US for the language code. Tip If you intend to have multiple languages simultaneously enabled on your site and will...

Adding and Manipulating Template Variables

The question becomes if you can make your own template files and control the variables being sent to them, how can you manipulate or add variables being passed into page and node templates Every call to load a template file passes through the phptemplate_callback function to which you were just introduced. This function is responsible for aggregating the variables to pass along to the correct template file, and these variables can come from three different locations The variables array passed...

Writing Your Own Database Abstraction Layer

Suppose we want to write a database abstraction layer for a new, futuristic database system named DNAbase that uses molecular computing to increase performance. Rather than start from scratch, we'll copy an existing abstraction layer and modify it. We'll use the MySQL implementation, since MySQL is the most popular database used with Drupal. First, we make a copy of includes database.mysql.inc and rename it as includes database.dnabase.inc. Then we change the logic inside each wrapper function...

Making Queries Secure with dbquery

A common way of exploiting web sites is called SQL injection. Let's examine a module written by someone not thinking about security. This person just wants a simple way to list titles of all nodes of a certain type function insecure_menu may_cache items array if may_cache items array 'path' gt 'insecure', 'title' gt t 'Insecure Module' , 'description' gt t 'Example of how not to do things.' , 'callback' gt 'insecure_code', 'access' gt user_access 'access content' Menu callback, called when user...

Creating a ModuleBased Vocabulary

Let's look at an example of a module-based vocabulary. The contributed image gallery module uses taxonomy to organize different image galleries. It creates its vocabulary programmatically, as shown in the following example, and assumes ownership of the vocabulary by setting the module key of the vocabulary array to the module name without .module . Returns and possibly creates a new vocabulary for Image galleries. function _image_gallery_get_vid vid '' if empty vid Check to see if an image...

Adding Filter Format Support

Because the body field is a textarea, and node body fields are aware of filter formats, you include Drupal's standard filter selector with the following line see Chapter 11 for more on using filters form 'body_filter' 'filter' filter_form node- gt format If you wanted the punchline field to also be able to use input filter formats, you'd have to add another column in your joke database table to store the input filter format setting per punchline, as follows ALTER TABLE 'joke' ADD...

Cleaning up with hookdelete

Just after a node is deleted from the database, Drupal lets modules know what has happened via hook_delete . This hook is typically used to delete related information from the database. This hook is only called for the current node type being deleted. If the node type is joke, then joke_delete will be called. Implementation of hook_delete . Delete the related information we were saving for this node. db_query 'DELETE FROM joke WHERE nid d', node- gt nid Note When a revision rather than the...

Providing Custom Paths for Terms

If your module is in charge of maintaining a vocabulary, it might want to provide custom paths for terms under its control, instead of using the default taxonomy term term id provided by taxonomy.module. When generating a link for a term, the following function in taxonomy.module is called. You should always call this function instead of generating links to taxonomy terms yourself don't assume that the taxonomy module maintains a taxonomy. Note how it checks with the module that owns the...

Defining Node Grants

There are three basic permissions for operations on nodes view, update, and delete. When one of these operations is about to take place, the module providing the node type gets first say with its node_access implementation. If that module doesn't take a position on whether the access is allowed, Drupal asks all modules that are interested in node access to respond to the question of whether the operation ought to be allowed. They do this by responding to hook_node_grants with a list of grant...

cachefilter filter module

External Authentication with Server Provided

When a user signs in with a username in the form of joe example.com, we have more information to go by. Drupal core contains drupal. module, which provides an XML-RPC client that contacts another server for authentication. For example, on the site http groups.drupal.org, you can log in with your http drupal.org username and password. Here's what happens when I do that for the first time 1. I log in to groups.drupal.org with the username jvandyk drupal.org and my password. 2. groups. drupal .org...

Using a Temporary Table

If you are doing a lot of processing, you may need to create a temporary table during the course of the request. You can do that using db_query_temporary with a call of the following form result db_query_temporary sql, arguments, temporary_table_name You can then query the temporary table using the temporary table name. For example, in the do_search function of Drupal's search module, the search is done in several stages using temporary tables to hold intermediary information. Here is the...

Manipulating Nodes That Are Not Our Type with hooknodeapi

The preceding hooks are only invoked based on the node type. When Drupal sees a blog node type, blog_load is called. What if you want to add some information to every node, regardless of its type The hooks we've reviewed so far aren't going to cut it for that we need an exceptionally powerful hook hook_nodeapi . Although this hook isn't needed for creating nodes, it's worth mentioning here because it creates an opportunity for modules to react to the different states during the life cycle of...

Translating Strings with t

All strings in Drupal should be run through the t function this is Drupal's translate function, with the function name shortened to t for convenience because of its frequent use. The locale-specific part of the function looks like this function t string, args 0 global locale if function_exists 'locale' amp amp locale 'en' Translate the string. string locale string In addition to translation, the t function also handles insertion of values into placeholders in strings. The values are typically...

The user Object

Drupal requires that the user have cookies enabled in order to log in a user with cookies turned off can still interact with Drupal as an anonymous user. During the session phase of the bootstrap process, Drupal creates a global user object that represents the identity of the current user. If the user is not logged in and so does not have a session cookie , then he or she is treated as an anonymous user. The code that creates an anonymous user looks like this and lives in bootstrap.inc function...

Displaying Menu Items As Tabs

In Drupal's admittedly obscure menu lingo, a callback that is displayed as a tab is known as a local task and has the type MENU_LOCAL_TASK or MENU_DEFAULT_LOCAL_TASK. The title of a local task should be a short verb, such as add or list. Local tasks usually act on some kind of object, such as a node, user, or workflow. Local tasks must have a parent item in order for the tabs to be rendered. A common practice is to assign a callback to a root path like milkshake, and then assign local tasks to...

Separate Database Server and a Web Server Cluster

Multiple web servers provide failover and can handle more traffic. The minimum number of computers needed for a cluster is two web servers. Additionally, you need a way to switch traffic between the machines. Should one of the machines stop responding, the rest of the cluster should be able to handle the load. Load balancers distribute web traffic among web servers. There are other kinds of load balancers for distributing other resources such as a hard disks and databases, but we'll cover those...

Keeping Informed of Vocabulary Changes with hooktaxonomy

If you do keep a vocabulary for your own module, you'll want to be informed of any changes that are made to the vocabulary through the standard Categories user interface. You might also want to be informed when a change is made to an existing vocabulary maintained by taxonomy. module. In either case, you can be informed of changes to vocabularies by implementing hook_taxonomy . The following module has an implementation of hook_taxonomy that keeps you informed of vocabulary changes by e-mail....

Understanding Template Files

Drupal Template Files Diagram

Some themes have all sorts of template files, while others only have page.tpl. php. So how do you know which template files you can create and have be recognized in Drupal What naming conventions surround the creation of template files You'll learn the ins and out of working with template files in the following section. page.tpl.php is the granddaddy of all template files, and provides the overall page layout for the site. Other template files are inserted into page.tpl.php, as the diagram in...

The punchline hookview

Now you have a complete system to enter and edit jokes. However, your users will be frustrated because although punchlines can be entered on the node submittal form, you haven't provided a way to make your module-provided punchline field visible when viewing the joke Let's do that now with hook_view Implementation of hook_view . function joke_view node, teaser FALSE, page FALSE if teaser Use Drupal's default node view. node node_prepare node, teaser Add a random number of Ha's to simulate a...

External Login

Wordpress External Authentication Login

True to Drupal's nature, external authentication can simply be plugged into Drupal by implementing hooks in a module. An overview of the process Drupal goes through when performing external authentication is shown in Figure 6-6. If no module that provides external authentication i.e., responds to the auth hook is enabled, Drupal will treat all usernames as local usernames. So both joe and joe example .com are simply considered strings with no special meaning. However, when a module that...

Technology Stack

Drupal Technology Stack

Drupal's design goals include both being able to run well on inexpensive web hosting accounts and being able to scale up to massive distributed sites. The former goal means using the most popular technology, and the latter means careful, tight coding. Drupal's technology stack is illustrated in Figure 1-1. Figure 1-1. Drupal's technology stack Figure 1-1. Drupal's technology stack The operating system is at such a low level in the stack that Drupal does not care much about it. Drupal runs...