Jun 17 2016
Jun 17
This is the next steps in getting my module working in Drupal 8. In the previous post, I got the block setup working, but it's just a generic "Hello World!" output. The block gets the most recent entries from a database table, so my next step is getting the database setup.

Databases

This doesn't seem to have changed from Drupal 7 to 8. You basically copy over the .install file. The hook_schema() takes care of it. BTW, one thing that is different is if you need to uninstall/reinstall the modules, you just need to drush pm-uninstall MODULE vs. drush dis MODULE ; drush pm-uninstall MODULE.

Once I had the database tables in place, I dumped my database tables from D7 and imported them into D8. NOTE: I probably need to either codify this (perhaps there's a way to hook into the migration system?) or keep notes about what tables to dump/import once everything's in place.

Now I needed to update my block to query the most recent entries in the table. db_query() is still supported in D8, however it looks like it's going away for D9, so if I wanted to future-proof my module even more, I could convert it to the new injection technique. So I created a storage class in my src folder. I downloaded the examples module and looked at the dbtng_example submodule and its DbtngExampleStorage class. I also found this answer on StackOverflow and the example posted in the select doc helpful. I ended up with a hybrid approach:

So a few things there. First, my post_date field was a legacy datetime field, so I had to convert the current time from a timestamp to the date format that mysql expected. format_date() is deprecated, so they recommend using Drupal::service('date.formatter'). Also, I make my __construct() method a little dynamic so that I don't have to pass in a connection, but it can support it if it is passed in.

Then my block build() method uses my storage class and calls the get_reports() method, passing in the block's configuration array. First, I add use Drupal\gated_content\GCStorage; to the top of my block plugin. Then my build() looks like this:

  public function build() {
    $storage = new GCStorage;
    $reports = $storage->get_reports($this->configuration);
    $build = array();
    kint($reports, $build);
    return $build;
  }

Block View

So now that my block has the right set of reports to show, I need to show them. This takes me to the whole theming and templates stuff. The D7 version called theme() directly and there was a hook_theme and I had a template. The end result was a simple
and foreach report, a
and l(); call to link to the report. Kind of reminds me of item_list a bit, so I think I'll start there.

Ok, it looks like item_list looks about the same. My render array just needs to '#theme' => 'item_list'. But l() is gone. This comment pointed me in the right direction. So now it looks like this:

    $items = array();
    foreach ($reports as $report) {
      $url = Url::fromRoute('');
      $items[] = \Drupal::l(t($report['title']), $url);
    }
    $build = array(
      'report_list' => array(
        '#theme' => 'item_list',
        '#items' => $items,
        '#attributes' => array(
          'class' => 'report-block',
        ),
      ),
    );

Success!

Of course, these all link to just the homepage, which isn't very helpful.

Menu

So now I'm looking down another rabbit hole. The URL to my report is reports/[ID#]. But I use this module on separate domains, so the reports part is configurable. So I need to get that configuration setting to get the first bit of the URL. Actually, I think I can skip that since we'll be doing something different in our migration plans, so I can skip that part of the module. [postnote: if I do end up needing this, it looks like this shows how]

Also, I had this module all setup with pathauto to get a nice SEO-friendly public URL. Ok, so I need to setup the menu routing so the user can get to /gated_content and /gated_content/[ID#] and /gated_content/[ID#]/download. And I need to setup pathauto again.

First, all of those URL's were setup in D7 with type of MENU_CALLBACK, so according to this doc, I need to set them up in a .routing.yml file. This wasn't something DMU setup for me, so I did this from scratch. This was a great doc that showed some examples going from D7 to D8.

My first question is that I was familiar with named placeholders and how the name would be used to call a NAME_load() function to put together the argument that gets passed into the callback. But these examples are using book, which uses node and entity, so I need something that will use my own data type.

Stuff for the next post!

Jun 15 2016
Jun 15
We are looking into porting our site to Drupal 8 and we have over 30 custom modules, so it's a pretty big undertaking. I thought I'd blog about the adventures in the hopes of helping others tackle porting to D8 as well as notes for myself.

Back in April, I took one of our sites and used Drupal Upgrade module to get it moved into D8, following these instructions. I really haven't touched it since then, so I can't really remember how that went. So I just blew the dust off and upgraded from 8.0 to 8.1 in the process. One of the first things I noticed is that comments were turned off, so I had to navigate into the various content types and edit them and edit the comments field to change it from Closed to Open.

Then I was looking through our custom modules and trying to figure out where to start first. Some of our stuff builds on top of each other, so I need to look at the hierarchy to determine what is something that isn't dependent on other things.

One of my first steps was to create a custom modules folder and copy my D7 custom module into that. I then copied the folder as a backup. Then I used the Drupal Module Upgrader (DMU) to generate an upgrade info report as well as attempt the upgrade process. Then I renamed that folder to append -auto and then I created a new folder where I will start work in earnest.

cd /path/to/drupal8 ;
mkdir -p modules/custom/gated_content ;
cp -r /path/to/drupal7/sites/all/modules/custom/gated_content modules/custom/gated_content ;
cp -r /path/to/drupal7/sites/all/modules/custom/gated_content modules/custom/gated_content-orig ;
drush dmu-analyze gated_content --path=modules/custom/gated_content ;
drush dmu-upgrade gated_content --path=modules/custom/gated_content ;
mv modules/custom/gated_content modules/custom/gated_content-auto ;
mkdir modules/custom/gated_content ;

So my first custom module handles what we call "gated content," which is a collection of PDF files that our website users can request to download, which takes them to a request form and after they fill it out, it emails them a link to the PDF.

The module also has a block that shows the most recent gated content entries, which we include in our sidebar.

So I just wanted to start with the block and the block's settings.

The Block

One of the reasons I wanted to start from scratch is that this module is pretty big with lots of code that needs addressing to work in D8 and I'd like to incrementally get stuff working without having all the old stuff in there. So I copied the module's .info.yml and .permissions.yml files into my blank folder to start. No .module file. At least for now.
Blocks have a different way of doing things. You create a plugin. You don't need to point to your plugin through some .yml file. You create a src/Plugin/Block folder in your module and then create a php file for your plugin class. The filename needs to match PSR-4 specifications, which is the magic that autoloads all of this. So I called mine GCListBlock.php. One of my first lessons is that my namespace has to match the module name. My module name is gated_content and I initially used gatedcontent, which resulted in the block showing up in the list, but once you tried to place it in a region, it would result in an error.
Another odd thing is that the phpdoc is very specific with double quotes vs. single quotes. Use double quotes.

Using single quotes resulted in this error:

Doctrine\Common\Annotations\AnnotationException: [Syntax Error] Expected PlainValue, got ''' at position 18 in class Drupal\gated_content\Plugin\Block\GCListBlock. in Doctrine\Common\Annotations\AnnotationException::syntaxError() (line 42 of /Users/jason/Sites/devdesktop/fnmd8-dev/docroot/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php).

Another hiccup I ran across is I had t() calls through my block code that I had to change to $this->t().
I think there was some sort of 8.1 update, which wasn't reflected in the Blocks doc I was pointed to from the DMU report (I added a comment), that says $form_state is now a FormStateInterface. This also means you need to update accessing the form_state values to use $form_state->getValue('FORMFIELDNAME').

Finally, blocks don't just show up in the list of blocks on the blocks page like you might expect from Drupal 6/7 days. You have to click the Place Block button to pull up a list of available blocks and you should see it there. This is pretty neat because you can add a block more than once to a region or across multiple regions. I'm sure there's some way to differentiate the build based on its own order and region, but I don't have to worry about that for now.

The Settings

I initially thought I needed to create a settings yml file, but actually, since the settings aren't used outside of the block code, they can be all specified and used in the block's class. You can provide the defaultConfiguration() method to specify the default values (return an array of keys to values).

Bonus: Devel Module

One of the hiccups I faced was how to get the devel and dpm() calls working like I was used to in D7. One of the cool things I undercovered while getting devel setup is the webprofiler submodule, which adds a nifty toolbar at the bottom of the page with lots of development information and options.


I couldn't get dpm() (or dsm()) calls to show anything, so I stumbled across the kint submodule, which looks even better. You basically enable it and then use kint() vs. dpm(). One bonus is that kint() allows for multiple variables in the same call. It outputted the variable in a narrow region, but there's right arrow you can click on to open it in a new tab. And there's a useful stack trace beneath the output. One other thing I read is that dpm() doesn't have access to protected data, but kint() does.

Also, if you're not seeing output from either dpm() or kint() calls, try doing a cache-rebuild (drush cr). If that fixes it, you may want to setup local development configuration overrides so you don't have to rebuild manually every time.
Jun 16 2014
Jun 16

How to Build a Drupal 8 Module

In the first installment of this article series on Drupal 8 module development we started with the basics. We’ve seen what files were needed to let Drupal know about our module, how the routing process works and how to create menu links programatically as configuration.

In this tutorial we are going to go a bit further with our sandbox module found in this repository and look at two new important pieces of functionality: blocks and forms. To this end, we will create a custom block that returns some configurable text. After that, we will create a simple form used to print out user submitted values to the screen.

Drupal 8 blocks

A cool new change to the block API in D8 has been a switch to making blocks more prominent, by making them plugins (a brand new concept). What this means is that they are reusable pieces of functionality (under the hood) as you can now create a block in the UI and reuse it across the site – you are no longer limited to using a block only one time.

Let’s go ahead and create a simple block type that prints to the screen Hello World! by default. All we need to work with is one class file located in the src/Plugin/Block folder of our module’s root directory. Let’s call our new block type DemoBlock, and naturally it needs to reside in a file called DemoBlock.php. Inside this file, we can start with the following:

<?php

namespace Drupal\demo\Plugin\Block;

use Drupal\block\BlockBase;
use Drupal\Core\Session\AccountInterface;

/**
 * Provides a 'Demo' block.
 *
 * @Block(
 *   id = "demo_block",
 *   admin_label = @Translation("Demo block"),
 * )
 */

class DemoBlock extends BlockBase {
  
  /**
   * {@inheritdoc}
   */
  public function build() {    
    return array(
      '#markup' => $this->t('Hello World!'),
    );
  }
  
  /**
   * {@inheritdoc}
   */
  public function access(AccountInterface $account) {
    return $account->hasPermission('access content');
  }  
  
}

Like with all other class files we start by namespacing our class. Then we use the BlockBase class so that we can extend it, as well as the AccountInterface class so that we can get access to the currently logged in user. Then follows something you definitely have not seen in Drupal 7: annotations.

Annotations are a PHP discovery tool located in the comment block of the same file as the class definition. Using these annotations we let Drupal know that we want to register a new block type (@Block) with the id of demo_block and the admin_label of Demo block (passed through the translation system).

Next, we extend the BlockBase class into our own DemoBlock, inside of which we implement two methods (the most common ones you’ll implement). The build() method is the most important as it returns a renderable array the block will print out. The access() method controls access rights for viewing this block. The parameter passed to it is an instance of the AccountInterface class which will be in this case the current user.

Another interesting thing to note is that we are no longer using the t() function globally for translation but we reference the t() method implemented in the class parent.

And that’s it, you can clear the caches and go to the Block layout configuration page. The cool thing is that you have the block types on the right (that you can filter through) and you can place one or more blocks of those types to various regions on the site.

Drupal 8 block configuration

Now that we’ve seen how to create a new block type to use from the UI, let’s tap further into the API and add a configuration form for it. We will make it so that you can edit the block, specify a name in a textfield and then the block will say hello to that name rather than the world.

First, we’ll need to define the form that contains our textfield. So inside our DemoBlock class we can add a new method called blockForm():

/**
 * {@inheritdoc}
 */
public function blockForm($form, &$form_state) {
  
  $form = parent::blockForm($form, $form_state);
  
  $config = $this->getConfiguration();

  $form['demo_block_settings'] = array(
    '#type' => 'textfield',
    '#title' => $this->t('Who'),
    '#description' => $this->t('Who do you want to say hello to?'),
    '#default_value' => isset($config['demo_block_settings']) ? $config['demo_block_settings'] : '',
  );
  
  return $form;
}

This form API implementation should look very familiar from Drupal 7. There are, however, some new things going on here. First, we retrieve the $form array from the parent class (so we are building on the existing form by adding our own field). Standard OOP stuff. Then, we retrieve and store the configuration for this block. The BlockBase class defines the getConfiguration() method that does this for us. And we place the demo_block_settings value as the #default_value in case it has been set already.

Next, it’s time for the submit handler of this form that will process the value of our field and store it in the block’s configuration:

/**
* {@inheritdoc}
*/
public function blockSubmit($form, &$form_state) {
 
 $this->setConfigurationValue('demo_block_settings', $form_state['values']['demo_block_settings']);
 
} 

This method also goes inside the DemoBlock class and all it does is save the value of the demo_block_settings field as a new item in the block’s configuration (keyed by the same name for consistency).

Lastly, we need to adapt our build() method to include the name to say hello to:

 /**
 * {@inheritdoc}
 */
public function build() {
  
  $config = $this->getConfiguration();
  
  if (isset($config['demo_block_settings']) && !empty($config['demo_block_settings'])) {
    $name = $config['demo_block_settings'];
  }
  else {
    $name = $this->t('to no one');
  }
  
  return array(
    '#markup' => $this->t('Hello @name!', array('@name' => $name)),
  );  
}

By now, this should look fairly easy. We are retrieving the block’s configuration and if the value of our field is set, we use it for the printed statement. If not, use use a generic one. You can clear the cache and test it out by editing the block you assigned to a region and add a name to say hello to. One thing to keep in mind is that you are still responsible for sanitizing user input upon printing to the screen. I have not included these steps for brevity.

Drupal 8 forms

The last thing we are going to explore in this tutorial is how to create a simple form. Due to space limitations, I will not cover the configuration management aspect of it (storing configuration values submitted through forms). Rather, I will illustrate a simple form definition, the values submitted being simply printed on the screen to show that it works.

In Drupal 8, form definition functions are all grouped together inside a class. So let’s define our simple DemoForm class inside src/Form/DemoForm.php:

<?php

/**
 * @file
 * Contains \Drupal\demo\Form\DemoForm.
 */

namespace Drupal\demo\Form;

use Drupal\Core\Form\FormBase;

class DemoForm extends FormBase {
  
  /**
   * {@inheritdoc}.
   */
  public function getFormId() {
    return 'demo_form';
  }
  
  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, array &$form_state) {
    
    $form['email'] = array(
      '#type' => 'email',
      '#title' => $this->t('Your .com email address.')
    );
    $form['show'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    );
    
    return $form;
  }
  
  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, array &$form_state) {
    
    if (strpos($form_state['values']['email'], '.com') === FALSE ) {
      $this->setFormError('email', $form_state, $this->t('This is not a .com email address.'));
    } 
  }
  
  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, array &$form_state) {
    
    drupal_set_message($this->t('Your email address is @email', array('@email' => $form_state['values']['email'])));
  }
  
}

Apart from the OOP side of it, everything should look very familiar to Drupal 7. The Form API has remained pretty much unchanged (except for the addition of some new form elements and this class encapsulation). So what happens above?

First, we namespace the class and use the core FormBase class so we can extend it with our own DemoForm class. Then we implement 4 methods, 3 of which should look very familiar. The getFormId() method is new and mandatory, used simply to return the machine name of the form. The buildForm() method is again mandatory and it builds up the form. How? Just like you are used to from Drupal 7. The validateForm() method is optional and its purpose should also be quite clear from D7. And finally, the submitForm() method does the submission handling. Very logical and organised.

So what are we trying to achieve with this form? We have an email field (a new form element in Drupal 8) we want users to fill out. By default, Drupal checks whether the value input is in fact an email address. But in our validation function we make sure it is a .com email address and if not, we set a form error on the field. Lastly, the submit handler just prints a message on the page.

One last thing we need to do in order to use this form is provide a route for it. So edit the demo.routing.yml file and add the following:

demo.form:
  path: '/demo/form'
  defaults:
    _form: '\Drupal\demo\Form\DemoForm'
    _title: 'Demo Form'
  requirements:
    _permission: 'access content'

This should look familiar from the previous article in which we routed a simple page. The only big difference is that instead of _content under defaults, we use _form to specify that the target is a form class. And the value is therefore the class name we just created.

Clear the caches and navigate to demo/form to see the form and test it out.

If you are familiar with drupal_get_form() and are wondering how to load a form like we used to in Drupal 7, the answer is in the global Drupal class. Thus to retrieve a form, you can use its formBuilder() method and do something like this:

$form = \Drupal::formBuilder()->getForm('Drupal\demo\Form\DemoForm');

Then you can return $form which will be the renderable array of the form.

Conclusion

In this article we’ve continued our exploration of Drupal 8 module development with two new topics: blocks and forms. We’ve seen how to create our own block type we can use to create blocks in the UI. We’ve also learned how to add a custom configuration to it and store the values for later use. On the topic of forms, we’ve seen a simple implementation of the FormBase class that we used to print out to the screen the value submitted by the user.

In the next tutorial we will take a quick look at configuration forms. We will save the values submitted by the user using the Drupal 8 configuration system. Additionally, we will look at the service container and dependency injection and how those work in Drupal 8. See you then.

Mar 26 2013
Mar 26

Episode Number: 

131

The Drupal 7 Floating Block module makes it easy to float a Drupal block along the sidebar as you scroll down the page. It uses a simple CSS selector to determine which blocks to float.

In this episode you will learn:

  • How to install and configure the Drupal 7 Floating Block module
  • How to determine the CSS selector to use for your block
  • How to get a Drupal block to float as you scroll down the page

Thanks to OSTraining for sponsoring this episode of the Daily Dose of Drupal.

DDoD Video: 

Mar 06 2013
Mar 06

There are some times in Drupal 6 where you push the limits of what the blocks interface can do. If you need to display the same block, multiple times on the same page, you will start to see these limitations. An example of where this is useful is a Newsletter signup form. Sometimes a client may want a newsletter signup form to be in the footer of every page, but also displayed more prominently on the contact form page.

You will also run into this issue if you want to output a block in one region on one page and another region on a separate page. An example of this would be to display the newsletter signup form in the header on the front page, but in the footer on every other page of the site.

Both of these examples can easily be achieved using something like Panels or Display Suite, but if you want to stick to the blocks interface, here is a simple way you can solve this by building a custom Drupal 6 module.

The first step is to create a simple Drupal 6 module. After you have the module created, we need to create our own Drupal 6 block. Drop the following code in your .module file. You will need to replace the module name with the name of your module. You will also need to look through the other code replacing text and descriptions as necessary. In my example I will be going through creating a second block for the Drupal 6 Constant Contact module.

/**
 * Implements hook_block().
 */
function MYMODULE_block($op = 'list', $delta = 0, $edit = array()) {
  if ($op == 'list') {
    $blocks[0] = array('info' => t('Constant Contact Block 2'));
 
    return $blocks;
  }
  else if ($op == 'view') {
    switch ($delta) {
      case 0:
        // Your module will need to define this function to render the block.
        $block = array(
          'subject' => t('Title of block #1'), 
          'content' => '',
        );
        break;
    }
    return $block;
  }
}

The next step is to identify the block you want to display. The best way to do this is to figure out which module you need to duplicate the block for. In my example this was the Constant Contact module. Open up the .module file for whichever module you want to duplicate the block for.

Once you have the module file opened, do a search for "_block" or "hook_block". This should get us to the function that has all the details you need to insert the line of code that will print this block. We need to get the module name and the delta value for our block. Here is an example from the constant_contact.module file's hook_block implementation.

/**
 * Enables us to place a signup form into a block
 */
function constant_contact_block($op = 'view', $delta = 0, $edit = array())
{
	switch($op) {
		case 'list':
			$blocks[0] = array(
				'info' => t('Constant Contact Signup Form'),
				'visibility'      => 0,
				'roles'      => array(1),
				'pages'      => 'user*',
			);
		return $blocks;
		case 'configure':
			$form = array();
		return;
		case 'save':
		return;
		case 'view':
			switch ($delta) {
				case 0:
					$block['subject'] = t('Signup');
					$block['content'] = drupal_get_form('constant_contact_signup_form');
				break;
			}
		return $block;
	}
}

I can pull out the module name from the function constant_contact_block and get that "constant_contact" is the module name. You can also take this from whatever is in front of the .module in the constant_contact.module file name.

The next step is to pull out the delta value for the block. This is displayed below the switch ($delta) { line of code. In this "case" we want the number "0". This is pulled from the case 0: line of code. Blocks may have multiple of these case statements, you will need to find the right delta value for the block you want to display. Many times in a Drupal 6 hook_block implementation this will simply be 0.

We now add the following line of code to our modules hook_block function.

$block = module_invoke('MYMODULE', 'block', 'view', [DELTA]);

We replace MyMODULE with the module name, in this case "constant_contact" and we replace [DELTA] with the delta value, in this case 0. Here is what the finished line of code looks like:

$block = module_invoke('constant_contact', 'block', 'view', 0);

You then need to replace this line of code with what would normally be your Drupal 6 block output code. The final version of your Drupal block code should look something like this:

/**
 * Implements hook_block().
 */
function MYMODULE_tweaks_block($op = 'list', $delta = 0, $edit = array()) {
  if ($op == 'list') {
    $blocks[0] = array('info' => t('Constant Contact Block 2'));
 
    return $blocks;
  }
  else if ($op == 'view') {
    switch ($delta) {
      case 0:
        $block = module_invoke('constant_contact', 'block', 'view', 0);
        break;
    }
    return $block;
  }
}

You can now add this block just like you would any other block. It should be an exact duplicate of the other Drupal block.

A couple notes: This approach still has it's limitations so a better solution is using something like Panels or Display Suite. However it works well for one off simple fixes on sites that are already making heavy use of blocks. Also note that if you are displaying the same block multiple times on the same page, everything should work fine, but your CSS may not validate if the block uses the same CSS ID since it will now be in multiple places inside the HTML.

Hope that helps and let me know if you have any questions.

Mar 06 2013
Mar 06

Episode Number: 

122

The Drupal 7 Block Class module provides an easy way to add a CSS class to a Drupal block.

In this episode you will learn:

  • How to use the Block Class module to add a CSS class to a Drupal 7 block
  • Cases that having a CSS class on your Drupal block might be useful

Thanks to Drupalize.me for sponsoring this episode of the Daily Dose of Drupal.

DDoD Video: 

Feb 15 2013
Feb 15

Episode Number: 

109

The Drupal 7 Block Up Down module allows easy management of your blocks from the front end of your site (rather than having to go to the Administer Blocks page).

In this episode you will learn:

  • What the Block Up Down module is used for
  • How to use the Block Up Down module to re-position or disable blocks on your Drupal site

Thanks to Drupalize.me for sponsoring today's episode.

DDoD Video: 

Aug 08 2012
Aug 08
Lullabot logo

Lullabot has trained thousands of Drupal developers & guided the development of some of the largest Drupal websites.

May 03 2012
May 03

Listen online: 

Kris Vanderwater talks about the Drupal 8 Initiative Blocks & Layouts Everywhere. Kris gives a brief overview of what this is and explains how he is working on the usability side, bringing together designers and javascript experts to ensure this will be a great experience for all users. Kris goes so far as to refer to it as "Panels in Core" and is looking for contributors, so if that strikes your fancy, take a listen to what Kris has to say.

This Drupal Voices was recorded at the 2012 DrupalCon in Denver.

Release Date: May 3, 2012 - 10:00am

Album:

Length: 8:00 minutes (5.56 MB)

Format: mono 44kHz 97Kbps (vbr)

Dec 06 2011
Dec 06

This screencast shows how you can use Rules to alter the presentation of your Drupal site, such as:

  • Enabling, disabling and moving blocks around
  • Setting HTML title element and also on-page titles
  • Setting body classes
  • Setting the active menu item (using Menu Position)

Some bigger questions about using Rules for altering presentation is also discussed:

  • Using Rules for presentation altering is relatively heavy. (It consumes about 2.5 MB more PHP memory than Context, and has about the same loading times – judging from a first, rough comparison.)
  • Using Rules for presentation altering gives a more complex UI than the interface use for modules made for more particular use cases.
  • It is possible for modules to provide alternative user interfaces to Rules.
  • Rules allows reusing actions in many different situations, between different modules.
  • Rules (and Entity API) provides generalized data handling.
Jul 09 2011
Jul 09
Printer-friendly versionPDF version

This is a short preview from my forthcoming e-book Building Your Blog With Drupal 7. There are two sections previewed here.

  1. Getting Your Blog Posts Onto The Front Page - I explain how to create a simple page, RSS feed and block using the new Views 3 interface.
  2. Arranging Sidebar Blocks - I explain how you can place the block you created in the previous section into the sidebar of your page.

Getting Your Blogs Posts Onto The Front Page

The next things you’re going to do are to set up a “view” (which is basically a list) for your blog posts and make that view the front page of your site. It’s true that there are simpler ways to do this, namely clicking the Promoted to front page checkbox in the add content window, but Views is so integral to Drupal that I think you should get started using it sooner rather than later.

To get started click on the Structure link in the admin menu, then select the Views link which should be the last one in the Structure window. At the very top of the next window you will see an Add new view link. When you click that link you should see a window that looks like the image below.

Add new view

There are a lot of choices to make when adding a new view so I’ll make it easy for you and show you the choices I have made in the image below.

You’re free to change any of the details to suit your own needs. The most important thing to understand is that these choices will result in the following features.

  1. A list of blog posts with the newest blog post displayed at the top
  2. A dedicated page at yourblog.com/blog that shows ten teaser (or summary) posts that include the title, the beginning of the body field and a link to the full post
  3. A dedicated RSS feed that people can use to subscribe to the blog in an RSS reader
  4. A block that you can place in the sidebar that has links to the five most recent posts

Once you have filled in your choices click the Save and exit button to complete the creation of your feed. The screen will refresh and you’ll be looking at the new page you created at yourblog.com/blog. You should see the “Hello World” post you created and an orange RSS feed icon that links to the blog feed. Now that the view for your blog has been created the next thing you want to do is make that view the front page of your site.

Click on Configuration in the admin menu then select the Site information link. The second section from the top of the site information page is called “Front Page”. Change the “Default front page” field from “node” to “blog” or whatever path you gave to your blog post view. Click Save configuration then navigate to your site home page. The front page of your site should now look something like the image below.

front page

Besides your blog posts the blocks to the left side of your posts are another important element of your site. The block you see on the top is the standard search block. I’ll have you leave that in place. The next blog down is the navigation block which we really don’t need since we have the administration bars at the top of the page. In the next section I will show you how to remove that block and add other blocks that you do need.

Arranging Sidebar Blocks

Click on Structure in the admin menu and then select the Blocks link which is the first link. You will see a table that looks like the one in the image below. Focus on the “Sidebar first” section of the table.

block administration

Click on the list box in the Navigation row and set the value to “-None-“. You’ll notice that Navigation disappears from the row. Scroll down to the very bottom of the page and drag the row called “blog_posts: Block” to the space below the Search form field. Then navigate to the bottom of the page and click the Save blocks button. Navigate to the home page and you will now see the Recent Posts block below the Search block.

If you like you can also add a Recent Comments block to the sidebar. The Drupal core comments module has created this block for you. Just go to the block administration window and drag “Recent Comments” to the appropriate position or select “Sidebar first” from the list box in the Recent Comments row. Keep in mind that those changes are not saved until you select the Save blocks button.

The final block that I’ll have you place for now is the block that will hold your tag (or category) “cloud”. In the Block administration window look for “Tags in Tags” and move that to Sidebar first then save your blocks. If you go to the home page it should now look something like the image below.

 home page blocks

You’ll notice that the “Tags in Tags” block has a dotted line around it with a configuration icon in the upper right portion of the block. The ability to go to the edit views of blocks directly from the block itself is a nifty new feature in Drupal 7. You should see something like that when you put your cursor directly over the block and point to the configuration icon. For all blocks you have the option of editing the title, the access levels and even the pages that they appear on. Tags in Tags happens to be a block that has an additional configuration option. You can edit the number of tags that appear in the block.

If you click on the configure block link that appears when you mouse over the configuration icon you will be taken to the block edit window where, among other things, you can adjust the block title to something like “Topics” and also change the number of tags that will be displayed if you like. Remember to click the Save button at the bottom of the window. Once you do that you will be returned to the home page of your site.

One thing you may have noticed when looking at your block configuration is the fact that the User login block is placed in the Sidebar first section. If you don’t want anonymous users to see that blog you should remove it just like you removed the Navigation block. You can always reach the login page of your site by navigating to /user/login.

I hope that you enjoyed this short preview. I have most of the content in the e-book finished. Once the content is complete I will be working on perfecting the formatting and cleaning up errors that I find along the way. If you want to be among the first to know when the e-book is finished then I suggest that you do one of three things if you haven't already.

  1. Subscribe to posts via the main Learn By The Drop RSS feed
Video Links

YouTube Version

Flash Version

Quicktime Version

Nov 11 2010
Nov 11

Many of my favorite websites offer a nice little feature, immediately following the body of the page, that highlights 3-5 "possibly related" stories or blog posts. I wanted to do this on OSC and some other sites, but found that it's difficult to add regions inside of nodes—the closest I could get with the default theme/block behavior is to have it appear after comment section, which is too far down the page to be relevant.

I decided to use the Featured Content module to create my blocks, as it offers a good amount of customization as to what kind of algorithms it uses to find related nodes... performance considerations aside. There are other ways to go about creating lists of related nodes, but this was quick and easy.

Adapting a solution I found here, I created a simple function inside my template.php file that allowed me to print a block from inside my node.tpl.php template.

Inside template.php:

<?php
/**
 * Helper function for retrieving block code for insertion into templates.
 *
 * @see http://drupal.org/node/753516#comment-2769068
 */
function osc_block_retrieve($module, $delta) {
 
$block = (object) module_invoke($module, 'block', 'view', $delta);
 
$block->module = $module;
 
$block->delta = $delta;
  return
theme('block', $block);
}
?>

Inside node.tpl.php:

<?php
 
<?php if ($page): ?>

    <div class="block-in-node">
      <?php print osc_block_retrieve('featured_content', '1'); ?>
    </div>
  <?php endif; ?>
?>

I chose to rank related nodes first by similar taxonomy terms, then by how many views the node received (I'm using the statistics module on this site).

Alternatively, you could do one of the following to accomplish the same kind of thing:

  • Set up a region inside your nodes, in the node.tpl.php file. This seems to be a little burdensome, though, unless you're planning on doing many different things inside said region(s).
  • Use the Panels module to add blocks inside of nodes, or in a different kind of page layout.

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web