If someone types "button pusher" and you consider that particular combination of words offensive, but not when used individually (e.g. button, or pusher), you can't filter them the way the module is currently.

Sorry for the messy patch. (see attached)

The only lines you need pay attention to are: 125, 126, 174, 175.

CommentFileSizeAuthor
patch_7.diff8.1 KBms2011

Comments

yngens’s picture

i need this function to filter the whole expressions, not separate words. but applying this patch gives lots of errors:

patch <*.diff
(Stripping trailing CRs from patch.)
patching file README.txt
Hunk #1 FAILED at 14.
1 out of 1 hunk FAILED -- saving rejects to file README.txt.rej
(Stripping trailing CRs from patch.)
patching file wordfilter.install
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file wordfilter.install.rej
(Stripping trailing CRs from patch.)
patching file wordfilter.module
Hunk #1 succeeded at 17 with fuzz 1 (offset 10 lines).
Hunk #2 FAILED at 86.
Hunk #3 FAILED at 96.
Hunk #4 FAILED at 133.
Hunk #5 FAILED at 169.
Hunk #6 FAILED at 196.
Hunk #7 FAILED at 223.
Hunk #8 FAILED at 265.
7 out of 8 hunks FAILED -- saving rejects to file wordfilter.module.rej

yngens’s picture

Version: 5.x-1.x-dev » master
Assigned: jaydub » Unassigned
Status: Closed (fixed) » Needs review

ok, after trying many different ways i managed to achieve the needed effect. i don't know how to make patches, so posting the whole code for the module:


<?php
// $Id: wordfilter.module,v 1.7 2007/06/19 12:13:44 add1sun Exp $

/**
 * @file
 * Replaces words inside posts with filtered versions.
 */

/**
 * Implementation of hook_help().
 *
 * @param $section
 *   string file path
 *
 * @return
 *   string
 */
function wordfilter_help($section = 'admin/help#wordfilter') {
  switch ($section) {
    case 'admin/modules#description':
      return t('Replaces words inside posts with filtered versions.');
    case 'admin/filters/wordfilter':
      return t('Here you can edit the words that are filtered by your site.');
  }
}

/**
 * Implementation of hook_perm().
 *
 * @return
 *   array of permissions
 */
function wordfilter_perm() {
  return array('administer words filtered');
}

/**
 * Implementation of hook_menu().
 *
 * @param $may_cache
 *   boolean indicating whether cacheable menu items should be returned
 *
 * @return
 *   array of menu information
 */
function wordfilter_menu($may_cache) {
  $items = array();

  if ($may_cache) {
    $access = user_access('administer words filtered');

    $items[] = array(
      'path' => 'admin/settings/wordfilter',
      'title' => t('Word filter'),
      'description' => t('Replaces words inside posts with filtered versions.'),
      'callback' => 'wordfilter_admin_list',
      'access' => $access);

    $items[] = array(
      'path' => 'admin/settings/wordfilter/list',
      'title' => t('List'),
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'weight' => -10);

    $items[] = array(
      'path' => 'admin/settings/wordfilter/add',
      'title' => t('Add'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array('wordfilter_admin_form'),
      'access' => $access,
      'type' => MENU_LOCAL_TASK);

    $items[] = array(
      'path' => 'admin/settings/wordfilter/edit',
      'title' => t('Edit'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array('wordfilter_admin_form'),
      'access' => $access,
      'type' => MENU_CALLBACK);
  }
  return $items;
}

/**
 * Implementation of hook_settings().
 *
 * @return
 *   array of form elements
 */
function wordfilter_settings_form() {
  $form["wordfilter_default_replacement"] = array(
    "#type" => "textfield",
    "#title" => t("Default Word Replacement"),
    "#default_value" => variable_get("wordfilter_default_replacement", "[filtered word]"),
    "#required" => true
  );

  $form["wordfilter_node_title"] = array(
    "#type" => "checkbox",
    "#title" => t("Enable Word Filtering On Node Titles"),
    "#default_value" => variable_get("wordfilter_node_title", true),
    "#return_value" => true
  );

  return system_settings_form($form);
}

/**
 * Implementation of hook_nodeapi().
 *
 * @param &$node
 *   editable node object
 * 
 * @param $op
 *   string of what process we're at
 * 
 * @param $teaser
 *   boolean if showing teaser
 * 
 * @param $page
 *   boolean if on full view page of a node
 *
 */
function wordfilter_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  if ($node && ($op == 'submit' || $op == 'update') && variable_get("wordfilter_node_title", true)) {
    $node->title = wordfilter_filter_process($node->title);
  }
}

/**
 * Implementation of hook_block().
 *
 * @param $op
 *   string for view type
 *
 * @param $delta
 *   int
 *
 * @return
 *   array of block information
 */
function wordfilter_block($op = 'list', $delta = 0) {
  if ($op == 'list') {
    $blocks[0]['info'] = t('Filtered word lists on submission pages');
    return $blocks;
  }
  else if ($op == 'view') {
    switch ($delta) {
      case 0:
        $block['subject'] = t('Filtered words');
        $block['content'] = $GLOBALS['display_wordfilter_block'] ? wordfilter_table() : '';
        return $block;
    }
  }
}

/**
 * @return string
 */
function wordfilter_filter_tips($delta, $format, $long = false) {
  if ($long) {
    return t('If you include a word in your post that\'s filtered (usually foul language), it will be replaced by the filtered version of the word.') . '<br />';
  }
  else {
    $GLOBALS['display_wordfilter_block'] = true;
    return t('Filtered words will be replaced with the filtered version of the word.');
  }
}

function wordfilter_table() {
  $content .= '<div align="center">';
  $content .= '<table border="0" cellspacing="1" cellpadding="0">';
  $list = _wordfilter_list();
  foreach ($list as $filtered_word) {
    $alt = implode(',', explode(',', $filtered_word->words));
    $content .= '<tr><td align="left">'. $filtered_word->replacement .'</td><td align="right">,'. $alt .'</td></tr>';
  }
  $content .= '</table></div>';
  return $content;
}

function wordfilter_filter($op, $delta = 0, $format = -1, $text = '') {
  switch ($op) {
    case 'list':
      return array(0 => t('Word filter'));
    case 'description':
      return wordfilter_help('admin/modules#description');
    case 'settings':
      $form = array('word_filter' => array(
        '#type' => 'fieldset',
        '#title' => t('Word filter'),
        '#description' => t('You can define a global list of words to be filtered on the <a href="%url">wordfilter settings page</a>.', array('%url' => url('admin/settings/wordfilter'))))
      );
      return drupal_get_form('wordfilter', $form);
    case 'process':
      return wordfilter_filter_process($text);
    default:
      return $text;
  }
}

function wordfilter_filter_process($text) {
  $text = ' '. $text .' ';
  $list = _wordfilter_list();
  foreach ($list as $word) {
    $words = explode(', ', $word->words);
    foreach ($words as $a) {
      // Prevent mysterious empty value from blowing away the node title.
      if (!empty($a)) {
        $replacement = ($word->replacement) ? $word->replacement : variable_get("wordfilter_default_replacement", "[filtered word]");
      
        if ($word->standalone) {
          $text = eregi_replace("([ ,\.\?!:\(\)\r\n\<\>])". preg_quote($a) ."([ ,\.\?!:\(\)\r\n\<\>])", "\\1". ($replacement) ."\\2", $text);
        } else {
          $text = eregi_replace(preg_quote($a), ($replacement), $text);
        }
      }
    }
  }
  $text = substr($text, 1, -1);

  return $text;
}

function _wordfilter_list($refresh = 0) {
  static $list = NULL;
  if (is_null($list) || $refresh) {
    $result = db_query('SELECT * FROM {wordfilter}');
    $list = array();
    while ($a = db_fetch_object($result)) {
      $list[] = $a;
    }
  }
  return $list;
}

function wordfilter_admin_list() {
  $header = array(t('Words'), t('Replacement'), t('Operations'));
  $rows = array();
  $list = _wordfilter_list(1);
  foreach ($list as $word) {
    $rows[] = array(
      check_plain($word->words),
      ($word->replacement) ? $word->replacement : variable_get("wordfilter_default_replacement", "[filtered word]"),
      l(t('Edit word'), 'admin/settings/wordfilter/edit/'. $word->id)
    );
  }
  $output .= theme('table', $header, $rows);
  
  $output .= drupal_get_form('wordfilter_settings_form');

  return $output;
}

/**
 * @return array
 */
function wordfilter_admin_form($word_id = NULL) {
  if (isset($word_id)) {
    $result = db_query('SELECT * FROM {wordfilter} WHERE id = %d', $word_id);
    $word = db_fetch_array($result);
  }

  $form = array();
  if ($word['id']) {
    $form['id'] = array(
      '#type' => 'hidden',
      '#value' => $word['id']
    );
  }

  $form['words'] = array(
    '#type' => 'textarea',
    '#title' => t('Words'),
    '#default_value' => $word['words'],
    '#description' => t('Enter a list of words you want to filter, separated by spaces.'),
    '#required' => true
  );
  $form['replacement'] = array(
    '#type' => 'textfield',
    '#title' => t('Replacement'),
    '#default_value' => ($word['replacement']) ? $word['replacement'] : variable_get("wordfilter_default_replacement", "[filtered word]"),
    '#size' => 50,
    '#maxlength' => 255,
    '#description' => t('Enter the filtered version of the word to replace the original words with.')
  );
  $form['standalone'] = array(
    '#type' => 'checkbox',
    '#title' => t('Stand-alone'),
    '#default_value' => $word['standalone'],
    '#description' => t('When checked, the word will only be filtered when found as a separate word (i.e. prefixed and suffixed by spaces or "whitespace"). A period one character after a word will exclude the words from replacement in stand-alone mode. This is useful for preventing accidental word filtering with short or common words.')
  );
  $form['Save Word Filter'] = array(
    '#type' => 'submit',
    '#value' => t('Save Word Filter')
  );

  if ($word['id']) {
    $form['Delete Word Filter'] = array(
      '#type' => 'submit',
      '#value' => t('Delete Word Filter')
    );
  }

  return $form;
}

function wordfilter_admin_form_validate($form_id, $form_values) {
  if (trim($form_values['words']) == '') {
    form_set_error('words', t('Please enter a word to filter.'));
  }
}

function wordfilter_admin_form_submit($form_id, $form_values) {
  if ($form_values['id']) {
    if ($form_values['op'] == t('Delete Word Filter')) {
      db_query("DELETE FROM {wordfilter} WHERE id = %d", $form_values['id']);
      $message = t('Deleted filter for: %words', array('%words' => $form_values['words']));
    }
    else {
      db_query("UPDATE {wordfilter} SET words='%s', replacement='%s', standalone=%d WHERE id = %d", $form_values['words'], $form_values['replacement'], $form_values['standalone'], $form_values['id']);
      $message = t('Updated filter for: %words', array('%words' => $edit['words']));
    }
  }
  else {
    db_query("INSERT INTO {wordfilter} (words, replacement, standalone) VALUES ('%s', '%s', %d)", $form_values["words"], $form_values["replacement"], $form_values["standalone"]);
    $message = t('Added filter for: %words', array('%words' => $form_values['words']));
  }
  watchdog('regular', $message);
  drupal_set_message($message);
}


jaydub’s picture

Version: master » 5.x-1.x-dev
Assigned: Unassigned » jaydub
jaydub’s picture

Status: Needs review » Fixed

Just checked in a refactoring of wordfilter word list
adminstration.

The main admin page now shows the current word list
as a table with paged results. From here you can edit
or remove a single original word/replacement word pair.

The add page has been changed to allow easier creation
of multiple original word/replacement word pairs. Quick
explanation:

"Enter a word or phrase you want to filter followed
by '|' and the replacement word or phrase. You can
enter multiple word and replacement word pairs by
hitting return and adding more word pairs. Any word
or phrases that do not have a replacement word or
phrase will use the default replacement word below."

Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.

Status: Needs review » Closed (fixed)