Drush command to close comments

There is a great module called Comment Closer that allows you to automatically close comments on certain nodes after a certain time period.

On a recent project, needed to come up with a solution to close comments apart from a cron job and without adding yet another module to the site.

I decided to make use of drush and created my first drush command.

With the drush file properly installed, I can now execute the following command from the site root directory:

drush comment-close --days=7 --types=story,blog

This command will close comments on all story and blog nodes that are older than 7 days.

I can also setup a nightly cron job to do this automatically using the same command, but specifying the specific site to run on.

drush comment-close --days=7 --types=story,blog --root=/home/mysite.com/public_html

The contents of the drush command file are below and a file attachment below that.

 * @file
 *   Comment closer drush command
 *   You can copy this file to any of the following
 *     1. A .drush folder in your HOME folder.
 *     2. Anywhere in a folder tree below an active module on your site.
 *     3. /usr/share/drush/commands (configurable)
 *     4. In an arbitrary folder specified with the --include option.
 * Implementation of hook_drush_command().
 * In this hook, you specify which commands your
 * drush module makes available, what it does and
 * description.
 * Notice how this structure closely resembles how
 * you define menu hooks.
 * @See drush_parse_command() for a list of recognized keys.
 * @return
 *   An associative array describing your command(s).
function sms_drush_command() {
  $items = array();
  $items['comment-close'] = array(
    'description' => "Close comments for nodes of a certain age",
    'options' => array(
      '--days' => 'Number of days in the past, before which, comments will be closed',
      '--types' => 'Comma delimited list of node types to include (e.g. story, blog)',
    'examples' => array(
      'drush comment-close --days=7 --types=story,blog' => 'Close comments for stories and blogs older than 7 days',
  return $items;
 * Implementation of hook_drush_help().
 * This function is called whenever a drush user calls
 * 'drush help <name-of-your-command>'
 * @param
 *   A string with the help section (prepend with 'drush:')
 * @return
 *   A string with the help text for your command.
function comment_closer_drush_help($section) {
  switch ($section) {
    case 'drush:comment-close':
      return dt("This command will close comments on nodes of specified node types older than the specified number of days.");
 * Implementation of drush_hook_COMMAND_validate().
function drush_comment_closer_comment_close_validate() {
  $days = drush_get_option('days');
  if (empty($days)) {
    return drush_set_error('DAYS_REQUIRED', dt('You must specify the number of days.'));
  if (!is_numeric($days) || $days <= 0) {
    return drush_set_error('NOT_NUMBER', dt('The day value must be a positive number !days', array('!days' => $days)));
 * Example drush command callback. This is where the action takes place.
 * The function name should be same as command name but with dashes turned to
 * underscores and 'drush_commandfile_' prepended, where 'commandfile' is
 * taken from the file 'commandfile.drush.inc', which in this case is 'sandwich'.
 * Note also that a simplification step is also done in instances where
 * the commandfile name is the same as the beginning of the command name,
 * "drush_example_example_foo" is simplified to just "drush_example_foo".
 * To also implement a hook that is called before your command, implement
 * "drush_hook_pre_example_foo".  For a list of all available hooks for a
 * given command, run drush in --debug mode.
 * If for some reason you do not want your hook function to be named
 * after your command, you may define a 'callback' item in your command
 * object that specifies the exact name of the function that should be
 * called.  However, the specified callback function must still begin
 * with "drush_commandfile_" (e.g. 'callback' => "drush_example_foo_execute").
 * All hook functions are still called (e.g. drush_example_pre_foo_execute,
 * and so on.)
 * In this function, all of Drupal's API is (usually) available, including
 * any functions you have added in your own modules/themes.
function drush_comment_closer_comment_close() {
  $days = drush_get_option('days');
  $types = drush_get_option('types');
  $node_types = explode(',', $types);
  $node_types = array_map('trim', $node_types);
  $timestamp = time() - ($days * 24 * 60 * 60);
  $args = array($timestamp);
  $where = 'WHERE created < %d';
  if (!empty($types)) {
    $args = array_merge($args, $node_types);
    $where .= ' AND type IN ('. db_placeholders($node_types, 'varchar') .')';
  $where .= ' AND comment = 2';
  $sql = 'UPDATE node SET comment = 1 '. $where;
  db_query('UPDATE node SET comment = 1 '. $where, $args);
  $affected = db_affected_rows();
  $msg = dt('Comments have been closed for !affected nodes.',
            array('!affected' => $affected)
  drush_print("\n" . $msg . "\n");
comment_closer.drush_.inc.zip1.94 KB