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/config/content/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_permission() {
return array(
'use uniqueness widget' => array(
'title' => t('Use uniqueness widget'),
'description' => t('Display the uniqueness widget during content authoring.'),
),
'administer uniqueness' => array(
'title' => t('Administer uniqueness settings'),
'description' => t('Configure the uniqueness module.'),
),
);
}
function uniqueness_help($path, $arg) {
$output = '<p>' . t('The Uniqueness module helps you avoid duplicate content on your site by informing users of similar or related content as they create <em>new</em> or edit <em>existing</em> content.');
switch ($path) {
case 'admin/config/content/uniqueness':
$output .= ' ' . l(t('Learn more'), 'admin/help/uniqueness');
$output .= '</p>';
return $output;
case 'admin/help#uniqueness':
$output .= '</p>';
$output .= '<p>' . t('A block and/or in-line user interface element is added to the content adding and/or editing form.') . ' ' . t('As the user types, Uniqueness searches on the title or vocabulary fields and displays a list of similar content.') . ' ' . t('To configure overall options such as search and appearance, visit the <a href="@uniqueness-settings-page">uniqueness settings</a> page. To use the in-line user interface element, enable it on each desired <a href="@content-types-page">content type</a> configuration page.', array(
'@content-types-page' => url('admin/structure/types'),
'@uniqueness-settings-page' => url('admin/config/content/uniqueness'),
)) . '</p>';
$output .= '<h3>' . t('Search modes') . '</h3>';
$output .= '<p>' . t('The module can find related content using one of three possible methods:') . '</p>';
$output .= '<dl>';
$output .= '<dt>' . t('Simple node title search (default)') . '</dt>' . '<dd>' . t('Matches the title of a new node by comparing the new title with the title of existing nodes.') . '</dd>';
$output .= '<dt>' . t('Drupal search') . '</dt>' . '<dd>' . t('Searches for content using the standard search module. Requires the core search module to be enabled.') . '</dd>';
$output .= '<dt>' . t('Apache Solr search') . '</dt>' . '<dd>' . t('Searches using the <a href="@apachesolr-project">Apache Solr</a> module. Apache Solr must be to be installed, enabled and configured.', array(
'@apachesolr-project' => url('http://drupal.org/project/apachesolr'),
)) . '</dd>';
$output .= '</dl>';
return $output;
}
}
function uniqueness_field_extra_fields() {
$extras = array();
if (in_array(UNIQUENESS_WIDGET_INLINE, variable_get('uniqueness_widgets', array(
UNIQUENESS_WIDGET_INLINE,
)))) {
foreach (array_keys(node_type_get_types()) as $type) {
$v = variable_get('uniqueness_type_' . $type, array());
if (!empty($v)) {
$extras['node'][$type] = array(
'form' => array(
'uniqueness' => array(
'label' => filter_xss_admin(variable_get('uniqueness_default_title', t('Related content'))),
'description' => t('Uniqueness inline widget.'),
'weight' => 0,
),
),
);
}
}
}
return $extras;
}
function uniqueness_form_node_type_form_alter(&$form, $form_state, $form_id) {
$form['uniqueness'] = array(
'#type' => 'fieldset',
'#title' => t('Uniqueness settings'),
'#group' => 'additional_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 new content of this content type'),
UNIQUENESS_EDIT_NODE => t('When editing an exist content 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()),
);
}
function uniqueness_form_alter(&$form, $form_state, $form_id) {
if (!empty($form['#node_edit_form'])) {
$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()))) {
$form['uniqueness']['#attached']['js'] = array(
drupal_get_path('module', 'uniqueness') . '/uniqueness.js',
array(
'data' => array(
'uniqueness' => _uniqueness_get_js_settings($type, $form['nid']['#value']),
),
'type' => 'setting',
),
);
$values = array();
if (!empty($form['nid']['#value'])) {
$values['nid'] = $form['nid']['#value'];
}
if (!empty($form['title'])) {
$values['title'] = strip_tags($form['title']['#default_value']);
}
if (!empty($values['taxonomy']['tags'][1])) {
$values['tags'] = strip_tags($form['taxonomy']['tags'][1]['#default_value']);
}
_uniqueness_store($values);
if (uniqueness_widget_enabled(UNIQUENESS_WIDGET_INLINE)) {
$count = 0;
$content = uniqueness_widget_content($count);
$form['uniqueness'] += array(
'#type' => 'fieldset',
'#title' => filter_xss_admin(variable_get('uniqueness_default_title', t('Related content'))),
'#collapsible' => 1,
'#collapsed' => $count == 0,
'#weight' => $form['title']['#weight'] + 1,
'uniqueness_type' => array(),
);
$form['uniqueness']['uniqueness_type'] += array(
'#type' => 'item',
'#title' => '',
'#markup' => $content,
);
}
}
}
}
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_get_js_settings($type, $nid) {
$minCharacters = variable_get('uniqueness_query_min', 3);
if (variable_get('uniqueness_search_mode', UNIQUENESS_SEARCH_MODE_NODETITLE) == UNIQUENESS_SEARCH_MODE_DRUPAL && $minCharacters < variable_get('minimum_word_size', 3)) {
$minCharacters = variable_get('minimum_word_size', 3);
}
$settings = array(
'URL' => base_path() . 'uniqueness-search/' . $type,
'prependResults' => variable_get('uniqueness_results_prepend', 0) == 1 ? TRUE : FALSE,
'minCharacters' => $minCharacters,
'searchingString' => filter_xss_admin(variable_get('uniqueness_searching_string', t('Searching…'))),
'noResultsString' => filter_xss_admin(variable_get('uniqueness_no_result_string', t('Success! No related content found.'))),
);
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;
}
return $settings;
}
function _uniqueness_store($values = array()) {
static $uniqueness_store = array();
if (!empty($values)) {
$uniqueness_store = $values;
}
return $uniqueness_store;
}
function uniqueness_block_info() {
$blocks['uniqueness'] = array(
'info' => t('Uniqueness search'),
'cache' => DRUPAL_NO_CACHE,
);
return $blocks;
}
function uniqueness_block_view($delta) {
if (uniqueness_widget_enabled(UNIQUENESS_WIDGET_BLOCK)) {
$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($count);
return $block;
}
}
}
function uniqueness_widget_content(&$count) {
$results = array();
$items = array();
$description = filter_xss_admin(variable_get('uniqueness_default_description', t("Help us avoid duplicate content! 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);
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);
}
}
}
$count = count($items);
return theme('uniqueness_widget', array(
'description' => $description,
'results' => $results,
));
}
function uniqueness_dynamic_callback() {
$values = array();
foreach (array(
'tags',
'title',
'nid',
'type',
) as $key) {
if (isset($_GET[$key])) {
$values[$key] = strip_tags($_GET[$key]);
}
}
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_output($items);
}
else {
drupal_json_output('false');
}
}
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);
}
}
function _uniqueness_content_nodetitle($values) {
if (empty($values['title'])) {
return array();
}
$q = db_select('node', 'n')
->fields('n', array(
'nid',
'title',
'status',
))
->condition('n.title', '%' . db_like($values['title']) . '%', 'LIKE');
if (isset($values['type'])) {
$q
->condition('n.type', $values['type']);
}
if (isset($values['nid']) && is_numeric($values['nid'])) {
$q
->condition('n.nid', $values['nid'], '<>');
}
if (!user_access('bypass node access')) {
if (user_access('view own unpublished content')) {
$q
->condition(db_or()
->condition('n.status', NODE_PUBLISHED)
->condition('n.uid', $GLOBALS['user']->uid));
}
else {
$q
->condition('n.status', NODE_PUBLISHED);
}
}
$q
->range(0, variable_get('uniqueness_results_max', 10) + 1);
$q
->addTag('node_access');
return $q
->execute()
->fetchAllAssoc('nid', PDO::FETCH_ASSOC);
}
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 ', explode(' ', $values['title']));
$search_results = node_search_execute($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 (isset($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(
'variables' => array(
'description' => NULL,
'results' => NULL,
),
),
);
}
function theme_uniqueness_widget($variables) {
$description = $variables['description'];
$results = $variables['results'];
$output = '';
if (!empty($description)) {
$output .= '<p class="uniqueness-description">' . $description . '</p>';
}
$output .= '<div class="uniqueness-dyn">';
$output .= '<span class="uniqueness-search-notifier"></span>';
if (empty($results)) {
$output .= '<div class="item-list"><ul></ul></div>';
}
else {
$output .= theme('item_list', array(
'items' => $results,
));
}
$output .= '</div>';
return $output;
}