📜 ⬆️ ⬇️

Creating a module for Drupal 7. Part 1

Foreword


I recently received a task to learn how to write modules for Drupal 7. I started scouring in search of various articles and manuals, and I realized that there are quite a few of them, and the information is very minimal. Official documentation also did not give me comprehensive information. Hardly collected some information from several sources and decided to share it with you.

I will not tell you what Drupal is, its structure. The article is designed for those who know the minimum principle of the hooks and display Drupal. All this can be read on the official website of the API Drupal .

Begin development of the module


I will show how to create a module that allows you to add RSS feeds and display their content on a separate page.

First you need to select the "short name" of the module. It will be used in all files and function names of the module. It must begin only with a letter and contain only lowercase characters and the "_" character. I called my module "rss_feeds".
')
Create a folder: sites / all / modules / rss_feeds (all new modules that you want to add must be in this folder). In it we create a file rss_feeds.info , which contains META-information about our module:

name = RSS Feeds
description = Makes a compact page to navigate on RSS feeds.
package = "RSS"
core = 7.x
version = "7.x-1.0"
configure = admin / config / content / rss_feeds
files [] = rss_feeds.module




There are some more fields you can read about here .

Our module will use a database in which it will store data about RSS (its name and URL). Create the rss_feeds.install file:

<?php function rss_feeds_uninstall() { cache_clear_all('rss_feeds', 'cache', TRUE); drupal_uninstall_schema('rssfeeds'); menu_rebuild(); } function rss_feeds_schema() { $schema['rssfeeds'] = array( 'fields' => array( 'id' => array('type' => 'serial', 'size'=>'normal', 'not null' => TRUE), 'name' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE), 'url' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE), 'created_at' => array('type' => 'int', 'not null' => TRUE), 'updated_at' => array('type' => 'int', 'not null' => TRUE), ), 'primary key' => array('id') ); return $schema; } 


In the schema () hook, we create the table we need. The uninstall () hook clears the cache, deletes the table and rebuilds the menu when removing a module (closing the "?>" Tag in Drupal is not to be set).

Creating a .module File


Next, create the module file itself - rss_feeds.module :

 <?php function rss_feeds_block_info() { $blocks['rss_feeds'] = array( 'info' => t('RSS Feeds'), 'cache' => DRUPAL_CACHE_PER_ROLE, //   ); return $blocks; } 


In this hook we describe the blocks used. We will only have one and be called 'rss_feeds' . 'info' is brief information about the block, and 'cache' is the caching rule. For details, see hook_block_info () .

Next, we describe hook_menu () :

 function rss_feeds_menu() { $items = array(); $items['admin/config/content/rss_feeds'] = array( 'title' => 'RSS Feeds', 'description' => 'Configure the RSS feeds list.', 'page callback' => 'rss_list', 'access arguments' => array('administer site configuration'), ); $items['admin/config/content/rss_feeds/list'] = array( 'title' => 'RSS feeds list', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => 1, ); // rss add form $items['admin/config/content/rss_feeds/add'] = array( 'title' => 'Add rss', 'page callback' => 'drupal_get_form', 'page arguments' => array('rss_feeds_form'), 'access arguments' => array('administer site configuration'), 'type' => MENU_LOCAL_TASK, 'weight' => 2, ); // rss edit form $items['admin/config/content/rss_feeds/%rss/edit'] = array( 'title' => 'Edit RSS', 'page callback' => 'drupal_get_form', 'page arguments' => array('rss_feeds_form', 4), 'access arguments' => array('administer site configuration'), 'type' => MENU_CALLBACK, ); // rss delete $items['admin/config/content/rss_feeds/%rss/delete'] = array( 'title' => 'Delete RSS', 'page callback' => 'rss_feeds_delete', 'page arguments' => array(4), 'access arguments' => array('administer site configuration'), 'type' => MENU_CALLBACK, ); $items['rss_feeds'] = array( 'title' => 'RSS feeds', 'page callback' => '_rss_feeds_page', 'access arguments' => array('access content'), ); $items['rss_feeds/%rss/items'] = array( 'title' => 'RSS feed content', 'page callback' => 'rss_content', 'page arguments' => array(1), 'access callback' => TRUE, 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); return $items; } 


In items, we specify the URL, its title (title), description (description), processing function (page callback), passed arguments (page arguments), access parameters (access arguments), type (type) and "weight" (weight). I would like to highlight page callback - drupal_get_from . This function takes a form as a parameter and outputs it. In “page arguments => array (1)” , we pass the 1st element of the URL as an argument (counting from 0).

Read more about hook_menu () .

Next, we describe the form through which we will add and edit our RSS feeds:

 function rss_feeds_form($form, &$form_state, $rss = null) { $form['name'] = array( '#title' => t('RSS feed name.'), '#description' => t('Insert RSS shortcut name'), '#type' => 'textfield', '#default_value' => $rss ? $rss['name'] : '', '#required' => true, ); $form['url'] = array( '#title' => t('RSS feed url.'), '#description' => t('Insert RSS url'), '#type' => 'textfield', '#default_value' => $rss ? $rss['url'] : '', '#required' => true, ); $form['submit'] = array( '#type' => 'submit', '#value' => $rss ? t('Save') : t('Add'), ); if ($rss) { $form['id'] = array( '#type' => 'value', '#value' => $rss['id'], ); } return $form; } 


As you can see, if we pass the $ rss parameter into the form, the form will understand, add a new tape, or edit an existing one. The function t () (translate), allows you to localize the module (I will discuss this later). Learn more about hook_form () .

Next, you need to describe hook_form_validate () , which will process the data entered into the form:

 function rss_feeds_form_validate($form, &$form_state) { $url = $form_state['values']['url']; if (fopen($url, "r")) { libxml_use_internal_errors(true); $rss_feed = simplexml_load_file($url); if (empty($rss_feed)) { form_set_error('url', t('URL is invalid!')); } } else { form_set_error('url', t('URL is invalid!')); } } 


First we get the data from $ form_state , and then we process it. If something is wrong, the standard form_set_error () is thrown out, in which we specify the name of the form field and the message.

When the form is validated, hook_form_submit () is called :

 function rss_feeds_form_submit($form, &$form_state) { $rss = array( 'name' => $form_state['values']['name'], 'url' => $form_state['values']['url'], 'created_at' => time(), 'updated_at' => time(), ); // save edit data if (isset($form_state['values']['id'])) { $rss['id'] = $form_state['values']['id']; drupal_write_record('rssfeeds', $rss, 'id'); drupal_set_message(t('RSS Feed saved!')); } // add new data else { drupal_write_record('rssfeeds', $rss); drupal_set_message(t('RSS Feed added!')); } drupal_goto('admin/config/content/rss_feeds'); } 


I think everything is clear. drupal_write_record () makes an entry in the database, drupal_set_message () shows the system message, drupal_goto () flips to the specified URL.

In order for a form to accept not just a tape ID ( $ rss ), but its data, you need to define hool_load () :

 function rss_load($id) { $rss = db_select('rssfeeds', 'n') ->fields('n', array('id', 'name', 'url', 'created_at', 'updated_at')) ->condition('n.id', $id) ->execute()->fetchAssoc(); return $rss; } 


Now, as $ rss , the form will be passed not a number, but an object with data.

Next, you should implement the function of displaying the page where we can edit our RSS feeds table - rss_list () :

 function rss_list() { $header = array( array('data' => t('Name')), array('data' => t('URL')), array('data' => t('Actions')) ); $rss = db_select('rssfeeds', 'n') ->fields('n', array('id', 'name', 'url')) ->execute()->fetchAll(); $row = array(); if ($rss) { foreach ($rss as $rss_feed) { $actions = array( l(t('edit'), 'admin/config/content/rss_feeds/' . $rss_feed->id . '/edit'), l(t('delete'), 'admin/config/content/rss_feeds/' . $rss_feed->id . '/delete'), ); $row [] = array( array('data' => $rss_feed->name), array('data' => $rss_feed->url), array('data' => implode(' | ', $actions)), ); } } return theme('table', array( 'header' => $header, 'rows' => $row, )); } 


Function l () (link) - creates a link. But the main function is theme () . You will meet with her separately, because It is very extensive and has many useful options.

Below, we will create a function for deleting the rss_feeds_delete () entries:

 function rss_feeds_delete($rss) { $rss_deleted = db_delete('rssfeeds') ->condition('id', $rss['id']) ->execute(); drupal_set_message(t('RSS Feed deleted!')); drupal_goto('admin/config/content/rss_feeds'); } 


No comments.

For convenience, I added a function that will return data, depending on the parameter (block or page). Here are its contents:

 function rss_contents($display) { $query = db_select('rssfeeds', 'n') ->fields('n', array('id', 'name', 'url')) ->orderBy('name', 'DESC'); if ($display == 'block') { $query->range(0, 5); } return $query->execute(); } 


If we specify 'block' as a parameter, we will display only 5 entries.

Next, we implement the output hook of the block - hook_block_view () :

 function rss_feeds_block_view($delta = '') { $blocks = array(); switch ($delta) { case 'rss_feeds': $select = db_select('rssfeeds', 'tc'); $select->addField('tc', 'name'); $select->addField('tc', 'url'); $entries = $select->execute()->fetchAll(); $blocks['subject'] = t('List of URLs'); $blocks['content'] = theme('rssfeeds_block', array('urls' => $entries)); } return $blocks; } 


This unit will be available in the administration panel.

Now we will write the function of displaying the page, on which there will be a list of tapes, when clicked, the content will be displayed (in a new tab):

 function _rss_feeds_page() { drupal_set_title(t('RSS Feeds')); $result = rss_contents('page')->fetchAll(); if (!$result) { $page_array['rss_feeds_arguments'] = array( '#title' => t('RSS Feeds page'), '#markup' => t('No RSS feeds available'), ); return $page_array; } else { $page_array = theme('rssfeeds_page', array('urls' => $result)); return $page_array; } } 


... and the content display page:

 function rss_content($rss) { $url = $rss['url']; libxml_use_internal_errors(true); $rss_feed = simplexml_load_file($url); if (!empty($rss_feed)) { drupal_set_title($rss_feed->channel->title); $page_array = theme('rssfeeds_content', array('items' => $rss_feed)); return $page_array; } else { $page_array['rss_feeds_arguments'] = array( '#title' => t('All posts from the last week'), '#markup' => t('No posts available.'), ); return $page_array; } } 


You may have noticed, but the pages will not be displayed. I specified the 'rssfeeds_block' and 'rssfeeds_content' parameters in the theme () function. These are the templates I created. We make hook_theme () to initialize them:

 function rss_feeds_theme() { return array( 'rssfeeds_block' => array( 'variables' => array( 'urls' => NULL ), 'template' => 'rssfeeds-block', ), 'rssfeeds_page' => array( 'variables' => array( 'urls' => NULL ), 'template' => 'rssfeeds-page', ), 'rssfeeds_content' => array( 'variables' => array( 'items' => NULL ), 'template' => 'rssfeeds-content', ) ); } 


In the 'template' field specify the name of the template.

Now create the template files themselves. Namely: rssfeeds-block.tpl.php , rssfeeds-page.tpl.php and rssfeeds-content.tpl.php .

Content of the first file:

 <div id="rssfeeds-pager"> <?php foreach ($urls as $url): ?> <span> <a target="_blank" href="http://<?php echo $url->url; ?>"><?php echo $url->url; ?></a><br> </span> <?php endforeach; ?> </div> 


... second:

 <div id="rssfeeds-pager"> <?php foreach ($urls as $url): ?> <span> <a target="_blank" href="rss_feeds/<?php echo $url->id; ?>/items"><?php echo $url->name; ?></a><br> </span> <?php endforeach; ?> </div> 


... and third, respectively:

 <?php foreach ($items->channel->item as $item): ?> <span class="title"><a href="<?php echo $item->link; ?>"><?php echo $item->title; ?></a></span><br><br> <?php echo $item->description; ?><br><br><?php echo $item->pubDate; ?> <hr><br><br> <?php endforeach; ?> 


Now our module will function. However, you probably noticed that classes are defined for elements. Now we attach a CSS style file to our module. To do this, add this line to the .info file:

stylesheets [all] [] = main.css

And create the main.css file:

 .title { font-size: 16px; text-shadow: 0px 0px 1px black; font-weight: bold; } .title a { text-decoration: none; color: #B81007; } .title a:hover { text-decoration: underline; } 


Conclusion


That's actually the finished module. If you like this article, I will write how to add js-files to the modules and make localization files. I hope she helps someone.

Thanks for attention!

PS



Wrote the second part .

Source: https://habr.com/ru/post/200340/


All Articles