View source
<?php
require_once 'word_link.actions.inc';
function word_link_permission() {
return array(
'view word link' => array(
'title' => t('View Word Link'),
),
'create word link' => array(
'title' => t('Create Word Link'),
),
'edit word link' => array(
'title' => t('Edit Word Link'),
),
'delete word link' => array(
'title' => t('Delete Word Link'),
),
);
}
function word_link_entity_info() {
return array(
'word_link' => array(
'label' => t('Word Link'),
'base table' => 'word_link',
'fieldable' => FALSE,
'entity keys' => array(
'id' => 'id',
'label' => 'text',
),
'bundles' => array(),
'deletion callback' => 'word_link_delete',
),
);
}
function word_link_action_info() {
$actions = array();
$actions['word_link_modify_action'] = array(
'type' => 'word_link',
'label' => t('Modify words'),
'behavior' => array(
'changes_property',
),
'configurable' => FALSE,
'vbo_configurable' => TRUE,
'triggers' => array(
'any',
),
);
$actions['word_link_delete_action'] = array(
'type' => 'word_link',
'label' => t('Delete words'),
'behavior' => array(
'changes_property',
),
'configurable' => FALSE,
'vbo_configurable' => FALSE,
);
$actions['word_link_disable_invalid_word_action'] = array(
'type' => 'word_link',
'label' => t('Disable words with invalid URLs'),
'behavior' => array(
'changes_property',
),
'configurable' => FALSE,
'vbo_configurable' => FALSE,
);
return $actions;
}
function word_link_menu() {
$items = array();
$items['admin/config/content/word-link/configuration'] = array(
'title' => 'Configuration',
'description' => 'Set the preferences for Word Link module.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'word_link_admin_settings',
),
'access arguments' => array(
'administer site configuration',
),
'type' => MENU_LOCAL_TASK,
'file' => 'word_link.admin.inc',
'weight' => 2,
);
$items['admin/config/content/word-link/add'] = array(
'title' => 'Add new word',
'description' => 'Add word',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'word_link_add_form',
),
'access arguments' => array(
'create word link',
),
'type' => MENU_LOCAL_TASK,
'file' => 'word_link.admin.inc',
);
$items['admin/config/content/word-link/edit/%word_link'] = array(
'title' => 'Edit word',
'description' => 'Word edit',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'word_link_add_form',
5,
),
'access arguments' => array(
'edit word link',
),
'type' => MENU_CALLBACK,
'file' => 'word_link.admin.inc',
);
$items['admin/config/content/word-link/delete/%word_link'] = array(
'title' => 'Delete',
'description' => 'Word delete',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'word_link_delete_form',
5,
),
'access arguments' => array(
'delete word link',
),
'type' => MENU_CALLBACK,
'file' => 'word_link.admin.inc',
);
$items['word-link/ajax/words'] = array(
'page callback' => 'word_link_words_autocomplete_callback',
'type' => MENU_CALLBACK,
'access arguments' => array(
'create word link',
),
);
$items['word-link/ajax/urls'] = array(
'page callback' => 'word_link_urls_autocomplete_callback',
'type' => MENU_CALLBACK,
'access arguments' => array(
'create word link',
),
);
return $items;
}
function word_link_menu_local_tasks_alter(&$data, $router_item, $root_path) {
if ($root_path == 'admin/config/content/word-link') {
$item = menu_get_item('admin/config/content/word-link/add');
if ($item['access']) {
$data['actions']['output'][] = array(
'#theme' => 'menu_local_action',
'#link' => $item,
);
}
}
}
function word_link_views_api() {
return array(
'api' => 3,
);
}
function word_link_init() {
if (variable_get('word_link_add_css', 1)) {
drupal_add_css(drupal_get_path('module', 'word_link') . '/css/word_link.css');
}
}
function word_link_theme() {
return array(
'word_link' => array(
'variables' => array(
'text' => NULL,
'tag' => NULL,
'attributes' => array(),
),
'file' => 'theme/word_link.theme.inc',
),
);
}
function word_link_filter_info() {
$filters['word_link'] = array(
'title' => t('Word link'),
'description' => t('Automatically converts words into links.'),
'process callback' => '_word_link_process',
'settings callback' => '_word_link_settings',
'default settings' => array(
'word_link_highlight' => FALSE,
'word_link_wrap_tag' => NULL,
'word_link_boundary' => FALSE,
'word_link_tags_except' => '<h1> <h2> <h3> <h4> <h5> <h6> <code>',
'word_link_content_types' => array(),
),
'weight' => 15,
);
return $filters;
}
function _word_link_settings($form, &$form_state, $filter, $format, $defaults) {
$filter->settings += $defaults;
$settings['word_link_highlight'] = array(
'#type' => 'checkbox',
'#title' => t('Highlight words.'),
'#description' => t('Highlight found words instead of replace it to links.'),
'#default_value' => $filter->settings['word_link_highlight'],
);
$settings['word_link_wrap_tag'] = array(
'#type' => 'textfield',
'#size' => 9,
'#title' => t('Wrap HTML tag'),
'#description' => t('Enter HTML tag which will be used to wrap word link. Be careful and enter only tag name (e.g. h1).'),
'#default_value' => $filter->settings['word_link_wrap_tag'],
);
$settings['word_link_boundary'] = array(
'#type' => 'checkbox',
'#title' => t('Word boundary'),
'#description' => t('If enabled all words will be converted, even those that are not wrapped by spaces.'),
'#default_value' => $filter->settings['word_link_boundary'],
);
$settings['word_link_tags_except'] = array(
'#type' => 'textfield',
'#title' => t('Disallowed HTML tags'),
'#description' => t('A list of HTML tags that will be ignored. Never enter here tags that are not text. E.g. @tags.', array(
'@tags' => '<img>',
)),
'#default_value' => $filter->settings['word_link_tags_except'],
);
$settings['word_link_content_types'] = array(
'#type' => 'checkboxes',
'#title' => t('Content types'),
'#description' => t('Choose content types in which words will be converted.'),
'#options' => node_type_get_names(),
'#default_value' => $filter->settings['word_link_content_types'],
);
return $settings;
}
function _word_link_process($text, $filter) {
$text = word_link_convert_text($text, $filter->settings);
return $text;
}
function word_link_convert_text($text, $settings) {
global $base_url;
$current_path = current_path();
$args = arg();
if (isset($args[0]) && $args[0] == 'node' && isset($args[1])) {
$type = word_link_get_node_type($args[1]);
if (empty($settings['word_link_content_types'][$type])) {
return $text;
}
}
$words = word_link_load_all();
if (empty($words)) {
return $text;
}
$tag = 'a';
if (!empty($settings['word_link_tags_except'])) {
$disallowed =& drupal_static('word_link_disallowed_tags');
if (!isset($disallowed)) {
$disallowed_tags = preg_split('/\\s+|<|>/', $settings['word_link_tags_except'], -1, PREG_SPLIT_NO_EMPTY);
$disallowed = array();
foreach ($disallowed_tags as $ancestor) {
$disallowed[] = 'and not(ancestor::' . $ancestor . ')';
}
$disallowed = implode(' ', $disallowed);
}
}
else {
$disallowed = '';
}
$patterns =& drupal_static('word_link_patterns');
if (!isset($patterns)) {
$path = drupal_strtolower(drupal_get_path_alias());
$pattern = array();
foreach ($words as $word) {
$url = str_replace($base_url . '/', '', $word->url);
$url = drupal_get_path_alias($url);
$match = FALSE;
if (!empty($word->except_list)) {
$match = drupal_match_path($path, $word->except_list);
if ($path != $current_path) {
$match = $match || drupal_match_path($current_path, $word->except_list);
}
}
$visibility = empty($word->except_list) || !isset($word->visibility) ? FALSE : $word->visibility;
if ($url != $path && !$match && !$visibility || $url != $path && $visibility && $match) {
$text_lower = preg_replace('/\\s+/', ' ', trim($word->text_lower));
$pattern[] = preg_replace('/ /', '\\s+', preg_quote($text_lower, '/'));
}
}
$patterns = array();
foreach (array_chunk($pattern, 1000, TRUE) as $pattern_chunk) {
if ($settings['word_link_boundary']) {
$patterns[] = '/(?<=)(' . implode('|', $pattern_chunk) . ')/ui';
}
else {
$patterns[] = '/((\\b)|(?<=))(' . implode('|', $pattern_chunk) . ')\\b/ui';
}
}
}
foreach ($patterns as $pattern) {
word_link_convert_text_recursively($text, $pattern, $words, $disallowed, $settings, $tag);
}
return $text;
}
function word_link_convert_text_recursively(&$text, $pattern, $words, $disallowed, $settings, $tag) {
$dom = filter_dom_load($text);
$xpath = new DOMXPath($dom);
$text_nodes = $xpath
->query('//text()[not(ancestor::a) ' . $disallowed . ']');
foreach ($text_nodes as $original_node) {
$text = $original_node->nodeValue;
$match_count = preg_match_all($pattern, $text, $matches, PREG_OFFSET_CAPTURE);
if ($match_count > 0) {
$offset = 0;
$parent = $original_node->parentNode;
$next = $original_node->nextSibling;
$parent
->removeChild($original_node);
foreach ($matches[0] as $delta => $match) {
$match_text = $match[0];
$match_pos = $match[1];
$text_lower = drupal_strtolower($match_text);
$word = $words[$text_lower];
$word_cache_id = $word->id . '_' . md5($match_text);
if ($word->case_sensitive && $word->text == $match_text || !$word->case_sensitive) {
$prefix = substr($text, $offset, $match_pos - $offset);
$parent
->insertBefore($dom
->createTextNode($prefix), $next);
$link = $dom
->createDocumentFragment();
$word_link_rendered =& drupal_static('word_link_rendered');
if (!isset($word_link_rendered[$word_cache_id])) {
if ($cache = cache_get('word_link_rendered_' . $word_cache_id)) {
$word_link_rendered[$word_cache_id] = $cache->data;
}
else {
$target = url_is_external($word->url) ? '_blank' : '';
$url_external = url_is_external($word->url);
$url_options = array();
$url_path = NULL;
if ($url_external) {
$url_path = $word->url;
}
else {
$url_parts = parse_url($word->url);
$url_query = array();
if (isset($url_parts['query'])) {
parse_str($url_parts['query'], $url_query);
}
$url_options = array(
'query' => $url_query,
'fragment' => isset($url_parts['fragment']) ? $url_parts['fragment'] : '',
);
if (empty($url_parts['path'])) {
$url_options['external'] = TRUE;
$url_path = NULL;
}
else {
$url_path = $url_parts['path'];
}
}
$attributes = array(
'href' => url($url_path, $url_options),
'title' => $word->url_title,
'class' => $word->class,
'target' => $target,
'rel' => $word->rel,
);
if ($settings['word_link_highlight']) {
$tag = 'span';
unset($attributes['href'], $attributes['target'], $attributes['rel']);
}
$word_link_rendered[$word_cache_id] = theme('word_link', array(
'text' => $match_text,
'tag' => $tag,
'attributes' => array_filter($attributes),
));
if (!empty($settings['word_link_wrap_tag'])) {
$word_link_rendered[$word_cache_id] = theme('html_tag', array(
'element' => array(
'#tag' => $settings['word_link_wrap_tag'],
'#value' => $word_link_rendered[$word_cache_id],
),
));
}
cache_set('word_link_rendered_' . $word_cache_id, $word_link_rendered[$word_cache_id], 'cache');
}
}
$link
->appendXML($word_link_rendered[$word_cache_id]);
$parent
->insertBefore($link, $next);
$offset = $match_pos + strlen($match_text);
}
else {
$prefix = substr($text, $offset, $match_pos - $offset);
$parent
->insertBefore($dom
->createTextNode($prefix), $next);
$parent
->insertBefore($dom
->createTextNode($match_text), $next);
$offset = $match_pos + strlen($match_text);
}
if ($delta == $match_count - 1) {
$suffix = substr($text, $offset);
$parent
->insertBefore($dom
->createTextNode($suffix), $next);
}
}
}
}
$text = filter_dom_serialize($dom);
}
function word_link_get_node_type($nid) {
$type =& drupal_static(__FUNCTION__ . '_' . $nid);
if (!isset($type)) {
$query = db_select('node', 'n')
->fields('n', array(
'type',
))
->condition('n.nid', $nid);
$type = $query
->execute()
->fetchField();
}
return $type;
}
function word_link_load_all($enabled = TRUE) {
$words =& drupal_static(__FUNCTION__);
if (!isset($words)) {
if ($cache = cache_get('word_link_words')) {
$words = $cache->data;
}
else {
$query = db_select('word_link', 'wl');
$query
->addExpression('LOWER(wl.text)', 'text_lower');
$query
->fields('wl');
if ($enabled) {
$query
->condition('status', 1);
}
$query
->orderBy('wl.weight');
$results = $query
->execute();
$words = array();
foreach ($results as $word) {
if (isset($words[$word->text_lower])) {
if ($words[$word->text_lower]->weight >= $word->weight) {
$words[$word->text_lower] = $word;
}
}
else {
$words[$word->text_lower] = $word;
}
}
cache_set('word_link_words', $words, 'cache');
}
}
return $words;
}
function word_link_load($id) {
$word =& drupal_static('word_link_load_' . $id);
if (!isset($word)) {
$query = db_select('word_link', 'wl')
->fields('wl')
->condition('id', $id, '=');
$word = $query
->execute()
->fetchAssoc();
$word = $word ? (object) $word : $word;
}
return $word;
}
function word_link_load_by_url($url) {
$url_alias = drupal_get_path_alias($url);
$query = db_select('word_link', 'wl')
->fields('wl')
->condition(db_or()
->condition('url', $url, '=')
->condition('url', $url_alias, '='));
$results = $query
->execute();
$words = array();
foreach ($results as $word) {
$words[$word->id] = $word;
}
return $words;
}
function word_link_exists($text, $id = 0) {
$query = db_select('word_link', 'wl')
->fields('wl', array(
'text',
'case_sensitive',
'id',
))
->condition('id', $id, '!=')
->condition('text', $text, '=');
$word = $query
->execute()
->fetchAssoc();
return $word ? (object) $word : $word;
}
function word_link_save(&$word) {
$word = (object) $word;
$insert = isset($word->id) ? 'id' : array();
$result = drupal_write_record('word_link', $word, $insert);
return $result ? $word : $result;
}
function word_link_delete($id) {
word_link_delete_multiple(array(
$id,
));
}
function word_link_delete_multiple($ids) {
db_delete('word_link')
->condition('id', $ids, 'IN')
->execute();
foreach ($ids as $id) {
word_link_clear_word_cache($id);
}
}
function word_link_path_delete($path) {
if ($path && isset($path['alias'])) {
$words = word_link_load_by_url($path['alias']);
$msg = t('Path alias @url', array(
'@url' => $path['alias'],
));
word_link_disable_words($words, $msg);
}
}
function word_link_node_delete($node) {
$words = word_link_load_by_url('node/' . $node->nid);
$msg = t('Node @name', array(
'@name' => $node->title,
));
word_link_disable_words($words, $msg);
}
function word_link_user_delete($account) {
$words = word_link_load_by_url('user/' . $account->uid);
$msg = t('User @name', array(
'@name' => $account->name,
));
word_link_disable_words($words, $msg);
}
function word_link_taxonomy_term_delete($term) {
$words = word_link_load_by_url('taxonomy/term/' . $term->tid);
$msg = t('Taxonomy term @name', array(
'@name' => $term->name,
));
word_link_disable_words($words, $msg);
}
function word_link_disable_words($words, $type_msg) {
if (empty($words)) {
return;
}
$words_list = array();
foreach ($words as $word) {
if ($word->status) {
$word->status = FALSE;
word_link_save($word);
$words_list[] = l($word->text, 'admin/config/content/word-link/edit/' . $word->id, array(
'attributes' => array(
'target' => '_blank',
),
));
}
}
if ($words_list) {
$words_list = theme('item_list', array(
'items' => $words_list,
));
$message = t('@type has been deleted and these words were disabled automatically: !list', array(
'@type' => $type_msg,
'!list' => $words_list,
));
drupal_set_message($message, 'warning');
}
word_link_clear_word_cache();
}
function word_link_words_autocomplete_callback($string = "") {
$matches = array();
if ($string) {
$result = db_select('word_link', 'wl')
->fields('wl', array(
'id',
'text',
))
->condition('text', db_like($string) . '%', 'LIKE')
->range(0, 10)
->execute();
foreach ($result as $word) {
$matches[$word->text . " ({$word->id})"] = check_plain($word->text) . " ({$word->id})";
}
}
drupal_json_output($matches);
}
function word_link_urls_autocomplete_callback($string = "") {
$matches = array();
if ($string) {
$node_query = db_select('node', 'n');
$node_query
->addField('n', 'nid', 'id');
$node_query
->addField('n', 'title', 'string');
$node_query
->condition('status', 1, '=');
$node_query
->condition('n.title', db_like($string) . '%', 'LIKE');
$node_query
->range(0, 10);
$nodes = $node_query
->execute()
->fetchAllAssoc('id');
$user_query = db_select('users', 'u');
$user_query
->addField('u', 'uid', 'id');
$user_query
->addField('u', 'name', 'string');
$user_query
->condition('status', 1, '=');
$user_query
->condition('u.name', db_like($string) . '%', 'LIKE');
$user_query
->range(0, 10);
$users = $user_query
->execute()
->fetchAllAssoc('id');
$results = array(
'node' => $nodes,
'user' => $users,
);
if (module_exists('taxonomy')) {
$term_query = db_select('taxonomy_term_data', 't');
$term_query
->addField('t', 'tid', 'id');
$term_query
->addField('t', 'name', 'string');
$term_query
->condition('t.name', db_like($string) . '%', 'LIKE');
$term_query
->range(0, 10);
$terms = $term_query
->execute()
->fetchAllAssoc('id');
$results['taxonomy/term'] = $terms;
}
foreach ($results as $path => $items) {
foreach ($items as $item) {
$matches[$path . '/' . $item->id] = check_plain($item->string) . " ({$item->id})";
}
}
}
drupal_json_output($matches);
}
function word_link_valid_path($path, $dynamic_allowed = FALSE) {
global $menu_admin;
$menu_admin = TRUE;
if ($path == '<front>' || url_is_external($path)) {
$item = array(
'access' => TRUE,
);
}
elseif ($dynamic_allowed && preg_match('/\\/\\%/', $path)) {
if ($item = db_query("SELECT * FROM {menu_router} where path = :path", array(
':path' => $path,
))
->fetchAssoc()) {
$item['link_path'] = $item['path'];
$item['link_title'] = $item['title'];
$item['external'] = FALSE;
$item['options'] = '';
_menu_link_translate($item);
}
}
elseif (strpos($path, '#') === 0) {
$item = array(
'access' => TRUE,
);
}
else {
$item = menu_get_item($path);
}
$menu_admin = FALSE;
return $item && $item['access'];
}
function word_link_clear_filter_cache() {
cache_clear_all('*', 'cache_filter', TRUE);
field_cache_clear();
}
function word_link_clear_word_cache($id = NULL) {
cache_clear_all('word_link_words', 'cache');
if (!empty($id)) {
cache_clear_all('word_link_rendered_' . $id, 'cache', TRUE);
}
}