Jan 02 2019
Jan 02

An article from ComputerMinds - Building with Drupal in the UK since 2005.

Anyone familiar with the Drupal core development lifecycle will know that presently the Drupal community supports two major versions at any one time: the current major release and its immediate predecessor. This means that at ComputerMinds we are currently helping our clients support and develop both Drupal 7 and Drupal 8 sites. So the obvious question that we get asked is ‘when is it time to upgrade’?

We can’t properly answer this question without bringing the next major release, Drupal 9, into the mix. So let’s look at the development timeline for these three versions. According to a blog post by Dries both Drupal 7 and 8 will have an end of life of no later than November 2021 with Drupal 9 being released roughly a year earlier in June 2020 to give site owners enough time to move over to Drupal 9. It is worth noting that from November 2021 only Drupal 9 will be supported. Dries outlines these dates with a whole bunch of details in this blog post.

Historically, migrating between major versions has been a considerable chunk of work as major versions aren’t backwards compatible; however, the good news is that migrating from Drupal 8 to Drupal 9 should be a very straightforward process - so long as you’ve kept your Drupal 8 site up-to-date! This is good news for anyone that’s already taken the plunge into the world of Drupal 8 as the migration process shouldn’t really be any more involved than a minor upgrade. This is because the only real changes will be to remove deprecated code and update dependencies, such as Symfony (Symfony 3 has an end of life of November 2021, hence this date being cut off for support for Drupal 8).

For site owners still using Drupal 7 the question of when to upgrade is slightly more complicated. Do you wait for Drupal 9 and skip Drupal 8, or should you upgrade now? As previously mentioned we can be reasonably confident that upgrading from Drupal 8 to Drupal 9 will be a straightforward process, so we don’t need to worry about having to redo lots of work a couple of years down the line if we do migrate to Drupal 8 now. So the question of when to migrate really varies depending on your current circumstance and preference.

Some site owners will want to benefit from new functionality added in Drupal 8 so will want to upgrade their Drupal 7 sites as soon as possible, whilst obviously factoring in how difficult and expensive the migration will be. Others will be perfectly happy sticking with Drupal 7 until support has ended, at which point they will have to port over in order to keep their site secure. Another piece of good news for anyone weighing up their options with Drupal 7 is that support for Drupal 7 will also be extended to November 2021 (previously support would have ended for Drupal 7 as soon as Drupal 9 was released) so this gives you another year to implement your migration to Drupal 9.

So the short answer of when to migrate your Drupal 7 site is really whenever is good for you. There’s no immediate rush and if you do opt to migrate to Drupal 8, as long as you keep your site up-to-date, upgrading to Drupal 9 when the time comes should be a cinch!

Jan 02 2019
Jan 02

An article from ComputerMinds - Building with Drupal in the UK since 2005.

At ComputerMinds we like to think that we’re all pretty good at what we do; however, nobody is perfect and this is why we always ensure that our code is properly peer reviewed as part of our quality assurance process.

Peer review is literally just what the name implies; we work together to review each other’s code to make sure that it all makes sense. This approach means that we’re able to spot obvious mistakes before they become a problem. It also has the huge advantage of allowing us to transfer knowledge between our team on a day-to-day basis.

Pull Requests

The primary way we peer our code is to make use of GitHub’s pull requests (PR) feature. This means that whenever we need to do some work on a Git repo we start by creating a new feature branch which will contain the chunk of work that we’re doing. Then once we are happy with the code we’ve written in this branch we’ll go over to GitHub and create a PR to merge our branch in with another branch which we know is stable, for example the master branch. Before this merge happens GitHub’s PR tool will show all the changes between the the two branches so that they can be reviewed by another developer.

At ComputerMinds we use pull requests a lot. We don’t like to work directly on a stable branch as this way there is much more chance the bugs might slip through the net. By using pull requests we can be sure that our code is properly sanity checked before it makes its way over to a stable environment, be that a client facing testing branch or the live branch. GitHub also makes it easy to add comments directly to the pull request so any issues are full documented and feedback is clearly displayed.

Face to face

When dealing with a more in-depth code change, it's particularly helpful to talk face-to-face, as it allows the original developer to talk you through their changes and the thinking behind them. This allows the reviewer to have a much better understanding of what the original developer was aiming to achieve and to sanity-check their thinking. A 'meatspace' chat can be more difficult to achieve than just getting some comments on a pull request, but it's often worth the effort.

Finding the right fit

Both of these methods have their strengths and weaknesses. Pull requests are quick and easy to use; however, when dealing with larger sets of changes things may get overlooked, or may not be properly understood without knowledge of the bigger picture. Face to face reviews obviously take up more resources to conduct the review but do allow for a more in-depth review where the bigger picture can be clearly explained by the original developer.

Obviously it goes without saying that these two approaches to peer review aren’t mutually exclusive - there are plenty of meatspace chats going on around the office about various PRs.

At ComputerMinds we're still working on how we do code review. There's always room for growth and for change, and we're actively promoting discussion amongst our team to see how we can do better.

How do you do quality assurance and review on your code? Share your thoughts and tips with us below!

Apr 17 2012
Apr 17

This article discusses how we can use a combination of techniques to take the standard 'Confirmation Form' provided by the Flag module and get it to load in a modal window rather than on its own page. We'll also extend this form slightly to allow the user to include some additional data before clicking 'Confirm'. As an example we'll use the Flag module to create an 'Abuse' flag that will apply to a comment entity - this is intended to allow a user to flag a comment as requiring moderations but before triggering the actions associated with the flag we need to display a modal popup to ask them why they're making the report. This seems to be reasonably standard functionality when it comes to reporting comments; however, the implementation of this within Drupal isn't as trivial as it first appears - as I found out!

Setting up the Basic Flagging Functionality

To add the ability to allow your users to flag a comment as requiring moderation is actually a very simple process - all the complexity surrounds adding in the modal form aspect. We begin by downloading and enabling the Flag module. This module has everything we need to be able to add a link to comments to trigger the report, and if we didn't want to collect any additional information we could just enable the Flag Actions sub-module to fire any number of triggers to do things like unpublish the comment or send an email. It's beyond the scope of this article to detail exactly how to configure the Flag module; however, detailed instructions are provided in its README.txt file.

One thing that we do need to explicitly mention regarding the configuration of your new flag is that you'll need to set its 'Display Options' to use a 'Confirmation Form' as this is what will give us a handle to allow the collection of additional information in the simplest way I could think of. We could have written a custom action but I thought as we've already got a form in place, our module would be better suited to just altering the way this is processed so if it's not enabled then the Flag module will just function as normal.

Extending the Standard Confirmation Form

Out of the box, the confirmation form provided by the Flag module does nothing more than display a form containing a submit button to confirm the action and a link to cancel it. We can just use hook_form_alter() to add a few of additional fields to this a basic implementation of which is shown below:

/**
* Implements hook_form_alter()
*/
function example_form_alter(&$form, &$form_state, $form_id){
  if($form_id == 'flag_confirm'){
    $form['reason'] = array(
      '#type' => 'select',
      '#title' => t('Reason for reporting this comment'),
      '#options' => array(
        'offensive' => t('Comment\'s offensive or unlawful'),
        'spam' => t('Advertising / Spam'),
        'other' => t('Another reason'),
      ),
    );
    $form['other'] = array(
      '#type' => 'textfield',
      '#title' => t('Reason'),
    );
    $form['comment_id'] = array(
      '#type' => 'value',
      '#value' => arg(4),
    );
    //Add our own submit handler to process this data.
    $form['#submit'][] = 'example_confirm_form_submit';
  }
}

There's nothing scary involved here. You'll notice we've added a hidden field to store the ID of the comment we are interested in - this just gives use easy access to it should we need to load the entity again in the submit handler. On this subject we've included our own submit handler to process this data. We need to do this as the Flag module will only care about the form elements that it has generated so in order to process these new fields we just add another function to the form's $form['#submit'] array. The function this points to will just take the standard arguments we pass to a submit handler so as a basic example we need to include a function like:

/**
* Additional submit handler for the comment confirmation form
*/
function example_confirm_form_submit($form, &$form_state){
  $params = $form_state['values'];
  //Do something with these submitted values
  //For example send them in an email to a moderator using php drupal_mail()
}

That's all we need to do with the confirmation form at this stage and if we didn't want to load it in a modal window then this would be enough to allow users to report comments and include additional information as part of that process. Working with modals makes things a bit more interesting.

AJAX and the Chaos Tool Suite

The reason why this is slightly more complicated than it first sounds is because we want the rendered form but we don't want to push it through the entire Drupal theme engine as this would mean we'd end up rendering another whole page within the popup when in fact all we want is the markup for the form. Loading forms in modal windows isn't actually that complicated in itself as the Chaos Tool Suite module provides some nice functionality to do the heavy lifting for us. What makes this particular example more complex is the fact that the form we want to render isn't being generated by our module and neither are any references to it so we need to extend the Flag module in a way that means our custom module can just slot in to add this modal functionality.

To get our module working with Chaos Tools we need to follow a similar technique to that described in our Make a link use ajax in Drupal 7 (it's easy) article. We begin by defining an implementation of hook_menu() as shown below:

/**
* Implements hook_menu()
*/
function example_menu(){
  $items['comments/%ctools_js/confirm/%flag/%'] = array(
    'title' => 'Contact',
    'page callback' => 'example_test_modal',
    'page arguments' => array(1, 3, 4),
    'access arguments' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}

You'll notice that there are a few placeholders in the path for our callback. We use these to tie into both the Chaos Tools and Flag modules and to pass through the ID of the comment being reported. The first wildcard is $ctools_js - this will trigger a function called ctools_js_load() to run within Chaos Tools to check whether or not the link is capable of running the JavaScript required to fire the AJAX request. If it is then this placeholder becomes ajax; if not it's set to nojs in exactly the same way as is shown in the Make a link use ajax in Drupal 7 (it's easy) article. However, in that example we explicitly define two callbacks whereas here the %ctools_js wildcard allows one callback to suffice as the Chaos Tools module will change the argument dynamically.

The next wildcard is %flag and this is what makes our menu callback work with the Flag module. When rendering the form the Flag module needs to reference an object that represents the flag that is being used as the trigger. This object is passed through to the form as an argument which means that it needs to be loaded as a variable before we can call the form. By including this placeholder we run the Flag module's implementation of flag_load() , which takes the string entered in the path and returns the relevant flag object.

The final wildcard is just a simple reference to the ID of the comment we're interacting with; again this will be needed to allow the Flag module to do its magic, as we'll see shortly.

Next we need to implement the page callback function we reference in hook_menu() as this will be what actually generates the response to any requests that hit a path matching our definition. We need to make sure it accepts three arguments corresponding to the wildcards discussed above; these parameters will have been set by each modules' _load() functions by the time we invoke the callback function.

function example_test_modal($js, $flag, $cid){
  //If JavaScript isn't enabled the just go to the standard confirmation form
  if (!$js) {
    drupal_goto('flag/confirm/flag/abuse/' . $cid, array('query' => array('destination', $_GET['destination'])));
  }

  //Include the relevant code from CTools
  ctools_include('modal');
  ctools_include('ajax');
  ctools_add_js('ajax-responder');

  //Build up the $form_state array
  //This is passed through to the form generated by the Flag module
  $form_state = array(
    'title' => t('Report Comment'),
    'ajax' => TRUE,
    'build_info' => array(
      'args' => array(
        0 => 'flag',
        1 => $flag,
        3 => $cid,
      ),
    ),
  );

  //Wrap the Flag module's form in a wrapper provided by CTools
  $output = ctools_modal_form_wrapper('flag_confirm', $form_state);

  if (!empty($form_state['executed'])) {
    $output = array();

    //This makes sure we go to the right place once we close the modal window
    if (isset($_GET['destination'])) {
      $output[] = ctools_ajax_command_redirect($_GET['destination']);
    }
    else {
      $output[] = ctools_ajax_command_reload();
    }
  }

  //Return the JSON string ready to be rendered back to the DOM
  print ajax_render($output);
  exit;
}

There's quite a lot going on in this function. First of all we check to see if we can use AJAX and render a modal version of the form. If not then we just redirect to the standard form which will be displayed on its own page. If JavaScript is enabled we then need to make sure we add all the code we need from Chaos Tools - this is just done by some simple helper functions provided by the module. The next thing we need to do is build up the $form_state array - this is an important stage as we also need to include the arguments in under a build_info key in order to get them over to the Flag module. This differs from how we'd usually do things if we weren't trying to render a modal form as it would be possible to just call drupal_get_form() and pass the arguments through as normal. Because we are using the Chaos Tools wrapper around the form we can't do this so we need to add them into the $form_state array. We also set the title of the modal window and the ajax key to TRUE .

We then use the Chaos Tools wrapper to add the form to the $output variable and apply a bit of logic to make sure we still honour the destination argument in the query string if it's present. If it's not then we just reload the current page when the modal window is closed. Finally we just print the JSON string and exit the function to stop it running through the theme engine and having markup added that will break the AJAX response.

Tying Everything Together

Now we have a function that will provide a valid AJAX response if requested, we need to start tying this into the links already being rendered by the Flag module. Chaos Tools is clever enough to realise that any link that has a class of ctools-use-modal needs to be loaded in a modal window if possible. So we need to add this class to the 'Flag' link on the comment to begin with. Next the link provided by the Flag module still points at the MENU_CALLBACK defined in that module so we need to rewrite this to point at our new page callback function defined in our implementation of hook_menu(). We could do all this using hook_comment_view_alter(); however, I opted to use jQuery to add the classes as this means that in real terms if JavaScript isn't enabled then the class won't be added and the link will never get pointed at our function so it will just work as normal.

(function ($) {

Drupal.behaviors.initModalFormsConfirm = {
  attach: function (context, settings) {
    $(".flag-link-confirm", context).once('init-modal-forms-contact', function () {
      this.href = this.href.replace(/flag\/confirm\/flag\/abuse/,'comments/nojs/confirm/abuse');
    }).addClass('ctools-use-modal ctools-modal-modal-popup-confirm');
  }
};

})(jQuery);

The jQuery code above just looks for any link that has a class of flag-link-confirm and then rewrites its href attribute based on a regular expression matching the entire string up to the point where the flag placeholder and comment ID are appended. We then add the ctools-use-modal class; you'll notice we also add another class of ctools-modal-modal-popup-confirm - this is to allow us to control how the modal window is rendered and we'll look at this next. To add this code to the comment we just use hook_comment_view() to call drupal_add_js(). It is important to notice that we set the weight to -20 - this ensures that this code runs before the Chaos Tools JavaScript. If you didn't do this then the ctools-use-modal class won't have been set in time for the Chaos Tools JavaScript to recognise it when it runs.

/**
* Implements hook_node_view_alter().
*/
function example_comment_view_alter($comment, $view_mode, $langcode) {
  drupal_add_js(drupal_get_path('module', 'example') . '/js/example.js', array('weight' => -20));
}

At the moment we're not quite there - clicking the link still won't load the modal window even though the class has been added as required. This is because when we're viewing a comment no code has been added in from the Chaos Tools module so this class has no context. In our page callback function above we've had to add this code in but this only runs after the link has been clicked, so we need a way to ensure that the code is also included before. In order to get around this we use an implementation of hook_init() to invoke a function that will add all the required JavaScript to the current page. We also wrap it in some logic to stop the code from being added to any of the Drupal installation pages.

/**
* Implements hook_init().
*/
function example_init() {
  if (!drupal_installation_attempted()) {
    example_configure();
  }
}

The code this calls will just add any JavaScript files that Chaos Tools needs in order to respond to the ctools-use-modal class and load the modal window. We also define some settings that will be added as JavaScript to help us theme the form; the code these reference is based on the Modal Forms module. This module provides some nice functionality to get some of the common core forms rendering in modal windows - for example using a 'login' link to load a modal version of the core user_login form. We're not actually using the module here but are borrowing the code it uses to render the modal window.

function example_configure(){
  static $configured = FALSE;
  if ($configured) {
    return;
  }
  //Include the relevant CTools code
  ctools_include('ajax');
  ctools_include('modal');
  ctools_modal_add_js();

  $throbber = theme('image', array('path' => ctools_image_path('loading_animation.gif', 'modal_forms'), 'alt' => t('Loading...'), 'title' => t('Loading')));
  $js_settings = array(
    'modal-popup-confirm' => array(
      'modalSize' => array(
        'type' => 'fixed',
        'width' => 500,
        'height' => 200,
      ),
      'modalOptions' => array(
        'opacity' => 0.85,
        'background' => '#000',
      ),
      'animation' => 'fadeIn',
      'modalTheme' => 'ModalFormsPopup',
      'throbber' => $throbber,
      'closeText' => t('Close'),
    ),
  );

  drupal_add_js($js_settings, 'setting');

  //Add in some custom CSS and our jQuery template
  ctools_add_css('example_popup', 'example');
  ctools_add_js('example', 'example');

  $configured = TRUE;
}

You can see that the $js_settings just take the form of an array with the key corresponding to the second class we added above. It also specifies that we should render the form using a 'theme' called ModalFormsPopup. This option just references a JavaScript file containing some code to override the standard Chaos Tools theming of the modal window - it's purely aesthetic. The Drupal.theme.prototype namespace was added in Drupal 6 to allow provide a method of cleanly overriding another module's JavaScript generated HTML code.

/**
* Provide the HTML to create the modal dialog.
*/
Drupal.theme.prototype.ModalFormsPopup = function () {
  var html = ''

  html += '<div id="ctools-modal" class="popups-box">';
  html += '  <div class="ctools-modal-content modal-forms-modal-content">';
  html += '    <div class="popups-container">';
  html += '      <div class="modal-header popups-title clearfix">';
  html += '        <h3 id="modal-title" class="modal-title"></h3>';
  html += '        <span class="popups-close close">' + Drupal.CTools.Modal.currentSettings.closeText + '</span>';
  html += '      </div>';
  html += '      <div class="modal-scroll"><div id="modal-content" class="modal-content popups-body"></div></div>';
  html += '    </div>';
  html += '  </div>';
  html += '</div>';

  return html;
}

That's pretty much all there is to it. We've essentially just written a lot of glue to get the Flag module's confirmation form working with the Chaos Tools modal popup functionality. More importantly, we've not hacked either module and all the AJAX degrades gracefully. I've used the implementation of example_configure() to also add some CSS just to polish the final result a bit. I've also included a custom throbber that I generated using an online Tool just to make it tie nicely into my site's look and feel.

Mar 08 2012
Mar 08

Facebook integration is obviously starting to become a de facto requirement with most web development projects. In most cases the requirements are reasonably straight forward and involve nothing more than including a ‘Like’ button on content, but what about actually adding your own bespoke content to Facebook like The Guardian – bring on the Facebook Canvas App.

Canvas Apps are essentially just a way of wrapping some externally hosted content and putting this onto a Facebook branded page. We’ll use a basic example of just getting this page onto Facebook as a starting point before starting to explore how we can tie this in with the Facebook GraphAPI and Open Graph Protocol to provide a rich app all written in a language which you are comfortable with. Gone are the days when we need to use the clunky Facebook Markup Language (FBML) and we can opt for the much simpler approach of iFrames leaving us as developers to concentrate on developing our apps and not having to plough through loads of poorly documented Facebook technical jargon.

Becoming a Facebook Developer

Before we do anything we need to get ourselves setup with a Facebook developers account. I am working from the ground up, having created a brand new Facebook account just to make sure I don’t miss any steps out, I’m pretty sure this will go against the Facebook terms of use but will dutifully delete the account when I’m done with this article!

First of all we need to visit the Facebook Developers Center which can be found at http://developers.facebook.com/ it is worth noting here that this is where you’ll find a whole load of documentation about how to use the various Facebook APIs. From here you need to click ‘Apps’ in the top right corner which will then ask you to give your permission to connect as shown below.

Developer App Authentication

Once you've given this the nod you'll be set up as a Facebook developer.

Creating your App in Facebook

We now need to create our App in Facebook, since the actual mechanics of the App will all be contained in the page that you display within the Canvas we'll ignore the inner workings for the time being and just make a simple App that'll render this page in Facebook. Start by clicking 'Create New App'. This will present you with a modal window to collect some basic information about your new App, you only really need to give it a valid name, however, it is worth giving it a namespace as well. The namespace will become useful when you start to play with the Open Graph Protocol.

Developer App Authentication

Click 'Continue' and once you've successfully entered a CAPTCHA you'll get to a whole load of settings for you app. We're interested in the 'Select how your app integrates with Facebook' at the bottom of the 'Basic Settings' page as shown below:

Basic App Settings

We need to do three things here, firstly we'll create a Canvas App which will just pull this page through to an iFrame within Facebook and also a Page Tab so that we can add a tab to it on our Facebook Page - we'll explore the concept of the Page Tab a bit more later. Finally we need to add a Site URL under the 'Website' tab, this is to give our app the context of a domain. Once we're done the settings will look similar to those shown below. It is worth noting that we need to supply both a standard URL and a secure URL as Facebook won't display content that isn't encrypted if the user is connected via HTTPS so that it doesn't cause an SSL certificate warning.

Completed App Settings

Using your app

Once you've set your app up that's it - you're ready to start using it. You can view you Canvas App by just using the URL provided by Facebook which in our example is http://apps.facebook.com/computermindscanvas/ you will notice that this doesn't look brilliant mainly because we're just rendering out this website and this hasn't been designed to fit into the space available. But this is exactly the way that popular Apps such as The Guardian news app work - we'll get onto the other clever Graph stuff in a bit.

We can also get our app to be displayed as a tab on a Facebook page, so for example if you visit our Facebook Page you'll notice we have a tab linking to this article as shown below.

Facebook Page Tab

To get this in place you need to visit the following URL where YOUR_APP_ID is the generated ID of your app which can be found at the top of your app's settings page and YOUR_URL is the URL that you want to redirect to once your Page Tab has been added. This has to be a URL that is of the same domain as your app's Site URL which we set up earlier.

http://www.facebook.com/dialog/pagetab?app_id=YOUR_APP_ID&next=YOUR_URL

So long as you are logged into Facebook you will then get the follow dialog which will allow you to choose which page you want to add the Page Tab to. Select a Page from the drop down and click 'Add Page Tab' and then you're done, you should now have a page tab on the selected Facebook page which pulls through content from the URL specified in your app's settings.

Adding the Page Tab

The Facebook GraphAPI and Open Graph Protocol

Now this all may seem pretty pointless up to now, yes there will sometimes be a requirement to display some bespoke static content in a Canvas App or Page Tab but really this isn't overly likely, and doesn't benefit from any of the advantages that we've come to expect from using Facebook. However, this starts to get interesting when we combine this with the new Facebook Open Graph Protocol.

By having your users connect to your site using Facebook Connect they are granting you permission to read and write to specific areas of Facebook on their behalf. Facebook uses OAuth to authenticate users and when your site invokes a request to get an authentication token for a specific user you also tell Facebook what you intend to do as this user. So for example a request in the following form would ask for permission to have you site read a user's email address and their news feed as well as their basic information. All full list of these permissions can be found at http://developers.facebook.com/docs/reference/api/permissions/.

https://www.facebook.com/dialog/oauth?
     client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream

Once your site is connected to a Facebook account you can then start to effectively use Facebook as this user within the confines of the permissions they have granted. This means that you can do clever things like post back to their news feed when they read an article on your site this is where you will start to make use of your app's namespace which was created right at the beginning of this process. You can find a tutorial on how to go about using the Open Graph Protocol at http://developers.facebook.com/docs/opengraph/tutorial/.

Tying this in with Drupal

Finally it is worth noting that a lot of the grunt work has already been done to get your Drupal site working with the Facebook Graph in the form of the Drupal for Facebook module. There isn't a stable release of this for Drupal 7 yet but the basics are there and it serves as very useful starting point if you want to develop an all singing all dancing integration with Facebook.

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