**** http://drupalwithpankaj.blogspot.com/
http://drupalwithpankaj.blogspot.com/2013/01/custom-module-in-drupal.html
https://drupal.org/node/310075
https://api.drupal.org/api/drupal/modules%21system%21theme.api.php/group/themeable/7
Name your module
The first step in creating a module is to choose a "short name" for it. This short name will be used in all file and function names in your module, so it must start with a letter, and it must contain only lower-case letters and underscores.
For this example, we'll choose "current_posts" as the short name. Important note: Be sure you follow these guidelines and do not use upper case letters in your module's short name, since it is used for both the module's file name and as a function prefix.
When you implement Drupal "hooks" (see later portions of tutorial), Drupal will only recognize your hook implementation functions if they have the same function name prefix as the name of the module file.
When you implement Drupal "hooks" (see later portions of tutorial), Drupal will only recognize your hook implementation functions if they have the same function name prefix as the name of the module file.
It's also important to make sure your module does not have the same short name as any theme you will be using on the site.
Create a folder and a module file
Given that our choice of short name is "current_posts" :
- Start the module by creating a folder in your
Drupal installation at the path:sites/all/modules/current_posts
- Create the PHP file for the module :
- Save it as
current_posts.module
in the directorysites/all/modules/current_posts
- As of Drupal 6.x,
sites/all/modules
is the
preferred place for non-core modules
(andsites/all/themes
for non-core themes),
because this places all site-specific files in the
sites directory. This allows you to more easily
update the core files and modules without
erasing your customizations. Alternatively, if
you have a multi-site Drupal installation and
this module is for only one specific site, you
can put it insites/your-site-folder/modules
.
- Add an opening PHP tag to the module :
<?php
- Module files begin with the opening PHP tag.
Do not place the CVS ID tag in your module. It
is no longer needed with drupal.org's
conversion to Git. If the coder module gives
you error messages about it, then that module
has not yet been updated to drupal.org's Git
conventions.
The module is not operational yet: it hasn't been activated. We'll activate the module later in the tutorial.
Main topic described: .info files
All modules must have a 'modulename.info' file, which contains meta information about the module.
The general format is:
name = Module Name
description = A description of what your module does.
core = 7.x
For our module, we will replace 'Module Name' in the example above with the name of our module, 'Current Posts'. Without this file, the module will not show up in the module listing. Here is our specific example:
name = Current Posts
description = A block module that lists links to recent posts.
core = 7.x
Add the source above to a file named
current_posts.info
and save it into the module's directory at sites/all/modules/current_posts
.
Note: If you copy and paste this code block, ensure that the description data does not contain a line break (turn off word-wrap on your text-editor to be sure). Otherwise, the .info file will not parse correctly.
.Info File Details
The details of what to put in a .info file can be found on the Writing .info files page.
Check
To make your module visible to Drupal create a 'modulename.module' file. For now it can simply be a text file that contains nothing but the opening
<?php
tag (with no closing tag). For our module this file will be named current_posts.module
.
Your module should now appear in the module list in your site. Go to Modules and scroll down to the bottom of the list in the 'Other' category. You should see the module 'Current Posts'.
Comments in Drupal modules
It's always a good idea to document how your module works in comments. Drupal uses Doxygen to draw documentation from source code, so contrib modules on drupal.org follow strict comment guidelines. See Doxygen and comment formatting conventions for more details. Following these guidelines is beneficial to anyone looking at your code even if it's not strictly necessary for your situation.
Your first comment:
<?php
/**
* @file
* A block module that displays recent blog and forum posts.
*/
?>
(Remember that the closing tag is included here for formatting reasons only and you should not include it in your real code.)
@file signifies that this comment pertains to the entire file. The doc block begins with a slash and two asterisks (/**) and ends with one asterisk and a slash (*/). Following Drupal guidelines, we will introduce each function in the module with such a comment.
Implementing your first hook
Hooks are fundamental to Drupal modules. They allow you to integrate your module into the actions of Drupal core. If you missed it, go back and read about hooks in Introduction to Drupal modules.
Your first hook is
hook_help
. This hook is recommended for inclusion in all contrib modules. hook_help
provides help and additional information about the module to the user. To implement any hook in Drupal, replace "hook" in the hook name with your module's short name, and create a function in the .module file with that name. So, to implement hook_help()
in our example module, we create a function called current_posts_help()
in the current_posts.module file:<?php
function
current_posts_help
(
$path
,
$arg
) {
}
?>
The
$path
parameter provides context for the help: where in Drupal or the module the user is when they are accessing help. The recommended way to process this variable is with a switch statement. This code pattern is common in Drupal modules. Here is an abbreviated implementation of this function for your module, along with its doc block comment:<?php
/**
* Implements hook_help.
*
* Displays help and module information.
*
* @param path
* Which path of the site we're using to display help
* @param arg
* Array that holds the current path as returned from arg() function
*/
function
current_posts_help
(
$path
,
$arg
) {
switch (
$path
) {
case
"admin/help#current_posts"
:
return
'<p>'
.
t
(
"Displays links to nodes created on this date"
) .
'</p>'
;
break;
}
}
(Note the closing
?>
should not appear in your code.)
The
recommendation. The
admin/help#modulename
case is used by Drupal core to link from the main help page (/admin/help
or ?q=admin/help
). You will eventually want to add more text to provide a better help message to the user; see Help text standard for the complete recommendation. The
t()
function that wraps the text marks it for translation. This function not only allows for translation, it can give your code an added layer of security. See Localization API for more information.Check
Look again at the module list by clicking Modules on the Toolbar in your Drupal installation. Enable the module and click 'Save configuration'. Close and reopen the Modules page, find your module in the list, and you should see a link to 'Help' on the right. Click it to see the help text returned by
You can also follow the Help link in the toolbar (
current_posts_help
. You can also follow the Help link in the toolbar (
http://example.com/admin/help
) and find your help link listed with the others on that page.
Disable your module and save ('Save configuration' button). Important: Be sure you follow that last step and disable your module and save, or new partial code in your module could break your site.
Modules are created to do all sorts of things: create blocks (abbreviated content that often appears on the right or left side of multiple pages), create special content types (for full page content - such as the content you are reading right now), track back-end information, and more.
You may hear the term 'block modules' used to describe modules that primarily create block content (such as the menu module), or 'node modules' used to describe modules that primarily generate full page content (such as the blog and forum modules). At this stage, this module is a 'block module', because it generates a block.
You may hear the term 'block modules' used to describe modules that primarily create block content (such as the menu module), or 'node modules' used to describe modules that primarily generate full page content (such as the blog and forum modules). At this stage, this module is a 'block module', because it generates a block.
In Drupal 7, there are at least eight block hooks. For the purposes of this module, we will use two of them. The first is
hook_block_info()
. As you might suspect, this hook tells Drupal what block(s) your module creates. We will use this hook to define a block that will eventually display the most recent posts. You can use a given hook exactly once in any module, so this hook must declare all blocks the module needs. For this module, a single block is all we need.
To use this hook to define our block, go to your
current_posts.module
file and create the functioncurrent_posts_block_info()
as follows:<?php
/**
* Implements hook_block_info().
*/
function
current_posts_block_info
() {
$blocks
[
'current_posts'
] = array(
'info'
=>
t
(
'Current posts'
),
//The name that will appear in the block list.
'cache'
=>
DRUPAL_CACHE_PER_ROLE
,
//Default
);
return
$blocks
;
}
?>
(Remember not to include the closing
?>
in your code.)
The doc block simply identifies the hook. For such a straightforward implementation, that is sufficient. Anyone reading the code can easily go to the API and call up the hook for further information.
The return value takes the form of an associative array. Pay special attention to this array structure, as it is Drupal's preferred programming structure. Arrays in PHP are well supported and very fast, and Drupal makes extensive use of them.
The only required value is 'info'.
hook_block_info
can also specify configuration settings. Here we set the cache to the default. See hook_block_info for a complete list of settings available.
Don't forget the final return statement.
Check
At this point, go to Modules, click the checkbox to enable Current Posts, and save your configuration. Next, navigate to Structure > Blocks. Scroll down to the bottom of the list. Among the disabled blocks, you should find the name, 'Current posts'. Return to Modules, disable your module and save. Important: Be sure you disable your module and save, or new partial code in your module could break your site.
Main function described: db_select()
Next we will create a custom function to retrieve the most recent posts. When a node is first created, the time of creation is stored in the database. We'll use this database field to find our data. We could include this code in the hook we will implement in the next tutorial page. Putting this section into a separate function keeps the code cleaner, easier to read and to maintain.
We will call the function
current_posts_contents
. We continue to follow the naming convention by beginning with the module short name. Then we use a descriptive word that is not a Drupal hook. The function begins with getting the time numbers. Here's the first part (without a closing brace because it's not the complete function):<?php
/**
* Custom content function.
*
* Set beginning and end dates, retrieve posts from database
* saved in that time period.
*
* @return
* A result set of the targeted posts.
*/
function
current_posts_contents
(){
//Get today's date.
$today
=
getdate
();
//Calculate the date a week ago.
$start_time
=
mktime
(
0
,
0
,
0
,
$today
[
'mon'
],(
$today
[
'mday'
] -
7
),
$today
[
'year'
]);
//Get all posts from one week ago to the present.
$end_time
=
time
();
?>
This code gets the current time, then calculates the time (in seconds since epoch start, seemktime for more information on time format) for midnight a week ago. These functions are straight PHP; you can look them up on the PHP website (php.net) for more details.
Next we use Drupal's Database API to retrieve our list of current nodes. This is the second part of the custom function:
<?php
//Use Database API to retrieve current posts.
$query
=
db_select
(
'node'
,
'n'
)
->
fields
(
'n'
, array(
'nid'
,
'title'
,
'created'
))
->
condition
(
'status'
,
1
)
//Published.
->
condition
(
'created'
, array(
$start_time
,
$end_time
),
'BETWEEN'
)
->
orderBy
(
'created'
,
'DESC'
)
//Most recent first.
->
execute
();
return
$query
;
}
?>
Built into Drupal is a very robust query builder, using a special object-oriented API. INSERT, UPDATE, and DELETE queries need this special care in order to behave consistently across all different databases. Although our SELECT query doesn't require this structure, this is a good opportunity to become familiar with it. You will see this structure used throughout Drupal.
- We build the query using the
db_select
method,
which takes a table name ('node') and alias ('n')
as arguments. - The
fields
method uses the table assigned the
alias 'n' to select the fields listed in the array in
the second argument. - The
condition
method takes three arguments. The
first is the field, the second the value, the third
the operator. If no operator is specified, as in
'status' above,=
is assumed. - The
orderBy
method sorts according to the field in
the first argument, in the order specified by the
second argument. - The
execute
method compiles and runs the query
and returns a result set/statement object.
Here's the complete function:
<?php
/**
* Custom content function.
*
* Set beginning and end dates, retrieve posts from database
* saved in that time period.
*
* @return
* A result set of the targeted posts.
*/
function
current_posts_contents
(){
//Get today's date.
$today
=
getdate
();
//Calculate the date a week ago.
$start_time
=
mktime
(
0
,
0
,
0
,
$today
[
'mon'
],(
$today
[
'mday'
] -
7
),
$today
[
'year'
]);
//Get all posts from one week ago to the present.
$end_time
=
time
();
//Use Database API to retrieve current posts.
$query
=
db_select
(
'node'
,
'n'
)
->
fields
(
'n'
, array(
'nid'
,
'title'
,
'created'
))
->
condition
(
'status'
,
1
)
//Published.
->
condition
(
'created'
, array(
$start_time
,
$end_time
),
'BETWEEN'
)
->
orderBy
(
'created'
,
'DESC'
)
//Most recent first.
->
execute
();
return
$query
;
}
?>
(Remember not to include the closing
?>
in your code.)See also
Main functions described: user_access(), l(), theme()
The next step in this tutorial is to take the data we generated in our custom function and turn it into content for the block. We will do this using
This function returns two values, 'subject', which is the title of the block, and 'content', which is self-documenting. Once again, we will use a switch structure. This structure allows for additional blocks to be added in the future if needed. The $delta parameter tells the function which block is being requested.
hook_block_view
. This function returns two values, 'subject', which is the title of the block, and 'content', which is self-documenting. Once again, we will use a switch structure. This structure allows for additional blocks to be added in the future if needed. The $delta parameter tells the function which block is being requested.
Access check
Here's the first part of the code:
<?php
function
current_posts_block_view
(
$delta
=
''
) {
switch(
$delta
){
case
'current_posts'
:
$block
[
'subject'
] =
t
(
'Current posts'
);
if(
user_access
(
'access content'
)){
//Retrieve and process data here.
}
?>
Best practice dictates that information displayed to the user be assessed against that user's permissions. Here we implement the most basic of checks, 'access content'. You can use any permission here that Drupal supplies, or even create your own. For a list of permission names, go to People > List (tab) (or
In the permission dropdown there, you will find a list of the machine readable names that you can use in your code. This list will include all permissions active on your site, including those created by contrib modules. The names in the Permissions tab (
http://example.com/admin/people
). In the permission dropdown there, you will find a list of the machine readable names that you can use in your code. This list will include all permissions active on your site, including those created by contrib modules. The names in the Permissions tab (
http://example.com/admin/people/permissions
) are not the machine readable names.
Another way to find permissions set in core modules is through the API reference. Enter the module name followed by
_permission
, for example, node_permission
. You'll get a list of all the permissions that node defines. Knowing which one to use might be a bit tricky. For example, the access content
permission we use here is actually defined in the node module, not the block module.Coding the data as links
Here's the next bit of code:
<?php
//Use our custom function to retrieve data.
$result
=
current_posts_contents
();
//Array to contain items for the block to render.
$items
= array();
//Iterate over the resultset and format as links.
foreach (
$result
as
$node
){
$items
[] = array(
'data'
=>
l
(
$node
->
title
,
'node/'
.
$node
->
nid
),
);
}
?>
First we use our custom function to save the data into the
$result
variable. The $items
variable gives us a place to store the processed data. We then iterate over the resultset, processing each item and formatting it as a link.
Notice the actual link is created by the l() function. (That's a small case 'L'.) The first parameter sets the link text, in this case the node's title. The second parameter is the actual link path. The path to any node is always "node/#", where # is the ID number of the node.
l()
uses this path to generate appropriate links, adjusting the URL to the installation's URL configuration.Theming the data
Drupal's presentation layer is a pluggable system known as the theme layer. Each theme can take control of most of Drupal's output, and has complete control over the CSS. Theming in Drupal is a vast subject with entire books devoted to the subject. Here we will merely touch the surface with a theme function. Later in the tutorial, we will delve into render arrays.
Here's the last section of code for
current_posts_block_view
:<?php
if (empty(
$items
)) {
//No content in the last week.
$block
[
'content'
] =
t
(
'No posts available.'
);
} else {
//Pass data through theme function.
$block
[
'content'
] =
theme
(
'item_list'
, array(
'items'
=>
$items
));
}
}
return
$block
;
}
}
?>
First, we allow for the possibility of no content that fits our criteria. Your module's block should appear whether or not new content from the last week exists on your site.
If the
The second argument passes the content to be themed.
$items
variable contains data, it goes to the theme()
function. The first argument of this function is the theme hook. Drupal includes many default theme hooks you can use with this function; see Default theme implementations for the complete list. We have chosen to theme our data as an unordered list, the theme_item_list theme hook. The second argument passes the content to be themed.
You may wonder why the code takes this form if the function is
theme_item_list
. theme()
looks for a theme function called theme_hookname
, where 'hookname' is the first argument, in this case,item_list
. In other words, the second part of the hook name becomes the first argument when the function is called, telling the theme function which of its default versions to use.The whole function
<?php
/**
* Implements hook_block_view().
*
* Prepares the contents of the block.
*/
function
current_posts_block_view
(
$delta
=
''
) {
switch(
$delta
){
case
'current_posts'
:
$block
[
'subject'
] =
t
(
'Current posts'
);
if(
user_access
(
'access content'
)){
//Use our custom function to retrieve data.
$result
=
current_posts_contents
();
//Array to contain items for the block to render.
$items
= array();
//Iterate over the resultset and format as links.
foreach (
$result
as
$node
){
$items
[] = array(
'data'
=>
l
(
$node
->
title
,
'node/'
.
$node
->
nid
),
);
}
if (empty(
$items
)) {
//No content in the last week.
$block
[
'content'
] =
t
(
'No posts available.'
);
}
else {
//Pass data through theme function.
$block
[
'content'
] =
theme
(
'item_list'
, array(
'items'
=>
$items
));
}
}
return
$block
;
}
}
?>
(Remember not to include the opening or closing PHP tags when you add this section.)
See also
Enable the module
Go to Modules, or
http://example.com/admin/modules
, and scroll down to the bottom of the list in the 'Other' category. You should see the module 'Current posts.' Click the checkbox to enableCurrent posts, and save your configuration. Now you should see a link to Help beside the module name. Click it to see the help text you entered in current_posts_help
.Enable the block
Next, navigate to Structure > Blocks, or
http://example.com/admin/structure/block
. Scroll down to the bottom of the list. Among the disabled blocks, you should find the name, 'Current posts'. Set its location for one of the page regions and save. Navigate to another page like your homepage to see your block. Congratulations! You have written a working module.Troubleshooting
If you get a "white screen" or a PHP error when you enable this module, it probably means you have a syntax error in your
.module
file. Be sure all your punctuation is correct, semi-colons, commas, etc. all in the right places, and that you have all the hook names and module short names spelled correctly. (In the case of a white screen, you may be able to find out what the PHP error was by looking in your Apache error log. Or you can try changing PHP's error reporting level.)
If you cannot find and fix the syntax error, nothing on your site will display, because Drupal will try to load your module on every page request. The easiest way to get your site working again is to delete the module's folder or move it out of the site, in which case Drupal will figure out that it shouldn't load this module after all, and your site should work again.
Clear caches
Drupal caches a lot of data, and if you are not seeing changes appear, that could be why. In this phase of the module, the caches shouldn't be an issue, but they will be as we proceed. To get all the troubleshooting instructions in one place, we'll give you the instructions here that you'll need later.
To clear the caches, go to Configuration > Performance or
http://example.com/admin/config/development/performance
, and click the Clear all cachesbutton.
Không có nhận xét nào:
Đăng nhận xét