Currently showing entries with the tag: dynamic block
|
page 1 of 1
|
How to Create Dynamic Blocks in Drupal
October 14, 2007 • 10:21PM • permalink
One of my clients uses the Drupal CMS Framework, which requires me to code custom modules and create custom blocks. Drupal (and PHP in general) make a lot of things very easy, but in some cases (Drupal in particular) make the simple things VERY difficult. I've come across quite a few cases where I needed to create dynamic blocks of content that can be stored and retrieved. At first I thought Drupal would make it impossible, but the solution is actually quite simple.
For this example, I'm going to build a simple Google AdSense module that will allow the creation of an infinite number of blocks.
The Assumptions
1) This module was built using Drupal 4.7. I'm not familiar enough with other Drupal environments to assure that this will work, but if anybody tries testing it on other Drupal versions - please let me know so I can update this blog entry!
2) I'm going to assume that the reader has built a basic Drupal module before and does not need a basic explanation of hooks.
3) I'm going to assume that there was previously a variable_set('google_adsense_code', 'pub-XXXXXXXXXXXX-XXXX') call in some form that will allow the site administrator to set their personal AdSense code.
The Database
Now, let's setup a basic database schema for this module. (Note, this was executed on MySql 5.0.22)
CREATE TABLE IF NOT EXISTS gadsense_blocks (
bid INT AUTO_INCREMENT PRIMARY KEY,
width INT,
height INT,
type VARCHAR(32)
);
The above would either be executed directly on the database server or embedded in a Drupal module .install file to create the table the first time the module is installed.
The above table is very simple with an auto-incrementing bid, the width and height of our target ad, and a simple text field we'll use to store whether our ad is a text or image ad (or both).
The Core Module Hooks
As I said above, I'm going to assume the reader has built a basic Drupal module before and can understand the below without explanation.
function gadsense_help($section = 'admin/help#gadsense') {
switch ($section) {
case 'admin/modules#description':
return t('Creates an area for Google AdSense support.');
}
}
function gadsense_perm() {
return array('administer adsense');
}
function gadsense_menu($may_cache) {
$items = array();
$items[] = array(
'path' => 'admin/settings/gadsense/list',
'title' => t('Google AdSense Ads'),
'callback' => 'list_ads_page',
'access' => user_access('administer adsense'),
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'admin/settings/gadsense/add',
'title' => t('Google AdSense Ads'),
'callback' => 'create_ads_page',
'access' => user_access('administer adsense'),
'type' => MENU_CALLBACK,
);
return $items;
}
The Administrator Pages
Now that we've got our core module created, we can get to work! We're going to create two pages for basic administration. The first page, the main admin page, will list all the blocks we've created so far and offer a link to create a new one.
function list_ads_page() {
$result = db_query('SELECT * FROM {gadsense_blocks} ORDER BY width + " x " + height ASC');
$rows = array();
while ($field = db_fetch_object($result)) {
$rows[] = array($field->bid, $field->width, $field->height, $field->type);
}
if (count($rows) == 0) {
$rows[] = array(array('data' => t('No ad blocks have been defined.'), 'colspan' => '6'));
}
$header = array(t('id'), t('width'), t('height'), t('type'));
$output = theme('table', $header, $rows);
$output .= '<br /><br />';
$output .= l("Add a New Block", "admin/settings/gadsense/add");
return $output;
}
This will form the page that you see here (by default):

The second page will perform the first half of our Drupal "magic". We're going to build the page to create our blocks. First we need to draw the form. Again, I'm going to assume you're competent with Drupal module building and just supply the code:
function create_ads_page() {
$form = array();
$sizes = array('120x600', '160x600', '728x90', '468x60', '300x250');
$types = array('text', 'image', 'text/image');
$form['ad_size'] = array('#type' => 'select', '#title' => 'Ad size', '#options' => $sizes);
$form['ad_type'] = array('#type' => 'select', '#title' => 'Ad type', '#options' => $types);
$form['submit'] = array('#type' => 'submit', '#value' => 'Submit');
return drupal_get_form('create_ad', $form);
}
Which will show the following page:

When submitted, the following code is executed.
function create_ad_submit($form_id, $form_values) {
$ad_sizes = array('120x600', '160x600', '728x90', '468x60', '300x250');
$width = 0;
$height = 0;
$type = '';
//check for valid sizes
foreach ($ad_sizes as $key => $value) {
if ($form_values['ad_size'] == $key) {
$dimensions = explode('x', $value);
$width = $dimensions[0];
$height = $dimensions[1];
}
}
if (intval($form_values['ad_type']) <= 2) {
$types = array('text', 'image', 'text/image');
$type = $types[$form_values['ad_type']];
}
if ($width == 0 || $height == 0 || $type == '') {
drupal_not_found();
}
else {
db_query("
INSERT INTO {gadsense_blocks}
(width, height, type)
VALUES
(%d, %d, '%s')",
$width, $height, $type);
drupal_set_message('Ad block created');
drupal_goto('admin/settings/gadsense/list');
}
}
After splitting the ad size selection into $width and $height variables and grabbing the ad $type, we insert a new record into our gadsense_blocks table. As shown above, this will create give it a unique bid value, which we'll reference later.
I'll create a few different blocks, and now our main gadsense page will be populated. Like this:

Now, the last thing we need to do is implement the block hook for both the list and view operations.
function gadsense_block($op='list', $delta=0) {
if ($op == "list") {
$result = db_query('
SELECT
*
FROM {gadsense_blocks}
ORDER BY width + " x " + height ASC');
$rows = array();
while ($field = db_fetch_object($result)) {
$block[$field->bid]["info"] = t('Google AdSense - '.$field->width.'x'.$field->height);
}
return $block;
}
else if ($op == 'view') {
$result = db_fetch_object(db_query('
SELECT
*
FROM {gadsense_blocks}
WHERE bid = %d',
$delta));
if ($result->bid > 0) {
$block['subject'] = 'Advertisement';
$block['content'] =
'
<script>
<!--
google_ad_client = "'.variable_get('google_adsense_code', '').'";
google_ad_width = "'.$result->width.'";
google_ad_height = "'.$result->height.'";
google_ad_format = "'.$result->width.'x'.$result->height.'_as";
google_ad_type = "'.$result->type.'";
//-->
</script>
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
';
}
if ($block)
return $block;
}
}
In the list operation, we select the gadsense blocks from out of the database and use them to populate the global block list. This is the "magic" behind our module.
Normally modules use hardcoded integers for indexes in the block hook, but as long as they are unique, Drupal couldn't care less what the index values actually are. Since we use the auto incrementing primary key column from our MySql database, we know the values will be unique.
Now, our /admin/block list will contain blocks that mirror our gadsense list:

The other operation we implement in our block hook is the view operation. This is what draws the block content - in our case, a Google AdSense ad.
The unique bid value that we used to index our block in the list operation is handed to us in the view operation. Then we just lookup the information about the ad's width, height and type and output the javascript that is required to call Google's script.
So, if we check the box to add the 468x60 ad block that we created, we'll see that it appears like this:

The Enhancements...
The finished version of the module that I created has numerous enhancements that you can easily add yourself, such as the ability to edit the block settings, delete a block, clone a block, change the AdSense tracking code, add an AdSense channel, etc.
Additionally, you can tie in to any setting that Google offers on the AdSense platform. Specifically, my module offers a color wheel to set the text color, border color, and other layout specific features.
The Google AdSense module is just one simple use for this concept. Dynamic blocks can be used in millions of situations such as allowing users to create their own blocks for display or share with their friends, index the blocks using the current date and show Holiday specific blocks, automatically import affiliate links and create dynamic blocks and many others. Once you start experimenting with it, I'm sure you'll come up with all sorts of unique ideas!
For this example, I'm going to build a simple Google AdSense module that will allow the creation of an infinite number of blocks.
The Assumptions
1) This module was built using Drupal 4.7. I'm not familiar enough with other Drupal environments to assure that this will work, but if anybody tries testing it on other Drupal versions - please let me know so I can update this blog entry!
2) I'm going to assume that the reader has built a basic Drupal module before and does not need a basic explanation of hooks.
3) I'm going to assume that there was previously a variable_set('google_adsense_code', 'pub-XXXXXXXXXXXX-XXXX') call in some form that will allow the site administrator to set their personal AdSense code.
The Database
Now, let's setup a basic database schema for this module. (Note, this was executed on MySql 5.0.22)
CREATE TABLE IF NOT EXISTS gadsense_blocks (
bid INT AUTO_INCREMENT PRIMARY KEY,
width INT,
height INT,
type VARCHAR(32)
);
The above would either be executed directly on the database server or embedded in a Drupal module .install file to create the table the first time the module is installed.
The above table is very simple with an auto-incrementing bid, the width and height of our target ad, and a simple text field we'll use to store whether our ad is a text or image ad (or both).
The Core Module Hooks
As I said above, I'm going to assume the reader has built a basic Drupal module before and can understand the below without explanation.
function gadsense_help($section = 'admin/help#gadsense') {
switch ($section) {
case 'admin/modules#description':
return t('Creates an area for Google AdSense support.');
}
}
function gadsense_perm() {
return array('administer adsense');
}
function gadsense_menu($may_cache) {
$items = array();
$items[] = array(
'path' => 'admin/settings/gadsense/list',
'title' => t('Google AdSense Ads'),
'callback' => 'list_ads_page',
'access' => user_access('administer adsense'),
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'admin/settings/gadsense/add',
'title' => t('Google AdSense Ads'),
'callback' => 'create_ads_page',
'access' => user_access('administer adsense'),
'type' => MENU_CALLBACK,
);
return $items;
}
The Administrator Pages
Now that we've got our core module created, we can get to work! We're going to create two pages for basic administration. The first page, the main admin page, will list all the blocks we've created so far and offer a link to create a new one.
function list_ads_page() {
$result = db_query('SELECT * FROM {gadsense_blocks} ORDER BY width + " x " + height ASC');
$rows = array();
while ($field = db_fetch_object($result)) {
$rows[] = array($field->bid, $field->width, $field->height, $field->type);
}
if (count($rows) == 0) {
$rows[] = array(array('data' => t('No ad blocks have been defined.'), 'colspan' => '6'));
}
$header = array(t('id'), t('width'), t('height'), t('type'));
$output = theme('table', $header, $rows);
$output .= '<br /><br />';
$output .= l("Add a New Block", "admin/settings/gadsense/add");
return $output;
}
This will form the page that you see here (by default):

The second page will perform the first half of our Drupal "magic". We're going to build the page to create our blocks. First we need to draw the form. Again, I'm going to assume you're competent with Drupal module building and just supply the code:
function create_ads_page() {
$form = array();
$sizes = array('120x600', '160x600', '728x90', '468x60', '300x250');
$types = array('text', 'image', 'text/image');
$form['ad_size'] = array('#type' => 'select', '#title' => 'Ad size', '#options' => $sizes);
$form['ad_type'] = array('#type' => 'select', '#title' => 'Ad type', '#options' => $types);
$form['submit'] = array('#type' => 'submit', '#value' => 'Submit');
return drupal_get_form('create_ad', $form);
}
Which will show the following page:

When submitted, the following code is executed.
function create_ad_submit($form_id, $form_values) {
$ad_sizes = array('120x600', '160x600', '728x90', '468x60', '300x250');
$width = 0;
$height = 0;
$type = '';
//check for valid sizes
foreach ($ad_sizes as $key => $value) {
if ($form_values['ad_size'] == $key) {
$dimensions = explode('x', $value);
$width = $dimensions[0];
$height = $dimensions[1];
}
}
if (intval($form_values['ad_type']) <= 2) {
$types = array('text', 'image', 'text/image');
$type = $types[$form_values['ad_type']];
}
if ($width == 0 || $height == 0 || $type == '') {
drupal_not_found();
}
else {
db_query("
INSERT INTO {gadsense_blocks}
(width, height, type)
VALUES
(%d, %d, '%s')",
$width, $height, $type);
drupal_set_message('Ad block created');
drupal_goto('admin/settings/gadsense/list');
}
}
After splitting the ad size selection into $width and $height variables and grabbing the ad $type, we insert a new record into our gadsense_blocks table. As shown above, this will create give it a unique bid value, which we'll reference later.
I'll create a few different blocks, and now our main gadsense page will be populated. Like this:

Now, the last thing we need to do is implement the block hook for both the list and view operations.
function gadsense_block($op='list', $delta=0) {
if ($op == "list") {
$result = db_query('
SELECT
*
FROM {gadsense_blocks}
ORDER BY width + " x " + height ASC');
$rows = array();
while ($field = db_fetch_object($result)) {
$block[$field->bid]["info"] = t('Google AdSense - '.$field->width.'x'.$field->height);
}
return $block;
}
else if ($op == 'view') {
$result = db_fetch_object(db_query('
SELECT
*
FROM {gadsense_blocks}
WHERE bid = %d',
$delta));
if ($result->bid > 0) {
$block['subject'] = 'Advertisement';
$block['content'] =
'
<script>
<!--
google_ad_client = "'.variable_get('google_adsense_code', '').'";
google_ad_width = "'.$result->width.'";
google_ad_height = "'.$result->height.'";
google_ad_format = "'.$result->width.'x'.$result->height.'_as";
google_ad_type = "'.$result->type.'";
//-->
</script>
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
';
}
if ($block)
return $block;
}
}
In the list operation, we select the gadsense blocks from out of the database and use them to populate the global block list. This is the "magic" behind our module.
Normally modules use hardcoded integers for indexes in the block hook, but as long as they are unique, Drupal couldn't care less what the index values actually are. Since we use the auto incrementing primary key column from our MySql database, we know the values will be unique.
Now, our /admin/block list will contain blocks that mirror our gadsense list:

The other operation we implement in our block hook is the view operation. This is what draws the block content - in our case, a Google AdSense ad.
The unique bid value that we used to index our block in the list operation is handed to us in the view operation. Then we just lookup the information about the ad's width, height and type and output the javascript that is required to call Google's script.
So, if we check the box to add the 468x60 ad block that we created, we'll see that it appears like this:

The Enhancements...
The finished version of the module that I created has numerous enhancements that you can easily add yourself, such as the ability to edit the block settings, delete a block, clone a block, change the AdSense tracking code, add an AdSense channel, etc.
Additionally, you can tie in to any setting that Google offers on the AdSense platform. Specifically, my module offers a color wheel to set the text color, border color, and other layout specific features.
The Google AdSense module is just one simple use for this concept. Dynamic blocks can be used in millions of situations such as allowing users to create their own blocks for display or share with their friends, index the blocks using the current date and show Holiday specific blocks, automatically import affiliate links and create dynamic blocks and many others. Once you start experimenting with it, I'm sure you'll come up with all sorts of unique ideas!
0 comments
|
page 1 of 1
|