You are here

sharedblocks.module in Shared Blocks 7

Same filename and directory in other branches
  1. 6 sharedblocks.module
  2. 7.2 sharedblocks.module

File

sharedblocks.module
View source
<?php

/**
 * Shared Blocks Module
 * @author Angie Byron and Jeff Robbins
 *
 * @todo
 *  - Check for blocks that are cached per page or per user and flag them as possibly incompatible
 *  - Add help text on publish and subscribe pages
 *  - Turn subscription add button into a local task
 */

/**
 * Implements hook_menu().
 */
function sharedblocks_menu() {
  $items = array();
  $items['admin/structure/sharedblocks'] = array(
    'title' => 'Shared Blocks',
    'description' => 'Configuration of shared blocks.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'sharedblocks_publish_form',
    ),
    'access arguments' => array(
      'access administration pages',
    ),
  );
  $items['admin/structure/sharedblocks/publish'] = array(
    'title' => 'Published Blocks',
    'page callback' => 'sharedblocks_publish_form',
    'access arguments' => array(
      'publish blocks',
    ),
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/structure/sharedblocks/subscribe'] = array(
    'title' => 'Subscribe Blocks',
    'page callback' => 'sharedblocks_subscribe_page',
    'access arguments' => array(
      'subscribe to blocks',
    ),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/structure/sharedblocks/subscribe/add'] = array(
    'title' => 'Add a Block Subscription',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'sharedblocks_subscribe_form',
    ),
    'access arguments' => array(
      'subscribe to blocks',
    ),
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/structure/sharedblocks/subscribe/edit/%'] = array(
    'title' => 'Subscribe Blocks',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'sharedblocks_subscribe_form',
      5,
    ),
    'access arguments' => array(
      'subscribe to blocks',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['admin/structure/sharedblocks/subscribe/delete/%'] = array(
    'title' => 'Subscribe Blocks',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'sharedblocks_subscribe_delete_form',
      5,
    ),
    'access arguments' => array(
      'subscribe to blocks',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['sharedblocks/%/%'] = array(
    'page callback' => 'sharedblocks_publish_block',
    'page arguments' => array(
      1,
      2,
    ),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implements hook_permission().
 */
function sharedblocks_permission() {
  return array(
    'publish blocks' => array(
      'title' => t('publish blocks'),
      'description' => t('Grants access to the Published Blocks settings page'),
    ),
    'subscribe to blocks' => array(
      'title' => t('subscribe to blocks'),
      'description' => t('Grants access to the Subscribe Blocks settings page'),
    ),
  );
}

/**
 * Implements hook_block_info().
 */
function sharedblocks_block_info() {

  // Get all blocks and read out their labels.
  $blocks = db_select('sharedblocks', 'sb')
    ->fields('sb', array(
    'name',
    'description',
  ))
    ->orderBy('name')
    ->execute();
  $return = array();
  foreach ($blocks as $block) {
    $return[$block->name] = array(
      'info' => t('@description (subscription)', array(
        '@description' => $block->description,
      )),
    );
  }
  return $return;
}

/**
 * Implements hook_block_view().
 */
function sharedblocks_block_view($delta) {

  // Look up details for this block.
  $block = db_select('sharedblocks', 'sb')
    ->fields('sb', array(
    'block_data',
  ))
    ->condition('name', $delta)
    ->execute()
    ->fetchField();
  if (!empty($block)) {
    $block = unserialize($block);
  }

  // Return the unserialized block data.
  return $block;
}

/**
 * Implements hook_cron().
 */
function sharedblocks_cron() {

  // Check to see if any shared blocks have expired
  $blocks = db_select('sharedblocks', 'sb')
    ->fields('sb', array(
    'id',
    'description',
    'url',
    'block_data',
    'update_interval',
  ))
    ->condition('expiration', REQUEST_TIME, '<')
    ->execute();
  while ($row = $blocks
    ->fetchAssoc()) {

    // If so, grab a new copy of the block data from the url.
    $block_data = sharedblocks_fetch_block($row['url']);
    if ($block_data) {
      $record['block_data'] = serialize($block_data);
      watchdog('sharedblocks', t('Block @description was successfully fetched.', array(
        '@description' => $row['description'],
      )));
    }
    else {
      watchdog('sharedblocks', t('Could not retrieve block from @url', array(
        '@url' => $row['url'],
      )), WATCHDOG_WARNING);
    }

    // Save record to the database.
    $record['id'] = $row['id'];
    $record['expiration'] = REQUEST_TIME + $row['update_interval'];
    drupal_write_record('sharedblocks', $record, 'id');
  }
}

/**
 *  CALLBACKS
 */

/**
 * Callback for admin/structure/sharedblocks/publish
 */
function sharedblocks_publish_form($form, &$form_state) {
  $published_blocks = variable_get('sharedblocks_publish', array());
  $form = array();
  $form['sharedblocks_publish'] = array(
    '#tree' => TRUE,
    '#title' => t('Published Blocks'),
  );

  // Get a list of all the available blocks in the system.
  foreach (module_implements('block_info') as $module) {
    $mod_blocks = module_invoke($module, 'block_info');
    if (is_array($mod_blocks)) {

      // Loop through the list.
      foreach ($mod_blocks as $delta => $info) {

        // Make checkboxes for each one.
        $form['sharedblocks_publish'][$module][$delta] = array(
          '#type' => 'checkbox',
          '#title' => check_plain($info['info']),
          '#default_value' => isset($published_blocks[$module][$delta]) && $published_blocks[$module][$delta] > 0,
          '#description' => isset($published_blocks[$module][$delta]) ? url("sharedblocks/{$module}/{$delta}", array(
            'absolute' => TRUE,
          )) : '',
        );
      }
    }
  }
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  return $form;
}

/**
 * Submission handler for the publish config form.
 */
function sharedblocks_publish_form_submit($form, &$form_state) {
  $values = $form_state['values'];
  variable_set('sharedblocks_publish', $values['sharedblocks_publish']);
  drupal_set_message(t('Published blocks have been saved.'));
}

/**
 * Callback for admin/structure/sharedblocks/subscribe
 */
function sharedblocks_subscribe_page() {
  $output = '';
  $rows = array();

  // Grab list of all shared blocks we've subscribed to.
  $blocks = db_select('sharedblocks', 'sb')
    ->fields('sb')
    ->orderBy('name')
    ->execute();
  foreach ($blocks as $r) {
    $edit = l(t('edit'), "admin/structure/sharedblocks/subscribe/edit/" . $r->id);
    $delete = l(t('delete'), "admin/structure/sharedblocks/subscribe/delete/" . $r->id);
    $rows[] = array(
      check_plain($r->name),
      check_plain($r->description),
      $edit,
      $delete,
    );
  }

  // Output list in a table.
  $output .= '<p>' . l(t('Add new subscribed block'), 'admin/structure/sharedblocks/subscribe/add') . '</p>';
  if (count($rows)) {
    $header = array(
      'Name',
      'Description',
      array(
        'data' => 'Operations',
        'colspan' => 2,
      ),
    );
    $output .= theme('table', array(
      'header' => $header,
      'rows' => $rows,
      'attributes' => $attributes = array(),
      'caption' => $caption = NULL,
    ));
  }
  else {
    $output .= t('No subscribed blocks defined. <a href="@add">Add one!</a>', array(
      '@add' => url('admin/structure/sharedblocks/subscribe/add'),
    ));
  }
  return $output;
}

/**
 * Form for adding new subscription block.
 */
function sharedblocks_subscribe_form($form, &$form_state, $id = NULL) {

  // Populate the default values.
  $edit = array(
    'id' => NULL,
    'name' => '',
    'label' => '',
    'url' => '',
    'update_interval' => 3600,
  );

  // @todo: this doesn't work if there's an error on the form
  if (!empty($form_state['input'])) {
    $edit = $form_state['input'];
  }
  elseif (!is_null($id) && is_numeric($id)) {
    $edit = db_select('sharedblocks', 'sb')
      ->fields('sb')
      ->condition('id', $id)
      ->execute()
      ->fetchAssoc();
  }
  $form = array();
  $form['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Name'),
    '#default_value' => $edit['name'],
    '#description' => t('Machine readable name of this block. Alphanumeric and underscore characters only.'),
    '#required' => TRUE,
  );
  $form['url'] = array(
    '#type' => 'textfield',
    '#title' => t('Subscribe URL'),
    '#default_value' => $edit['url'],
    '#description' => t('The URL to the block you wish to subscribe to, supplied by publishing site.'),
    '#required' => TRUE,
  );
  $period = drupal_map_assoc(array(
    60,
    300,
    600,
    1200,
    1800,
    3600,
    10800,
    21600,
    32400,
    43200,
    86400,
    172800,
    259200,
    604800,
    1209600,
    2419200,
    4838400,
    9676800,
  ), 'format_interval');
  $form['update_interval'] = array(
    '#type' => 'select',
    '#title' => t('Refresh rate'),
    '#options' => $period,
    '#description' => t("How frequently should this block's content be updated? Note that this can only run as often as cron runs."),
    '#default_value' => $edit['update_interval'],
  );
  if (!is_null($id)) {
    $form['id'] = array(
      '#type' => 'value',
      '#value' => $id,
    );
  }
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  return $form;
}

/**
 * Validate callback for subscription block add/edit form.
 */
function sharedblocks_subscribe_form_validate($form, &$form_state) {
  $values = $form_state['values'];

  // Check for machine-readable name.
  if (preg_match('/[^0-9A-Za-z_]/', $values['name'])) {
    form_set_error('name', t('Your machine-readable name must be alphanumeric and underscore characters only.'));
  }
}

/**
 * Submit callback for subscription block add/edit form.
 */
function sharedblocks_subscribe_form_submit($form, &$form_state) {
  $values = $form_state['values'];

  // Fetch the block from the publishing site.
  $block_data = sharedblocks_fetch_block($values['url']);
  if (empty($block_data)) {
    form_set_error('url', t('Block information not received: Please check your URL.'));
  }
  else {

    // Specify to drupal_write_record() whether we're doing an insert or update.
    if (!isset($values['id'])) {
      $update = array();
    }
    else {
      $update = array(
        'id',
      );
      $record['id'] = $values['id'];
    }

    // Prep our values for the database.
    $record['name'] = $values['name'];
    $record['url'] = $values['url'];
    $record['update_interval'] = (int) $values['update_interval'];
    $record['block_data'] = serialize($block_data);
    $record['description'] = $block_data['subject'];
    $record['last_update'] = REQUEST_TIME;
    $record['expiration'] = REQUEST_TIME + $values['update_interval'];

    // Populate the table with values.
    drupal_write_record('sharedblocks', $record, $update);

    // Redirect back to the listing page.
    $form_state['redirect'] = 'admin/structure/sharedblocks/subscribe';
    drupal_set_message(t('Your subscription block has been saved.'));
  }
}

/**
 * Form for deletion of a subscription block.
 */
function sharedblocks_subscribe_delete_form($form, &$form_state, $id = NULL) {
  if (!is_null($id) && is_numeric($id)) {
    $edit = db_select('sharedblocks', 'sb')
      ->fields('sb')
      ->condition('id', $id)
      ->execute()
      ->fetchAssoc();
  }
  $form['id'] = array(
    '#type' => 'hidden',
    '#value' => $id,
  );
  $form['name'] = array(
    '#type' => 'hidden',
    '#value' => $edit['name'],
  );
  return confirm_form($form, t('Are you sure you want to delete the %name shared block?', array(
    '%name' => $edit['name'],
  )), 'admin/structure/sharedblocks/subscribe', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
}

/**
 * Submit callback for subscription block delete form.
 */
function sharedblocks_subscribe_delete_form_submit($form, &$form_state) {
  $values = $form_state['values'];

  // Delte the subscription block.
  db_delete('sharedblocks')
    ->condition('id', $values['id'])
    ->execute();

  // Redirect back to the listing page.
  $form_state['redirect'] = 'admin/structure/sharedblocks/subscribe';
  drupal_set_message(t('The %name subscription block has been delete.', array(
    '%name' => $values['name'],
  )));
}

/**
 * Fetch block contents from a published site.
 *
 * @param $url
 *   The URL to the published block, for example:
 *   http://pubtest.lulladev.com/sharedblocks/comment/0
 * @return
 *   Returns block data from the published site, or FALSE if block was invalid.
 */
function sharedblocks_fetch_block($url) {
  $response = drupal_http_request($url);
  if (isset($response->error)) {
    $block_data = FALSE;
  }
  else {

    // Block exists: pull its information into an array.
    $block_data = drupal_json_decode($response->data);
  }
  return $block_data;
}

/**
 * Page callback for block publish callback.
 */
function sharedblocks_publish_block($module, $delta) {
  $blocks = variable_get('sharedblocks_publish', array());
  if ($blocks[$module][$delta]) {

    // Load the block.
    $block = module_invoke($module, 'block_view', $delta);
    if (is_array($block)) {

      // Translate relative URLs into absolute ones.
      // NOTE: Only works with double quotes..
      // @todo: see about capturing ('|") and then matching %2 at end
      // @todo: make this work with the render array
      $regex = '~(href|src|HREF|SRC)="(\\/.+?)"~';

      //$block['content'] = preg_replace($regex, '\\1="' . $GLOBALS['base_url'] . '\\2"', $block['content']);
      drupal_json_output($block);
      return;
    }
  }

  // If you get here, something has gone wrong.
  return MENU_NOT_FOUND;
}

Functions

Namesort descending Description
sharedblocks_block_info Implements hook_block_info().
sharedblocks_block_view Implements hook_block_view().
sharedblocks_cron Implements hook_cron().
sharedblocks_fetch_block Fetch block contents from a published site.
sharedblocks_menu Implements hook_menu().
sharedblocks_permission Implements hook_permission().
sharedblocks_publish_block Page callback for block publish callback.
sharedblocks_publish_form Callback for admin/structure/sharedblocks/publish
sharedblocks_publish_form_submit Submission handler for the publish config form.
sharedblocks_subscribe_delete_form Form for deletion of a subscription block.
sharedblocks_subscribe_delete_form_submit Submit callback for subscription block delete form.
sharedblocks_subscribe_form Form for adding new subscription block.
sharedblocks_subscribe_form_submit Submit callback for subscription block add/edit form.
sharedblocks_subscribe_form_validate Validate callback for subscription block add/edit form.
sharedblocks_subscribe_page Callback for admin/structure/sharedblocks/subscribe