View source
<?php
define('UNIQUENESS_WIDGET_INLINE', 0x1);
define('UNIQUENESS_WIDGET_BLOCK', 0x2);
define('UNIQUENESS_SEARCH_MODE_NODETITLE', 0x1);
define('UNIQUENESS_SEARCH_MODE_DRUPAL', 0x2);
define('UNIQUENESS_SEARCH_MODE_SOLR', 0x3);
define('UNIQUENESS_ADD_NODE', 0x1);
define('UNIQUENESS_EDIT_NODE', 0x2);
define('UNIQUENESS_SCOPE_ALL', 0x1);
define('UNIQUENESS_SCOPE_CONTENT_TYPE', 0x2);
function uniqueness_menu() {
$items['uniqueness-search'] = array(
'title' => 'Uniqueness search',
'page callback' => 'uniqueness_dynamic_callback',
'access arguments' => array(
'use uniqueness widget',
),
'type' => MENU_CALLBACK,
);
$items['admin/settings/uniqueness'] = array(
'title' => 'Uniqueness settings',
'description' => 'Configure the behaviour and appearance of the uniqueness widget.',
'file' => 'uniqueness.admin.inc',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'uniqueness_settings',
),
'access arguments' => array(
'administer uniqueness',
),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
function uniqueness_perm() {
return array(
'use uniqueness widget',
'administer uniqueness',
);
}
function uniqueness_help($path, $arg) {
switch ($path) {
case 'admin/settings/uniqueness':
$output = '<p>' . t('Uniqueness module provides a way to avoid duplicate content on your site by informing a user about similar or related content during creation of a new post.') . '</p>';
return $output;
case 'admin/help#uniqueness':
$output = '<p>' . t('Uniqueness module provides a way to avoid duplicate content on your site by informing a user about similar or related content during creation of a new post.') . '</p>';
$output .= '<p>' . t('A UI widget is added to the node adding and/or editing form which performs asynchronous searches on input fields (like the node title or vocabularies) and returns a list of similar content.') . '</p>';
$output .= '<p>' . t('This widget needs to be enabled separately for each content type on the configuration page for each <a href="@content-types-page">content type</a>. Configuration options (appearance, search modes) are available on the <a href="@uniqueness-settings-page">uniqueness settings page</a>.', array(
'@content-types-page' => url('admin/content/types'),
'@uniqueness-settings-page' => url('admin/settings/uniqueness'),
)) . '</p>';
$output .= '<h3>' . t('Search modes') . '</h3>';
$output .= '<p>' . t('The module supports three different search modes:') . '</p>';
$output .= '<ul>';
$output .= '<li>' . t('Simple node title search (default): tries to match the title of a new node by comparing the new title with the title of existing nodes.') . '</li>';
$output .= '<li>' . t('Drupal search: tries to find similar nodes by searching for nodes using the standard search module. Requires the (core) search module to be enabled!') . '</li>';
$output .= '<li>' . t('Apache Solr search: tries to find similar nodes using the <a href="@apachesolr-project">Apache Solr</a> module which is required to be installed, configured and enabled.', array(
'@apachesolr-project' => url('http://drupal.org/project/apachesolr'),
)) . '</li>';
$output .= '</ul>';
return $output;
}
}
function uniqueness_content_extra_fields() {
$widget_types = variable_get('uniqueness_widgets', array(
UNIQUENESS_WIDGET_INLINE,
));
if (!in_array(UNIQUENESS_WIDGET_INLINE, $widget_types)) {
return array();
}
$extras['uniqueness'] = array(
'label' => filter_xss_admin(variable_get('uniqueness_default_title', t('Related content'))),
'description' => t('Uniqueness inline widget.'),
);
return $extras;
}
function uniqueness_form_alter(&$form, $form_state, $form_id) {
if ($form_id == 'node_type_form') {
$form['uniqueness'] = array(
'#type' => 'fieldset',
'#title' => t('Uniqueness settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['uniqueness']['uniqueness_type'] = array(
'#type' => 'checkboxes',
'#title' => t('Provide uniqueness search'),
'#options' => array(
UNIQUENESS_ADD_NODE => t('When adding a new node of this content type'),
UNIQUENESS_EDIT_NODE => t('When editing an existing node of this content type'),
),
'#description' => t('Shows similar content when adding or editing content to help avoid duplication.'),
'#default_value' => variable_get('uniqueness_type_' . $form['#node_type']->type, array()),
);
}
elseif (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] . '_node_form' == $form_id) {
$type = $form['type']['#value'];
$op = empty($form['#node']->nid) ? UNIQUENESS_ADD_NODE : UNIQUENESS_EDIT_NODE;
_uniqueness_widget_store(array(
'type' => $type,
'op' => $op,
));
if (user_access('use uniqueness widget') && in_array($op, variable_get('uniqueness_type_' . $type, array()))) {
_uniqueness_add_search_javascript($type, $form['nid']['#value']);
if (uniqueness_widget_enabled(UNIQUENESS_WIDGET_INLINE)) {
$form['uniqueness'] = array(
'#type' => 'fieldset',
'#title' => filter_xss_admin(variable_get('uniqueness_default_title', t('Related content'))),
'#collapsible' => 1,
'#collapsed' => 0,
'#weight' => $form['title']['#weight'] + 1,
);
$form['uniqueness']['uniqueness_type'] = array(
'#type' => 'item',
'#title' => '',
);
$form['uniqueness']['uniqueness_type']['#value'] = uniqueness_widget_content();
}
$form['#submit'][] = '_uniqueness_node_add_submit';
}
}
}
function uniqueness_module_status_check() {
$types = array_keys(node_get_types('types'));
$active = FALSE;
foreach ($types as $type) {
$v = variable_get('uniqueness_type_' . $type, array());
if (!empty($v)) {
$active = TRUE;
}
}
if (!$active) {
drupal_set_message(t('Uniqueness search has not been enabled for any content types. It can be activated on the respective configuration page for each <a href="@content-types-page">content type</a>.', array(
'@content-types-page' => url('admin/content/types'),
)));
}
}
function uniqueness_widget_enabled($widget) {
$widget_types = variable_get('uniqueness_widgets', array(
UNIQUENESS_WIDGET_INLINE,
));
return in_array($widget, $widget_types);
}
function _uniqueness_widget_store($options = NULL) {
static $saved_options = NULL;
if ($options !== NULL) {
$saved_options = $options;
}
return $saved_options;
}
function _uniqueness_add_search_javascript($type, $nid) {
drupal_add_js(drupal_get_path('module', 'uniqueness') . '/uniqueness.js');
$search_url = base_path() . 'uniqueness-search/' . $type;
$search_mode = variable_get('uniqueness_search_mode', UNIQUENESS_SEARCH_MODE_NODETITLE);
$minCharacters = variable_get('uniqueness_query_min', 3);
if ($search_mode == UNIQUENESS_SEARCH_MODE_DRUPAL && $minCharacters < variable_get('minimum_word_size', 3)) {
$minCharacters = variable_get('minimum_word_size', 3);
}
$settings = array(
'URL' => $search_url,
'preview' => FALSE,
'prependResults' => variable_get('uniqueness_results_prepend', 0) == 1 ? TRUE : FALSE,
'minCharacters' => $minCharacters,
'searchingString' => filter_xss_admin(variable_get('uniqueness_searching_string', t('Searching…'))),
);
if (!empty($form_state['node_preview'])) {
$settings['preview'] = TRUE;
}
if (variable_get('uniqueness_scope', UNIQUENESS_SCOPE_CONTENT_TYPE) == UNIQUENESS_SCOPE_CONTENT_TYPE) {
$settings['type'] = $type;
}
if (is_numeric($nid) && $nid != 0) {
$settings['nid'] = $nid;
}
drupal_add_js(array(
'uniqueness' => $settings,
), 'setting');
}
function _uniqueness_node_add_submit($form, &$form_state) {
if ($form_state['clicked_button']['#id'] == 'edit-preview') {
$values = $form_state['values'];
$store = array();
if (!empty($values['title'])) {
$store['title'] = strip_tags($values['title']);
}
if (!empty($values['taxonomy']['tags'][1])) {
$store['tags'] = strip_tags($values['taxonomy']['tags'][1]);
}
if (!empty($store)) {
_uniqueness_store($store);
}
}
}
function _uniqueness_store($values = array()) {
static $uniqueness_store = array();
if (!empty($values)) {
$uniqueness_store = $values;
}
return $uniqueness_store;
}
function uniqueness_block($op = 'list', $delta = 0, $edit = array()) {
if (!uniqueness_widget_enabled(UNIQUENESS_WIDGET_BLOCK)) {
return;
}
if ($op == 'list') {
$blocks['uniqueness'] = array(
'info' => t('Uniqueness search'),
'cache' => BLOCK_NO_CACHE,
);
return $blocks;
}
elseif ($op == 'view') {
$options = _uniqueness_widget_store();
if ($options !== NULL && user_access('use uniqueness widget') && $delta == 'uniqueness' && in_array($options['op'], variable_get('uniqueness_type_' . $options['type'], array()))) {
$block['subject'] = filter_xss_admin(variable_get('uniqueness_default_title', t('Related content')));
$block['content'] = uniqueness_widget_content();
return $block;
}
}
}
function uniqueness_widget_content() {
$results = array();
$description = filter_xss_admin(variable_get('uniqueness_default_description', t("Help us increase the signal to noise ratio! If we find content that's related or similar to what you're posting it will be listed here.")));
$values = _uniqueness_store();
if (!empty($values)) {
$content = uniqueness_content($values);
$items = array();
foreach ($content as $nid => $item) {
if (!in_array($nid, array_keys($items))) {
$items[$nid] = $item;
$options = array(
'attributes' => array(
'target' => '_blank',
),
);
$results[] = l($item['title'], 'node/' . $item['nid'], $options);
}
}
}
return theme('uniqueness_widget', $description, $results);
}
function uniqueness_dynamic_callback() {
$values = array();
if ($_GET['tags']) {
$values['tags'] = strip_tags($_GET['tags']);
}
if ($_GET['title']) {
$values['title'] = strip_tags($_GET['title']);
}
if ($_GET['nid']) {
$values['nid'] = strip_tags($_GET['nid']);
}
if ($_GET['type']) {
$values['type'] = strip_tags($_GET['type']);
}
if (!empty($values)) {
$related_content = uniqueness_content($values);
}
if (!empty($related_content)) {
$items = array();
$i = 0;
$limit = variable_get('uniqueness_results_max', 10);
foreach ($related_content as $nid => $item) {
if (!in_array($nid, array_keys($items))) {
$items[$nid] = $item;
$items[$nid]['href'] = url('node/' . $nid);
}
if (++$i > $limit) {
$items[$nid]['more'] = TRUE;
break;
}
}
drupal_json($items);
}
else {
drupal_json('false');
}
return;
}
function uniqueness_content($values) {
$search_mode = variable_get('uniqueness_search_mode', UNIQUENESS_SEARCH_MODE_NODETITLE);
switch ($search_mode) {
case UNIQUENESS_SEARCH_MODE_NODETITLE:
return _uniqueness_content_nodetitle($values);
case UNIQUENESS_SEARCH_MODE_DRUPAL:
return _uniqueness_content_drupalsearch($values);
case UNIQUENESS_SEARCH_MODE_SOLR:
return _uniqueness_content_solr($values);
}
return $related_content;
}
function _uniqueness_content_nodetitle($values) {
$related_content = array();
if ($values['title']) {
$where = array(
$values['title'],
);
$sql = "SELECT n.nid, n.title FROM {node} n WHERE LOWER(n.title) LIKE LOWER('%%%s%') AND n.status = 1";
if (array_key_exists('type', $values)) {
$sql .= " AND n.type = '%s'";
$where[] = $values['type'];
}
if (array_key_exists('type', $values) && is_numeric($values['nid'])) {
$sql .= " AND n.nid != %d";
$where[] = $values['nid'];
}
$result = db_query_range(db_rewrite_sql($sql), $where, 0, variable_get('uniqueness_results_max', 10) + 1);
while ($row = db_fetch_array($result)) {
$related_content[$row['nid']] = $row;
}
}
return $related_content;
}
function _uniqueness_content_drupalsearch($values) {
if (!module_exists('search')) {
drupal_set_message(t('Search module not found. Please enable the search module or select a different search mode on the uniqueness configuration page.'), 'warning');
return array();
}
$searchstring = array_key_exists('type', $values) ? ' type:' . $values['type'] . ' ' : '';
$searchstring .= join(' OR ', split(' ', $values['title']));
$search_results = node_search('search', $searchstring);
$limit = variable_get('uniqueness_results_max', 10);
if (count($search_results) > $limit + 1) {
array_slice($search_results, 0, $limit + 1, TRUE);
}
$related_content = array();
$nid = array_key_exists('nid', $values) ? $values['nid'] : 0;
foreach ($search_results as $result) {
$item = array();
$item['html'] = TRUE;
$item['nid'] = $result['node']->nid;
$item['title'] = $result['title'];
if ($nid != $item['nid']) {
$related_content["{$result['node']->nid}"] = $item;
}
}
return $related_content;
}
function _uniqueness_content_solr($values) {
if (!module_exists('apachesolr_search')) {
drupal_set_message(t('Solr search module not found. Please select a different search mode on the uniqueness configuration page.'), 'warning');
return array();
}
$related_content = array();
$filter = array_key_exists('type', $values) ? 'type:' . $values['type'] : '';
$nid = array_key_exists('nid', $values) ? $values['nid'] : 0;
if ($values['title']) {
$title_content = uniqueness_solr($values['title'], $filter, $nid);
if (!empty($title_content)) {
$related_content = $related_content + $title_content;
}
}
if ($values['tags']) {
$tags = explode(',', $values['tags']);
foreach ($tags as $tag) {
$results = uniqueness_solr(trim($tag), $filter, $nid);
if (!empty($results)) {
$related_content = $related_content + $results;
}
}
}
$limit = variable_get('uniqueness_results_max', 10);
if (count($related_content) > $limit + 1) {
array_slice($related_content, 0, $limit + 1, TRUE);
}
return $related_content;
}
function uniqueness_solr($string, $filter, $nid) {
$related_content = array();
try {
$solr_results = apachesolr_search_execute($string, $filter, '', '', 0, 'uniqueness');
foreach ($solr_results as $result) {
$item = array();
$item['html'] = TRUE;
$item['nid'] = $result['node']->nid;
$item['title'] = $result['title'];
if ($item['nid'] != $nid) {
$related_content["{$result['node']->nid}"] = $item;
}
}
} catch (Exception $e) {
watchdog('Apache Solr', nl2br(check_plain($e
->getMessage())), NULL, WATCHDOG_ERROR);
}
return $related_content;
}
function uniqueness_apachesolr_prepare_query(&$query, &$params, $caller) {
if ($caller == 'uniqueness') {
$params['mm'] = 1;
}
}
function uniqueness_theme($existing, $type, $theme, $path) {
return array(
'uniqueness_widget' => array(
'arguments' => array(
'description' => NULL,
'results' => NULL,
),
),
);
}
function theme_uniqueness_widget($description = '', $results = array()) {
$output = '';
if (!empty($description)) {
$output .= "<p>" . $description . "</p>";
}
$output .= '<div class="uniqueness-dyn">';
$output .= '<span class="uniqueness-search-notifier"></span>';
if (!empty($results)) {
$output .= theme('item_list', $results);
}
$output .= '</div>';
return $output;
}