seowatcher_get_provider_name($provider), 'class' => 'checkbox');
}
$rows = array();
// construct table body
for ($i = 1 ; $i <= MAX_KEYWORDS ; $i++) {
$keyword = variable_get('seowatcher_keyword_' . $i, '');
$keyword = preg_replace('/^\s*?/', '', $keyword); // remove leading space
$keyword = preg_replace('/\s*?$/', '', $keyword); // remove trailing space
if (empty($keyword)) continue;
$row = array();
$row[] = array('data' => $keyword, 'align' => 'left');
// loop for all providers
foreach ($providers as $provider) {
if (!$ranks) {
$rank = $_SESSION['seowatcher_' . $i][$provider];
}
else {
$rank = $ranks['seowatcher_' . $i][$provider];
}
$row[] = array('data' => ($rank != -1) ? $rank : t('-'), 'align'=> 'center');
}
$rows[] = $row;
}
$output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('style' => 'width: 90%')));
return $output;
}
/**
* Generate a table of competitive ranking result
*
* Note: if $ranks is NULL, then use $_SESSION variable
* If there's no competitive sites specified, it return NULL
*/
function seowatcher_generate_competitive_table($ranks = NULL) {
global $base_url;
$my_url = variable_get('seowatcher_site_url', $base_url);
$target_url = seowatcher_get_competitor_url();
array_unshift($target_url, $my_url); // add my URL at the top
$num_target = count($target_url);
if ($num_target <= 1) { // no competitive sites
return '';
}
$output = '';
$providers = seowatcher_get_target_providers();
for ($i = 1 ; $i <= MAX_KEYWORDS ; $i++) {
$keyword = variable_get('seowatcher_keyword_' . $i, '');
$keyword = preg_replace('/^\s*?/', '', $keyword); // remove leading space
$keyword = preg_replace('/\s*?$/', '', $keyword); // remove trailing space
if (empty($keyword)) continue;
// construct table header
$header = array();
$header[] = t('Site URL');
foreach ($providers as $provider) {
// class="checkbox" will align the header text to be centered
$search_query_url = seowatcher_get_search_query_url($provider, $keyword);
$provider_anchor = '' . seowatcher_get_provider_name($provider) . '';
$header[] = array('data' => $provider_anchor, 'class' => 'checkbox');
}
$rows = array();
// construct table body
for ($target = 0 ; $target < $num_target ; $target++) {
$url = $target_url[$target];
$row = array();
if ($target == 0) {
$row[] = array('data' => t('This site') . ' (' . $url . ')', 'align' => 'left');
}
else {
$target_anchor = '' . $url . '';
$row[] = array('data' => $target_anchor, 'align' => 'left');
}
// loop for all providers
foreach ($providers as $provider) {
if (!$ranks) {
$rank = $_SESSION['seowatcher_keyword_' . $i][$provider][$url];
}
else {
$rank = $ranks['seowatcher_keyword_' . $i][$provider][$url];
}
$row[] = array('data' => ($rank != -1) ? $rank : t('-'), 'align'=> 'center');
}
$rows[] = $row;
}
$output .= '
' . t('Keyword') . ': ' . $keyword . '
' . "\n";
$output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('style' => 'width: 90%')));
$output .= "\n";
}
return $output;
}
/**
* Generate ranking chart by keyword (using Google Chart API)
*/
function seowatcher_generate_keyword_graph($keyword) {
$chart_width = variable_get('seowatcher_chart_width', 480);
$max_rank = variable_get('seowatcher_max_rank', 100);
$legend = '';
$rank = '';
$output = '';
$data = seowatcher_get_ranking_info($keyword);
$best = $data->best;
$worst = $data->worst;
$oldest = date('M-d', $data->oldest);
$latest = date('M-d', $data->latest);
$providers = seowatcher_get_target_providers();
foreach ($providers as $provider) {
$ranks = seowatcher_load_past_rankings($provider, $keyword);
$legend .= seowatcher_get_provider_name($provider) . '|';
foreach ($ranks as $date => $val) {
if ($val <= 0) $val = 999; // not found!
$rank .= $val . ','; // $val -1 means "no data"
}
$rank = rtrim($rank, ','); // drop trailing comma
$rank .= '|'; // connect to next provider's data
}
$legend = rtrim($legend, '|'); // drop trailing |
$rank = rtrim($rank, '|'); // drop trailing |
$y_range_min = $worst + 2;
$y_range_max = $best - 2;
if ($y_range_max < 1) $y_range_max = 1;
$chart_height = (int)($chart_width * 2 / 3);
// construct URL for Google Chart API
$output .= ' . ': ' . $keyword
. '&chts=444444,18' // title size (16px)
. '&cht=lc' // char type: line chart
. '&chs=' . $chart_width . 'x' . $chart_height
. '&chdl=' . $legend
. '&chdlp=t' // legend at top
. '&chxt=x,y' // axis
. '&chxl=0:|' . $oldest . '|' . $latest // x-axis label
. '&chxr=0,0,365|' // x-axis range
. '1,' . $y_range_min . ',' . $y_range_max // y-axis range
. '&chds=' . $y_range_min . ',' . $y_range_max
. '&chco=dd6666,eecc22,6666ff,66dd22,0000ff,888888' // line colors
. '&chd=t:' . $rank;
$output .= ')
' . "\n";
return $output;
}
/**
* Load the current(=latest) ranking from database
*
* return: 2D array array['keyword']['provider'] => rank
*/
function seowatcher_load_current_ranking() {
$output = array();
$providers = seowatcher_get_target_providers();
for ($i = 1 ; $i <= MAX_KEYWORDS ; $i++) {
$keyword = variable_get('seowatcher_keyword_' . $i, '');
$keyword = preg_replace('/^\s*?/', '', $keyword); // remove leading space
$keyword = preg_replace('/\s*?$/', '', $keyword); // remove trailing space
if (empty($keyword)) continue;
// loop for all providers
foreach ($providers as $provider) {
// get latest rank for the provider and keyword
$rank = db_query("SELECT rank FROM {seowatcher} WHERE provider=:provider AND keyword=:keyword ORDER BY date DESC LIMIT 1", array(':provider' => $provider, ':keyword' => $keyword))->fetchField();
$output['seowatcher_' . $i][$provider] = $rank;
}
}
return $output;
}
function seowatcher_get_ranking_info($keyword) {
// limits to 1 year
$one_year_ago = mktime(0, 0, 0, date("m"), date("d"), (date("Y")-1));
$data = db_query("SELECT MAX(rank) AS worst, MIN(rank) AS best, MIN(date) AS oldest, MAX(date) AS latest FROM {seowatcher} WHERE keyword=:keyword AND rank > 0 AND date > :date", array(':keyword' => $keyword, ':date' => $one_year_ago))->fetchObject();
return $data;
}
/**
* Delete rankings that are older than 1 year
*
* Note: this function is called from hook_cron.
*/
function seowatcher_delete_old_rankings() {
$one_year_ago = mktime(0, 0, 0, date("m"), date("d"), (date("Y")-1));
db_delete('seowatcher')
->condition('date', $one_year_ago, '<')
->execute();
}
/**
* Load past rankings from database
*/
function seowatcher_load_past_rankings($provider, $keyword) {
// limits to 1 year
$one_year_ago = mktime(0, 0, 0, date("m"), date("d"), (date("Y")-1));
$result = db_query("SELECT date, rank FROM {seowatcher} WHERE provider=:provider AND keyword=:keyword AND date > :date ORDER BY date", array(':provider' => $provider, ':keyword' => $keyword, ':date' => $one_year_ago));
$ranks = array();
foreach ($result as $data) {
$ranks[$data->date] = $data->rank;
}
return $ranks;
}
/**
* Load competitive rankings from database
*/
function seowatcher_load_competitive_rankings() {
$ranks = array();
for ($i = 1 ; $i <= MAX_KEYWORDS ; $i++) {
$keyword = variable_get('seowatcher_keyword_' . $i, '');
$keyword = preg_replace('/^\s*?/', '', $keyword); // remove leading space
$keyword = preg_replace('/\s*?$/', '', $keyword); // remove trailing space
if (empty($keyword)) continue;
$result = db_query("SELECT * FROM {seowatcher_competitive} WHERE keyword=:keyword", array(':keyword' => $keyword));
foreach ($result as $data) {
$provider = $data->provider;
$url = $data->url;
$rank = $data->rank;
$ranks['seowatcher_keyword_' . $i][$provider][$url] = $rank;
}
}
return $ranks;
}
/**
* Save ranking of my site info to database
*/
function seowatcher_save_my_ranking($provider, $keyword, $max_rank, $rank) {
$today = mktime(0, 0, 0, date("m"), date("d"), date("Y"));
$result = db_query("SELECT * FROM {seowatcher} WHERE provider=:provider AND keyword=:keyword AND max_rank=:max_rank AND date=:date", array(':provider' => $provider, ':keyword' => $keyword, ':max_rank' => $max_rank, ':date' => $today));
if ($result->rowCount()) {
// update
db_update('seowatcher')
->fields(array('rank' => $rank))
->condition('provider', $provider)
->condition('keyword', $keyword)
->condition('max_rank', $max_rank)
->condition('date', $today)
->execute();
}
else {
// insert
db_insert('seowatcher')
->fields(array(
'date' => $today,
'keyword' => $keyword,
'provider' => $provider,
'max_rank' => $max_rank,
'rank' => $rank,
))
->execute();
}
}
/**
* Delete all records from the competitive site rankings
*/
function seowatcher_delete_competitive_ranking() {
db_delete('seowatcher_competitive')->execute();
}
/**
* Save compatitive site rankings to database
*/
function seowatcher_save_competitive_ranking($provider, $keyword, $url, $rank) {
$today = mktime(0, 0, 0, date("m"), date("d"), date("Y"));
db_insert('seowatcher_competitive')
->fields(array(
'date' => $today,
'keyword' => $keyword,
'provider' => $provider,
'url' => $url,
'rank' => $rank,
))
->execute();
}
/**
* Erase all past ranking data from the database
*/
function seowatcher_delete_ranking_data() {
db_delete('seowatcher')->execute();
db_delete('seowatcher_competitive')->execute();
variable_del('seowatcher_last_executed');
drupal_set_message(t('All ranking data has been deleted successfully'), 'warning');
}
//--------------------------------------------------------------------------------
// Hooks and Form
//--------------------------------------------------------------------------------
/**
* Implements hook_permission().
*/
function seowatcher_permission() {
$permissions = array(
'administer seo watcher' => array(
'title' => t('Administer SEO Watcher module'),
'description' => '',
),
'access seo watcher reports' => array(
'title' => t('Access SEO Wacther reports'),
'description' => t('view the reports generated by SEO Watcher module.'),
),
);
return $permissions;
}
/**
* Implements hook_cron
* Note: Although this function is called every cron time, we will not
* perform the ranking check more than the specified frequency
*
*/
function seowatcher_cron() {
// check to see if we should execute or not
$today = mktime(0, 0, 0, date("m"), date("d"), date("Y"));
$last_executed = variable_get('seowatcher_last_executed', '');
$frequency = variable_get('seowatcher_frequency', 1);
if ($last_executed != '') {
switch($frequency) {
case 1: // Everyday
$next = strtotime("+1 day", $last_executed);
break;
case 2: // Every week (Sunday)
// $next = strtotime("+1 week", $last_executed);
$next = strtotime("next Sunday", $last_executed);
break;
case 3: // Every month (1st day of the next month)
$next_month = strtotime("+1 month", $last_executed);
$next = mktime(0, 0, 0, date("m", $next_month), 1, date("Y", $next_month));
break;
}
if ($today < $next) return;
}
// update last executed date
$today = mktime(0, 0, 0, date("m"), date("d"), date("Y"));
variable_set('seowatcher_last_executed', $today);
watchdog('cron', 'SEO Watcher cron task started at %time.', array('%time' => format_date(time(), 'custom', 'H:i:s')));
seowatcher_check_ranking(TRUE); // save results to database
seowatcher_delete_old_rankings(); // delete rankings older than 1 year
seowatcher_notify_moderators(); // send notification email to admin (if enabled)
watchdog('cron', 'SEO Watcher cron task completed at %time.', array('%time' => format_date(time(), 'custom', 'H:i:s')));
}
/**
* Form handler for 'Check ranking now' button
*/
function seowatcher_check_now() {
watchdog('seowatcher', 'Temporary rank check started at %time.', array('%time' => format_date(time(), 'custom', 'H:i:s')));
seowatcher_check_ranking(FALSE); // no saving
watchdog('seowatcher', 'Tempoaray rank check completed at %time.', array('%time' => format_date(time(), 'custom', 'H:i:s')));
}
/**
* Check ranking of all keywords from all service provider
*/
function seowatcher_check_ranking($save = FALSE) {
global $base_url;
$max_rank = variable_get('seowatcher_max_rank', 100);
$my_url = variable_get('seowatcher_site_url', $base_url);
$target_url = seowatcher_get_competitor_url();
array_unshift($target_url, $my_url); // add my URL at the top
$num_target = count($target_url);
if ($save && $num_target > 1) {
// clear old records
seowatcher_delete_competitive_ranking();
}
$providers = seowatcher_get_target_providers();
// loop for all keywords
for ($i = 1 ; $i <= MAX_KEYWORDS ; $i++) {
$keyword = variable_get('seowatcher_keyword_' . $i, '');
$keyword = preg_replace('/^\s*?/', '', $keyword); // remove leading space
$keyword = preg_replace('/\s*?$/', '', $keyword); // remove trailing space
if (empty($keyword)) continue;
// loop for all providers
foreach ($providers as $provider) {
$rank = seowatcher_get_ranking($provider, $keyword, $target_url, $max_rank);
if ($save) {
seowatcher_save_my_ranking($provider, $keyword, $max_rank, $rank[0]);
}
else {
$_SESSION['seowatcher_' . $i][$provider] = $rank[0];
}
if ($num_target > 1) {
for ($target = 0 ; $target < $num_target ; $target++) {
$url = $target_url[$target];
if ($save) {
seowatcher_save_competitive_ranking($provider, $keyword, $url, $rank[$target]);
}
else {
$_SESSION['seowatcher_keyword_' . $i][$provider][$url] = $rank[$target];
}
}
}
}
}
}
/**
* Notify moderators the checking result via an email
*
* Note: This function is called from hook_cron
*
*/
function seowatcher_notify_moderators() {
$emails = array();
//-------------------------------------
// by roles
//-------------------------------------
$roles = variable_get('seowatcher_notify_roles', array());
$rid_array = array();
foreach($roles as $rid => $rname) {
if ($rid == 0) { // admin
// get admin email
$admin = user_load(1); // uid 1 is admin
$emails[] = $admin->mail;
}
else {
$rid_array[] = $rid;
}
if(count($rid_array)) {
// get email of all active (not blocked) users in the selected roles
$result = db_query("SELECT DISTINCT u.uid, u.name, u.mail FROM {users} u INNER JOIN {users_roles} ur ON u.uid = ur.uid WHERE ur.rid IN (". implode(",", $rid_array) . ") AND u.status=1");
}
foreach ($result as $user) {
$emails[] = $user->mail;
}
}
//-------------------------------------
// additional emails
//-------------------------------------
$receipients = preg_split("/\n/", variable_get('seowatcher_notify_receipients', ''), -1, PREG_SPLIT_NO_EMPTY);
foreach ($receipients as $email) {
$email = preg_replace('/\s/', '', $email);
if (empty($email)) continue;
if (seowatcher_is_valid_email($email)) {
$emails[] = $email; // add email
}
}
if (!count($emails)) {
return; // no receipients
}
$report = '';
// generate report
$ranks = seowatcher_load_current_ranking();
$output = seowatcher_generate_ranking_table($ranks) . "\n";
$report .= '' . t('Ranking of this site') . '
' . "\n";
$report .= $output . '
' . "\n";
$ranks = seowatcher_load_competitive_rankings();
$output = seowatcher_generate_competitive_table($ranks);
if ($output) {
$report .= '' . t('Competitive analysis') . '
' . "\n";
$report .= $output . '
' . "\n";
}
$style = 'table { border-spacing: 0; border-collapse: collapse; } tr { border: solid 1px #ccc; } td { padding: 2px; } thead { background-color: #eee; }';
$today = date("Y-m-d");
$report_url = url('admin/reports/seowatcher', array('absolute' => TRUE));
$report_page = '' . $report_url . '';
$message_args = array(
'!today' => $today,
'!report' => $report,
'!report_page' => $report_page,
'!br1' => '
',
'!br2' => '
',
);
// I know it's a bit ugly, but I wanted to make this HTML mail message
// translatable to other languages
$message_body = '';
EOT;
$message_body .= t('Hello, !br2 This email was automatically generated by the SEO Watcher module during cron operations. !br1 Below is the ranking chek result on !today.!br2 !report !br1 You can see the past rankings of the site at !report_page !br2 Thank you, !br2', $message_args);
$message_body .= '';
$params = array(
'body' => $message_body,
'subject' => t('[@site-name] SEO Watcher Report', array('@site-name' => variable_get('site_name', t('Drupal')))),
);
// send email
foreach($emails as $email) {
drupal_mail('seowatcher', date("Y-m-d"), $email, language_default(), $params);
}
}
/**
* Implements hook_mail
*/
function seowatcher_mail($key, &$message, $params) {
$headers = array(
'MIME-Version' => '1.0',
'Content-Type' => 'text/html; charset=UTF-8; format=flowed',
'Content-Transfer-Encoding' => '8Bit',
'X-Mailer' => 'Drupal',
);
foreach ($headers as $key => $value) {
$message['headers'][$key] = $value;
}
$message['subject'] = $params['subject'];
$message['body'][] = $params['body'];
}
/**
* Implements hook_menu
*/
function seowatcher_menu() {
$items = array();
// config section
$items['admin/config/search/seowatcher'] = array(
'title' => 'SEO Watcher',
'description' => 'Allow users to configure the search engine ranking settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array('seowatcher_settings_form'),
'access arguments' => array('administer seo watcher'),
);
// report section
$items['admin/reports/seowatcher'] = array(
'title' => 'SEO Watcher',
'description' => 'Allow users to see the search engine ranking.',
'page callback' => 'drupal_get_form',
'page arguments' => array('seowatcher_report_form'),
'access arguments' => array('access seo watcher reports'),
);
return $items;
}
/**
* Form: Configutation Settings
*/
function seowatcher_settings_form($form, &$form_state) {
global $base_url;
//--------------------------------------------------------
// check ranking now and show results if the session
// variables 'seowatcher_check_now' is set.
//--------------------------------------------------------
if (isset($form_state['storage']['seowatcher_check_now'])) {
unset($form_state['storate']['seowatcher_check_now']);
// check the ranking now
seowatcher_check_now();
$form['results'] = array(
'#type' => 'fieldset',
'#title' => t('Check results'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$output = seowatcher_generate_ranking_table();
$form['results']['seowatcher_results'] = array(
'#type' => 'item',
'#markup' => '' . t('Ranking of this site') . '
' . $output . "
\n",
);
$output = seowatcher_generate_competitive_table();
if ($output) {
// show compatitive analysis only when competitive sites are specified.
$form['results']['seowatcher_competitive'] = array(
'#type' => 'item',
'#markup' => '' . t('Competitive analysis') . '
' . $output . "
\n",
);
}
}
//--------------------------------------------------------
$form['seowatcher_site_url'] = array(
'#type' => 'textfield',
'#title' => t('Site URL'),
'#default_value' => variable_get('seowatcher_site_url', $base_url),
'#description' => t('This is the URL of this site and most probably you do not need to change it. It must be an absolute URL starting with http://.'),
'#size' => 40,
'#maxlength' => 40,
);
// show the settings form
for ($i = 1 ; $i <= MAX_KEYWORDS_STD ; $i++) {
$keyword = variable_get('seowatcher_keyword_' . $i, '');
$form['seowatcher_keyword_' . $i] = array(
'#type' => 'textfield',
'#title' => t('Search keyword') . ' ' . $i,
'#default_value' => $keyword,
'#size' => 40,
'#maxlength' => 40,
);
}
$form['more_keywords'] = array(
'#type' => 'fieldset',
'#title' => t('More keywords'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$headnote = t('Please do not use these extra keywords if you perform ranking check everyday. Please consider changing the check frequency to weekly or monthly.
');
$form['more_keywords']['headnote'] = array(
'#type' => 'item',
'#markup' => $headnote,
);
for ($i = MAX_KEYWORDS_STD+1 ; $i <= MAX_KEYWORDS ; $i++) {
$keyword = variable_get('seowatcher_keyword_' . $i, '');
$form['more_keywords']['seowatcher_keyword_' . $i] = array(
'#type' => 'textfield',
'#title' => t('Search keyword') . ' ' . $i,
'#default_value' => $keyword,
'#size' => 40,
'#maxlength' => 40,
);
}
$form['competitive'] = array(
'#type' => 'fieldset',
'#title' => t('Competitive analysis'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$competitive_headnote = t('Enter the URL of the competitive sites that you would like to check. The more competitive sites you add, the more it may take to complete checking. Please enter the full URL starting with http://
');
$form['competitive']['headnote'] = array(
'#type' => 'item',
'#markup' => $competitive_headnote,
);
for ($i = 1 ; $i <= MAX_COMPETITORS ; $i++) {
$competitor_url = variable_get('seowatcher_competitor_' . $i, '');
$form['competitive']['seowatcher_competitor_' . $i] = array(
'#type' => 'textfield',
'#title' => t('Competitor\'s URL ') . $i,
'#default_value' => $competitor_url,
'#size' => 60,
'#maxlength' => 60,
);
}
$competitive_footnote = t('Note: Only the result of the latest competitive analysis is saved to the database.
');
$form['competitive']['footnote'] = array(
'#type' => 'item',
'#markup' => $competitive_footnote,
);
$providers = seowatcher_get_all_providers();
$option = array();
foreach($providers as $provider) {
$provider_name = seowatcher_get_provider_name($provider);
$option[$provider] = $provider_name;
}
$form['seowatcher_searchengines'] = array(
'#type' => 'checkboxes',
'#title' => t('Searh engines to check'),
'#options' => $option,
'#default_value' => variable_get('seowatcher_searchengines', array()),
'#desciption' => t('Select the search engines to be checked.'),
);
$max_rank = variable_get('seowatcher_max_rank', 100);
$form['seowatcher_max_rank'] = array(
'#type' => 'select',
'#title' => t('Maximum rank to check'),
'#default_value' => $max_rank,
'#options' => drupal_map_assoc(array(50, 100, 200, 300)),
'#description' => t('Increasing the maximum rank will increase the time to complete the ranking check. So please make it as minimum as possibe.'),
);
$frequency = variable_get('seowatcher_frequency', 1);
$form['seowatcher_frequency'] = array(
'#type' => 'select',
'#title' => t('Check frequency'),
'#default_value' => $frequency,
'#options' => array(
1 => t('Everyday'),
2 => t('Every week (Sunday)'),
3 => t('Every month (1st day)'),
),
);
$form['seowatcher_chart_width'] = array(
'#type' => 'select',
'#title' => t('Chart width'),
'#default_value' => variable_get('seowatcher_chart_width', 480),
'#options' => drupal_map_assoc(array(320, 400, 480, 540, 600)),
'#description' => t('This is the width of charts in the reports page. Use the width that matches to the width of the admin page of your site. The height of charts are automatically determined based on the width.'),
);
$form['mailreport'] = array(
'#type' => 'fieldset',
'#title' => t('Email report'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$members_only = TRUE;
$roles = user_roles($members_only);
$roles['0'] = t('Admin'); // add admin to the top of the role list
ksort($roles);
$form['mailreport']['seowatcher_notify_roles'] = array(
'#type' => 'select',
'#title' => t('Receipient roles'),
'#default_value' => variable_get('seowatcher_notify_roles', array()),
'#options' => $roles,
'#multiple' => TRUE,
'#size' => 3,
'#description' => t('Select roles that receive email report. You can select multiple roles using Shift/Ctrl keys. Ctrl+click to unselect an item.'),
);
$form['mailreport']['seowatcher_notify_receipients'] = array(
'#type' => 'textarea',
'#title' => t('Additional receipient\'s emails'),
'#default_value' => variable_get('seowatcher_notify_receipients', ''),
'#rows' => 5,
'#cols' => 30,
'#description' => t('Enter one email address per row and do not use comma and other separator between email addresses. If you want to send reports to unregistered person, use this field.'),
);
$form['seowatcher_check_now'] = array(
'#type' => 'checkbox',
'#default_value' => variable_get('seowatcher_check_now', 0),
'#title' => t('Check the ranking with the new settings'),
'#description' => t('If checked, the rankings are checked upon saving the settings. This operation may take a few minutes depending on the settings and search results. The result of this check is not stored to the database.'),
);
// specify form submit handler
$form['#submit'] = array('seowatcher_settings_form_submit');
return system_settings_form($form);
}
/**
* Implements hook_validate()
*/
function seowatcher_settings_form_validate($form_id, $form_values) {
$op = $form_values['values']['op'];
if ($op == t('Cancel')) return;
$keyword_specified = 0;
for ($i = 1 ; $i <= MAX_KEYWORDS ; $i++) {
if (!empty($form_values['values']['seowatcher_keyword_' . $i])) {
$keyword_specified++;
}
}
if (!$keyword_specified) {
drupal_set_message(t('Please specify at least one keyword. SEO Watcher does nothing without a keyword specified.'), 'warning');
}
$frequency = $form_values['values']['seowatcher_frequency'];
if (($keyword_specified > MAX_KEYWORDS_STD) && ($frequency == 1)) {
drupal_set_message(t('Please consider changing check frequency to weekly or monthly for the number of keywords you have specified.'), 'warning');
}
for ($i = 1 ; $i <= MAX_COMPETITORS ; $i++) {
$url = $form_values['values']['seowatcher_competitor_' . $i];
if (!empty($url)) {
if (!valid_url($url, TRUE)) {
form_set_error('seowatcher_competitor_' . $i, t('Invalid URL is specified. Please use full URL starting with http://'));
}
}
}
$receipients = preg_split("/\n/", $form_values['values']['seowatcher_notify_receipients'], -1, PREG_SPLIT_NO_EMPTY);
foreach ($receipients as $email) {
$email = preg_replace('/\s/', '', $email);
if (empty($email)) continue;
if (!seowatcher_is_valid_email($email)) {
form_set_error('seowatcher_notify_receipients', t('Invalid email address is specified.'));
}
}
}
function seowatcher_is_valid_email($email) {
return eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $email);
}
/**
* Settings form submit handler
*/
function seowatcher_settings_form_submit(&$form, &$form_state) {
unset($form_state['storage']['seowatcher_check_now']);
// check to see if we need to check the ranking now
if ($form['seowatcher_check_now']['#value']) {
$form_state['storage']['seowatcher_check_now'] = TRUE;
$form_state['rebuild'] = TRUE;
}
}
/**
* Form: Ranking Report
*/
function seowatcher_report_form($form, &$form_state) {
$form = array();
if (isset($form_state['storage']['seowatcher_delete_confirm'])) {
// confirmation form
unset($form_state['storage']['seowatcher_delete_confirm']);
return seowatcher_confirm_delete($form_state);
}
$latest_date = db_query("SELECT MAX(date) FROM {seowatcher}")->fetchField();
if (!$latest_date) {
$form['seowatcher_results'] = array(
'#type' => 'item',
'#markup' => t('No ranking record found. Please configure the module settings and run cron task first.') . "
\n",
);
return $form;
}
$latest_date = date('M d, Y', $latest_date);
$form['seowatcher_headnot'] = array(
'#type' => 'item',
'#markup' => '' . t('Below is the result of the ranking check performed at the last cron execution on %date. The results may vary depending on the data of the server of the search engine provider it uses. Hyphen in the result means that the site was not found within the maximum rank.', array('%date' => $latest_date)) . '
',
);
//---------- generate a table of the current ranking ----------
$ranks = seowatcher_load_current_ranking();
$output = seowatcher_generate_ranking_table($ranks);
$form['seowatcher_results'] = array(
'#type' => 'item',
'#markup' => '' . t('Ranking of this site') . '
' . $output . "\n",
);
//---------- generate a table of the competitive analysis ----------
$ranks = seowatcher_load_competitive_rankings();
$output = seowatcher_generate_competitive_table($ranks);
if ($output) {
// show compatitive analysis only when competitive sites are specified.
$form['seowatcher_competitive'] = array(
'#type' => 'item',
'#markup' => '' . t('Competitive analysis') . '
' . $output . "\n",
);
}
//---------- generate a chart using Google Chart API -----------
$form['seowatcher_graph_title'] = array(
'#type' => 'item',
'#markup' => '' . t('Past rankings by keyword') . '
'. "\n",
);
// loop for all keywords
for ($i = 1 ; $i <= MAX_KEYWORDS ; $i++) {
$keyword = variable_get('seowatcher_keyword_' . $i, '');
$keyword = preg_replace('/^\s*?/', '', $keyword); // remove leading space
$keyword = preg_replace('/\s*?$/', '', $keyword); // remove trailing space
if (empty($keyword)) continue;
$output = seowatcher_generate_keyword_graph($keyword);
$form['seowatcher_graph_' . $i] = array(
'#type' => 'item',
'#markup' => '
' . $output . "\n",
);
}
if (user_access('administer seo watcher')) {
$form['seowatcher_clear_data'] = array(
'#type' => 'submit',
'#value' => t('Delete all ranking data'),
'#prefix' => '
',
'#suffix' => t(' Note: All past ranking data will be deleted from the database.'),
'#submit' => array('seowatcher_report_form_submit'),
);
}
return $form;
}
/**
* Report form submit handler
*/
function seowatcher_report_form_submit(&$form, &$form_state) {
if (isset($form_state['values']['process'])) {
// it's cofirmed
seowatcher_delete_ranking_data();
return TRUE;
}
// prepare for the confirmation form
$form_state['storage']['seowatcher_delete_confirm'] = TRUE;
$form_state['rebuild'] = TRUE;
}
/**
* Delete confirmation form
*/
function seowatcher_confirm_delete($form_state) {
$form = array();
// specify form submit handler
$form['process'] = array('#type' => 'hidden', '#value' => 'true');
$form['destination'] = array('#type' => 'hidden', '#value' => 'admin/reports/seowatcher');
return confirm_form($form,
NULL, // title
'admin/reports/seowatcher',
t('Are you sure you want to delete all ranking records?'),
t('Delete'),
t('Cancel'));
}
//--------------------------------------------------------------------------------
// Core function - access search engine
//--------------------------------------------------------------------------------
/**
* Get search query URL of the specified keyword
*/
function seowatcher_get_search_query_url($provider, $keywd) {
$keywd = urlencode($keywd); // URL encode
switch ($provider) {
case GOOGLE_JP:
// google.co.jp
$search_url = "http://www.google.co.jp/search";
$option = "?hl=ja"
. "&btnG=Google+%E6%A4%9C%E7%B4%A2"
. "&ie=UTF-8"
. "&oe=UTF-8"
. "&lr="
. "&q=" . $keywd;
break;
case GOOGLE_COM:
// google.com (worldwide)
$search_url = "http://www.google.com/search";
$option = "?btnG=Google+Search"
. "&ie=UTF-8"
. "&oe=UTF-8"
. "&lr="
. "&q=" . $keywd;
break;
case YAHOO_JP:
// yahoo.co.jp
$search_url = "http://search.yahoo.co.jp/search";
$option = "?ei=UTF-8&" . "p=" . $keywd;
break;
case YAHOO_COM:
// yahoo.com (worldwide)
$search_url = "http://search.yahoo.com/search";
$option = "?ei=UTF-8" . "&p=" . $keywd;
break;
case BING_JP:
// bing.co.jp
$search_url = "http://www.bing.co.jp/search";
$option = "?q=" . $keywd;
break;
case BING_COM:
// bing.com (worldwide)
$search_url = "http://www.bing.com/search";
$option = "?q=" . $keywd;
break;
}
return $search_url . $option;
}
/**
* get the ranking of the $target_url from the search result of $keyword
* at the search engine $provider
*
* @param $keywd
* A string of search keyword. Since the string will be urlencoded upon
* executing of the search query, you should not urlencode $keywd i
* parameter before calling this function.
*
* @param $target_url
* A string of a single URL or an array of multiple URLs. If an array of
* mutiple URLs is passed, then the output result will be an array of
* rankings.
*
* @return
* Ranking (-1 is returned if not found within the max_rank)
* It can be either a integer value or an array of integers depending on
* the $target_url parameter passed.
*/
function seowatcher_get_ranking($provider, $keywd, $target_url, $max_rank = 100) {
if ($target_url == NULL) return;
$num_target = is_array($target_url)? count($target_url) : 1;
$base_query = seowatcher_get_search_query_url($provider, $keywd);
// DEBUG
// print "base_query: " . $base_query . "
\n"; // DEBUG
switch ($provider) {
case GOOGLE_COM: // google.com (worldwide)
case GOOGLE_JP: // google.co.jp
$base_query .= "&start=";
break;
case YAHOO_COM: // yahoo.com (worldwide)
case YAHOO_JP: // yahoo.co.jp
$base_query .= "&b=";
break;
case BING_COM: // bing.com (worldwide)
case BING_JP: // bing.co.jp
$base_query .= "&first=";
break;
default:
return; // do nothing
}
$rank = 1;
$num_found = 0;
// initialize results
if (is_array($target_url)) {
$output = array();
for ($j = 0 ; $j < $num_target ; $j++) {
$output[$j] = -1;
}
}
else {
$output = -1;
}
// page loop (10 items per page)
// Note: this loop stops when all the target URLs are found
for ($i = 0 ; $i < $max_rank / 10 ; $i++) {
// add search start position to the query
if ($provider == GOOGLE_JP || $provider == GOOGLE_COM) {
$query = $base_query . ($i * 10);
}
else if ($provider == YAHOO_JP || $provider == YAHOO_COM
|| $provider == BING_JP || $provider == BING_COM) {
$query = $base_query . ($i * 10 + 1);
}
// execute query and get the returned data from server
// $html = @file_get_contents($query);
$request = drupal_http_request($query);
$html = $request->data;
// DEBUG
// print "HTML: " . $html . "
\n";
$links = array();
// extract URL (strip off other anchor attributes, query string and HTML tags
if ($provider == GOOGLE_JP || $provider == GOOGLE_COM) {
preg_match_all('/ class="r">/', $html, $links);
}
else if ($provider == YAHOO_JP) {
preg_match_all('//', $html, $links);
}
else if ($provider == YAHOO_COM) {
preg_match_all('/ class="yschttl spt" href="([^"\?]+?)["\?].*?>/', $html, $links);
}
else if ($provider == BING_JP || $provider == BING_COM) {
preg_match_all('/