You are here

contentoptimizer.module in Content Optimizer 6

Analyzes node content for search engine optimization recommendations

File

contentoptimizer.module
View source
<?php

/**
 * @file
 * Analyzes node content for search engine optimization recommendations
 */

/**
 * Implementation of hook_menu().
 */
function contentoptimizer_menu() {
  $items = array();
  $items['admin/settings/contentoptimizer'] = array(
    'title' => 'Content optimizer',
    'description' => 'Analize and optimize node content.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'contentoptimizer_admin_settings',
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer page titles',
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'contentoptimizer.admin.inc',
  );
  $items['contentoptimizer/analyze_js'] = array(
    'title' => '',
    'page callback' => 'contentoptimizer_analyze_js',
    'access callback' => true,
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implementation of hook_form_alter().
 *
 * Add Content Optimizer field set to node edit forms.
 */
function contentoptimizer_form_alter(&$form, $form_state, $form_id) {
  if (isset($form['type']['#value']) && $form['type']['#value'] . '_node_form' == $form_id) {

    // Add the Location fields on the Node edit form
    $node = $form['#node'];
    $settings = variable_get('contentoptimizer_settings', array());
    $form['contentoptimizer'] = contentoptimizer_form($settings, $node);
    $form['#submit'][] = 'contentoptimizer_node_submit';
  }
}

/**
 * Get form elements for editing keyword.
 */
function contentoptimizer_form($settings, $node) {
  drupal_add_css(drupal_get_path('module', 'contentoptimizer') . '/contentoptimizer.css');
  $display = variable_get('contentoptimizer_display', array(
    'sections',
    'main',
  ));
  drupal_add_js(array(
    'contentoptimizer' => array(
      'analyze_callback' => base_path() . 'contentoptimizer/analyze_js',
      'nid' => $node->nid,
      'display_sections' => $display['sections'] ? 1 : 0,
      'display_main' => $display['main'] ? 1 : 0,
      'analyze_on_start' => variable_get('contentoptimizer_analyze_on_start', '0'),
    ),
  ), 'setting');
  drupal_add_js(drupal_get_path('module', 'contentoptimizer') . '/contentoptimizer.js');
  $sql = '
    SELECT keyword
    FROM {contentoptimizer_keyword}
    WHERE nid = %d
  ';
  $keyword = db_result(db_query($sql, $node->nid));
  $numforms = 1;
  $form['contentoptimizer'] = array(
    '#type' => 'fieldset',
    '#title' => t('Content optimizer'),
    '#tree' => TRUE,
    '#attributes' => array(
      'class' => 'contentoptimizer',
    ),
    '#weight' => 10,
    //'#weight' => $settings['form']['weight'],
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );
  if ($numforms == 1) {
    $form['contentoptimizer']['keyword'] = array(
      '#type' => 'textfield',
      '#title' => t('Targeted keyword phrase'),
      '#default_value' => $keyword,
    );
    $form['contentoptimizer']['analyze'] = array(
      '#type' => 'button',
      '#value' => t('Analyze Content'),
      '#attributes' => array(
        "onclick" => "contentoptimizer_analyze(); return (false);",
      ),
    );
  }
  return $form;
}
function contentoptimizer_node_submit($form, &$form_state) {

  //print "contentoptimizer_node_submit($form,$form_state)";

  //print_r($form_state);
  $sql = '
    UPDATE {contentoptimizer_keyword}
    SET keyword = "%s"
    WHERE nid = %d
  ';
  db_query($sql, $form_state['values']['contentoptimizer']['keyword'], $form_state['values']['nid']);
  if (!db_affected_rows()) {
    $sql = '
  	  INSERT INTO {contentoptimizer_keyword}
  	  (nid,keyword) VALUES
  	  (%d,"%s")
  	';
    db_query($sql, $form_state['values']['nid'], $form_state['values']['contentoptimizer']['keyword']);
  }
}
function contentoptimizer_analyze_js() {
  $ret = array();
  $ret['status'] = TRUE;
  $keyword = strtolower($_REQUEST['keyword']);
  $node = node_load($_REQUEST['nid']);
  $check_meta = true;
  $ret['general']['section_label'] = t('General');
  $ret['general']['recommendations'] = array();
  $node->title = $_REQUEST['title'];
  if ($_REQUEST['page_title'] && $_REQUEST['page_title'] != -1) {
    $node->page_title = $_REQUEST['page_title'];
  }
  $_GET['q'] = 'node/' . $node->nid;
  $title = $_REQUEST['title'];
  if (module_exists('page_title')) {
    $page_title_pattern = variable_get('page_title_type_' . (isset($node->type) ? $node->type : ''), '');
    if (empty($page_title_pattern)) {
      $page_title_pattern = variable_get('page_title_default', '[page-title] | [site-name]');
    }
    $page_title_pattern = str_replace('[page-title]', $_REQUEST['page_title'] && $_REQUEST['page_title'] != -1 ? $_REQUEST['page_title'] : $_REQUEST['title'], $page_title_pattern);
    $page_title_pattern = str_replace('[title]', check_plain($_REQUEST['title']), $page_title_pattern);
    $page_title_pattern = str_replace('[title-raw]', $_REQUEST['title'], $page_title_pattern);
    $types = array();
    if (isset($node)) {
      $types['node'] = $node;
    }
    $types['page_title'] = NULL;

    //Apply token patterns using token_replace_multiple
    $page_title = token_replace_multiple($page_title_pattern, $types);
  }
  else {
    $page_title = $_REQUEST['title'];
    $ret['general']['recommendations'][] = t('The <a href="http://drupal.org/project/page_title" target="_blank">Page Title</a> module is not installed. We recommend installing it for enhanced control of page titles.');
  }
  if (!module_exists('nodewords')) {
    $check_meta = false;
    $ret['general']['recommendations'][] = t('The <a href="http://drupal.org/project/nodewords" target="_blank">Meta Tags / Nodewords</a> module is not installed. We recommend installing to enable editing of page meta information.');
  }
  $page_title0 = $page_title;
  $page_title = strtolower($page_title);
  $ret['page_title'] = contentoptimizer_calc_stats($page_title, $keyword);
  $ret['page_title']['section_label'] = t('Page title');
  $ret['page_title']['recommendations'] = array();
  if ($ret['page_title']['char_count'] > 70) {
    $ret['page_title']['recommendations'][] = t('Page titles should be no longer than 70 characters. Your title is currently ' . $ret['page_title']['char_count'] . ' characters. Reduce the text in your page title.');
  }
  else {
    if ($ret['page_title']['word_count'] > 12) {
      $ret['page_title']['recommendations'][] = t('Page titles should be no longer than 12 word. Your title is currently ' . $ret['page_title']['word_count'] . ' words. Reduce the number of words in your page title.');
    }
    else {
      if ($ret['page_title']['word_count'] < 5 && $ret['page_title']['char_count'] < 40) {
        $ret['page_title']['recommendations'][] = t('Page titles are the most important content area for optimization. You currently have only ' . $ret['page_title']['word_count'] . ' words. Add some descriptive keywords to your title.');
      }
    }
  }
  if ($keyword) {
    if ($ret['page_title']['keyword_count'] == 0) {
      $ret['page_title']['recommendations'][] = t('Your keyword phrase does not appear in the title. Add your kewyords to your title.');
    }
    else {
      if ($ret['page_title']['keyword_count'] > 2) {
        $ret['page_title']['recommendations'][] = t('Your keyword phrase appears more than 2 times in the page title. Reduce the number of times the keywords instances to less than 2.');
      }
    }
    if ($ret['page_title']['keyword_prominence'] < 50) {
      $ret['page_title']['recommendations'][] = t('Your keyword proninence is less that 50%. Increase your keyword\'s prominence by moving it closer to the begining of your page title.');
    }
  }
  else {
    $ret['page_title']['recommendations'][] = t('No keyword phrase was submitted for analysis. Input a keyword for more targeted recommendations.');
  }
  $ret['page_title']['msg'] .= theme_contentoptimizer_analysis_section_msg($ret['page_title'], $keyword, $page_title0);

  // analize body
  if (1 == 1) {
    $body .= "<h2>" . $_REQUEST['title'] . "</h2>\n";
  }
  $body .= $_REQUEST['body'];
  $body0 = $body;
  $body = strtolower($body);
  $body_notags = strip_tags($body);
  $ret['body'] = contentoptimizer_calc_stats($body_notags, $keyword);
  $ret['body']['section_label'] = t('Body: node title + node body');
  $body_words_min = 200;
  $body_words_max = 800;
  $body_frequency_min = 2;
  $body_frequency_max = 4;
  $ret['body']['recommendations'] = array();
  if ($ret['body']['word_count'] < $body_words_min) {
    $ret['body']['recommendations'][] = t('Your body should be between %min and %max words. It is currently %words. Increase the number of words.', array(
      '%min' => $body_words_min,
      '%max' => $body_words_max,
      '%words' => $ret['body']['word_count'],
    ));
  }
  else {
    if ($ret['body']['word_count'] > $body_words_max) {
      $ret['body']['recommendations'][] = t('Your body should be between %min and %max words. It is currently %words. Reduce the number of words.', array(
        '%min' => $body_words_min,
        '%max' => $body_words_max,
        '%words' => $ret['body']['word_count'],
      ));
    }
  }
  if ($keyword) {
    if ($ret['body']['keyword_count'] < $body_frequency_min) {
      $ret['body']['recommendations'][] = t('Your keyword phrase should occur in your body between %min and %max times. It is currently occurs only %frequency time. Increase the number of keyword occurences in your body copy.', array(
        '%min' => $body_frequency_min,
        '%max' => $body_frequency_max,
        '%frequency' => $ret['body']['keyword_count'],
      ));
    }
    else {
      if ($ret['body']['keyword_count'] > $body_frequency_max) {
        $ret['body']['recommendations'][] = t('Your keyword phrase should occur in your body between %min and %max times. It is currently occurs only %frequency time. Reduce the number of keyword occurences in your body copy.', array(
          '%min' => $body_frequency_min,
          '%max' => $body_frequency_max,
          '%frequency' => $ret['body']['keyword_count'],
        ));
      }
    }
    if ($ret['body']['keyword_prominence'] < 50) {
      $ret['body']['recommendations'][] = t('Your keyword proninence is less that 50%. Increase your keyword\'s prominence by moving occurences closer to the begining of your copy.');
    }
  }
  else {
    $ret['body']['recommendations'][] = t('No keyword phrase was submitted for analysis. Input a keyword for more targeted recommendations.');
  }
  $ret['body']['msg'] = theme_contentoptimizer_analysis_section_msg($ret['body'], $keyword, $body0);

  // analize meta description
  if ($check_meta && $_REQUEST['meta_description'] != -1) {
    $meta_description .= strtolower(strip_tags($_REQUEST['meta_description']));
    $ret['meta_description'] = contentoptimizer_calc_stats($meta_description, $keyword);
    $ret['meta_description']['section_label'] = t('Meta description');
    $meta_description_words_min = 10;
    $meta_description_words_max = 50;
    $meta_description_frequency_min = 0;
    $meta_description_frequency_max = 2;
    $ret['meta_description']['recommendations'] = array();
    if ($ret['meta_description']['word_count'] < $meta_description_words_min) {
      $ret['meta_description']['recommendations'][] = t('Your meta description should be between %min and %max words. It is currently %words. Increase the number of words.', array(
        '%min' => $meta_description_words_min,
        '%max' => $meta_description_words_max,
        '%words' => $ret['meta_description']['word_count'],
      ));
    }
    else {
      if ($ret['meta_description']['word_count'] > $meta_description_words_max) {
        $ret['meta_description']['recommendations'][] = t('Your meta description should be between %min and %max words. It is currently %words. Reduce the number of words.', array(
          '%min' => $meta_description_words_min,
          '%max' => $meta_description_words_max,
          '%words' => $ret['meta_description']['word_count'],
        ));
      }
    }
    if ($keyword) {
      if ($ret['meta_description']['keyword_count'] < $meta_description_frequency_min) {
        $ret['meta_description']['recommendations'][] = t('Your keyword phrase should occur in your meta description between %min and %max times. It is currently occurs only %frequency time. Increase the number of keyword occurences in your meta description copy.', array(
          '%min' => $meta_description_frequency_min,
          '%max' => $meta_description_frequency_max,
          '%frequency' => $ret['meta_description']['keyword_count'],
        ));
      }
      else {
        if ($ret['meta_description']['keyword_count'] > $meta_description_frequency_max) {
          $ret['meta_description']['recommendations'][] = t('Your keyword phrase should occur in your meta description between %min and %max times. It is currently occurs only %frequency time. Reduce the number of keyword occurences in your meta description copy.', array(
            '%min' => $meta_description_frequency_min,
            '%max' => $meta_description_frequency_max,
            '%frequency' => $ret['meta_description']['keyword_count'],
          ));
        }
      }

      //if($ret['meta_description']['keyword_prominence'] < 50) {

      //  $ret['meta_description']['recommendations'][] = t('Your keyword proninence is less that 50%. Increase your keyword\'s prominence by moving occurences closer to the begining of your copy.');

      //}
    }
    else {
      $ret['meta_description']['recommendations'][] = t('No keyword phrase was submitted for analysis. Input a keyword for more targeted recommendations.');
    }
    $ret['meta_description']['msg'] = theme_contentoptimizer_analysis_section_msg($ret['meta_description'], $keyword);
  }

  // analize meta keywords
  if ($check_meta && $_REQUEST['meta_keywords'] != -1) {
    $meta_keywords = strtolower($_REQUEST['meta_keywords']);
    $ret['meta_keywords'] = contentoptimizer_calc_stats($meta_keywords, $keyword);
    $ret['meta_keywords']['section_label'] = t('Meta keywords');
    $meta_keyword_segs = explode(',', $meta_keywords);
    $ret['meta_keywords']['phrase_count'] = count($meta_keyword_segs);
    $meta_keywords_words_min = 5;
    $meta_keywords_words_max = 50;
    $meta_keywords_phrase_min = 1;
    $meta_keywords_phrase_max = 15;
    $meta_keywords_frequency_min = 1;
    $meta_keywords_frequency_max = 2;
    $ret['meta_keywords']['recommendations'] = array();
    if ($ret['meta_keywords']['word_count'] < $meta_keywords_words_min) {
      $ret['meta_keywords']['recommendations'][] = t('Your meta keywords should be between %min and %max words. It is currently %words. Increase the number of words.', array(
        '%min' => $meta_keywords_words_min,
        '%max' => $meta_keywords_words_max,
        '%words' => $ret['meta_keywords']['word_count'],
      ));
    }
    else {
      if ($ret['meta_keywords']['word_count'] > $meta_keywords_words_max) {
        $ret['meta_keywords']['recommendations'][] = t('Your meta keywords should be between %min and %max words. It is currently %words. Reduce the number of words.', array(
          '%min' => $meta_keywords_words_min,
          '%max' => $meta_keywords_words_max,
          '%words' => $ret['meta_keywords']['word_count'],
        ));
      }
    }
    if ($ret['meta_keyphrases']['phrase_count'] < $meta_keyphrases_phrases_min) {
      $ret['meta_keyphrases']['recommendations'][] = t('Your meta keywords should include %min and %max phrases. There are currently %phrases. Increase the number of phrases.', array(
        '%min' => $meta_keyphrases_phrases_min,
        '%max' => $meta_keyphrases_phrases_max,
        '%phrases' => $ret['meta_keyphrases']['phrase_count'],
      ));
    }
    else {
      if ($ret['meta_keyphrases']['phrase_count'] > $meta_keyphrases_phrases_max) {
        $ret['meta_keyphrases']['recommendations'][] = t('Your meta keywords should include %min and %max phrases. There are currently %phrases. Reduce the number of phrases.', array(
          '%min' => $meta_keyphrases_phrases_min,
          '%max' => $meta_keyphrases_phrases_max,
          '%phrases' => $ret['meta_keyphrases']['phrase_count'],
        ));
      }
    }
    if ($keyword) {
      if ($ret['meta_keywords']['keyword_count'] < $meta_keywords_frequency_min) {
        $ret['meta_keywords']['recommendations'][] = t('Your keyword phrase should occur in your meta keywords between %min and %max times. It is currently occurs only %frequency time. Increase the number of keyword occurences in your meta keywords.', array(
          '%min' => $meta_keywords_frequency_min,
          '%max' => $meta_keywords_frequency_max,
          '%frequency' => $ret['meta_keywords']['keyword_count'],
        ));
      }
      else {
        if ($ret['meta_keywords']['keyword_count'] > $meta_keywords_frequency_max) {
          $ret['meta_keywords']['recommendations'][] = t('Your keyword phrase should occur in your meta keywords between %min and %max times. It is currently occurs only %frequency time. Increase the number of keyword occurences in your meta keywords.', array(
            '%min' => $meta_keywords_frequency_min,
            '%max' => $meta_keywords_frequency_max,
            '%frequency' => $ret['meta_keywords']['keyword_count'],
          ));
        }
      }
      if ($ret['meta_keywords']['keyword_prominence'] < 30) {
        $ret['meta_keywords']['recommendations'][] = t('Your keyword proninence is less that 30%. Increase your keyword\'s prominence by moving occurences closer to the begining of your copy.');
      }
    }
    else {
      $ret['meta_keywords']['recommendations'][] = t('No keyword phrase was submitted for analysis. Input a keyword for more targeted recommendations.');
    }
    $ret['meta_keywords']['msg'] = theme_contentoptimizer_analysis_section_msg($ret['meta_keywords'], $keyword);
  }
  if (module_exists('setags') && variable_get('contentoptimizer_include_setags', 0)) {
    $context = $page_title . "\n" . $body;
    $setags = setags_extract_tags_api($context);
    $setags_msg .= "<h3>Extracted Tags</h3>";
    $setags_msg .= "<ol>\n";
    if (is_array($setags)) {
      foreach ($setags as $key => $term) {
        $setags_msg .= '<li>' . $term . "</li>\n";
      }
    }
    else {
      $setags_msg .= '<li>' . t('No terms returned') . "</li>\n";
    }
    $setags_msg .= "</ol>\n";
    $ret['general']['msg_post_recs'] = $setags_msg;
  }
  $ret['general']['msg'] = theme_contentoptimizer_analysis_general_msg($ret, $keyword);
  drupal_json($ret);
}
function contentoptimizer_calc_stats($content, $keyword) {
  $ret = array();
  $ret['char_count'] = strlen($content);
  $ret['word_count'] = str_word_count($content);
  if ($keyword) {
    $content_segs = explode($keyword, $content);
    $ret['keyword_count'] = count($content_segs) - 1;
    $ret['keyword_density'] = 0;
    if ($ret['word_count']) {
      $ret['keyword_density'] = 100 * $ret['keyword_count'] / $ret['word_count'];
    }
    $ret['keyword_positionsum'] = 0;
    $i = 0;
    foreach ($content_segs as $seg) {
      if ($i >= $ret['keyword_count']) {
        break;
      }
      $wordpos = str_word_count($seg) + 1;
      $ret['keyword_positionsum'] += $wordpos;
      $i++;
    }

    // prominence = ($totalwords - (($positionsum - 1) / $positionsnum)) * (100 / $totalwords)
    $ret['keyword_prominence'] = 0;
    if ($ret['keyword_count']) {
      $ret['keyword_prominence'] = ($ret['word_count'] - ($ret['keyword_positionsum'] - 1) / $ret['keyword_count']) * (100 / $ret['word_count']);
    }
  }
  return $ret;
}
function theme_contentoptimizer_analysis_section_msg($data, $keyword, $content = '') {
  $content = htmlentities($content);
  if (strlen($content) > 100) {
    $content = substr($content, 0, 100) . '...';
  }
  $msg .= '<div class="contentoptimizer_analysis">' . "\n";
  $msg .= '<div class="' . ($data['recommendations'] ? "warning" : "status") . '">' . "\n";
  $msg .= '<h3>' . t('Content optimizer analysis') . ($data['section_label'] ? " (" . $data['section_label'] . ")" : "") . "</h3>\n";
  $msg .= '<pre>' . $content . "</pre>\n";
  $msg .= t('chars') . " = " . $data['char_count'];
  $msg .= ", " . t('words') . " = " . $data['word_count'];
  if ($keyword) {
    $msg .= ", " . t('frequency') . " = " . $data['keyword_count'];
    $msg .= ", " . t('density') . " = " . number_format($data['keyword_density'], 1) . "%";
    $msg .= ", " . t('prominence') . " = " . number_format($data['keyword_prominence'], 1) . "%";
  }
  if ($data['msg_pre_recs']) {
    $msg .= "<br />\n" . $data['msg_pre_recs'];
  }
  if (!$data['recommendations']) {
    $data['recommendations'][] = t('Optimized');
  }
  $msg .= "\n<ul>\n";
  foreach ($data['recommendations'] as $rec) {
    $msg .= "<li>{$rec}</li>\n";
  }
  $msg .= "</ul>\n";
  if ($data['msg_post_recs']) {
    $msg .= "<br />\n" . $data['msg_post_recs'];
  }
  $msg .= '<input class="form-submit" type="button" onclick="contentoptimizer_analyze(); return (false);" value="' . t('Analyze Content') . '"/>';
  $msg .= "</div>\n";
  $msg .= "</div>\n";
  return $msg;
}
function theme_contentoptimizer_analysis_general_msg($data, $keyword) {
  $status = "status";
  if ($data['page_title']['recommendations'] || $data['body']['recommendations']) {
    $status = "warning";
  }
  $msg .= '<div class="contentoptimizer_analysis">' . "\n";
  $msg .= '<div class="' . $status . '">' . "\n";
  $msg .= '<h3>' . t('Content optimizer analysis') . "</h3>\n";
  if ($data['general']['msg_pre_recs']) {
    $msg .= "<br />\n" . $data['general']['msg_pre_recs'];
  }
  foreach ($data as $section => $d) {
    if (!$d['section_label']) {
      continue;
    }
    if (!$d['recommendations']) {
      if ($section == 'general') {
        $d['recommendations'][] = t('OK - no general recommendations');
      }
      else {
        $d['recommendations'][] = t('Optimized');
      }
    }
    $msg .= "<h4>" . $d['section_label'] . "</h4>\n";
    $msg .= "<ul>\n";
    foreach ($d['recommendations'] as $rec) {
      $msg .= "<li>{$rec}</li>\n";
    }
    $msg .= "</ul>\n";
  }
  if ($data['general']['msg_post_recs']) {
    $msg .= "<br />\n" . $data['general']['msg_post_recs'];
  }
  $msg .= "</div>\n";
  $msg .= "</div>\n";
  return $msg;
}