cmf.module in Content Management Filter 5
Same filename and directory in other branches
@brief Content management filter module file
This file contains all the functions used by the module.
@attention Copyright (C) 2008 Nuno Veloso <nunoveloso18 (at) gmail (dot) com> @author Nuno André Veloso Matias (http://www.nunoveloso.org)
File
cmf.moduleView source
<?php
/**
* @file
* @brief Content management filter module file
*
* This file contains all the functions used by the module.
*
* @attention Copyright (C) 2008 Nuno Veloso <nunoveloso18 (at) gmail (dot) com>
* @author Nuno André Veloso Matias (http://www.nunoveloso.org)
*/
/**
* Implementation of hook_help().
*/
function cmf_help($section = '') {
switch ($section) {
case "admin/help#cmf":
$output = '<p>' . t("This module adds an easier way for administrators to filter the content on a Drupal site for administration purposes.") . '</p>';
$output .= '<p>' . t("It's an improvement over the content page in the administration area of Drupal. It can show on the same page nodes and comments and adds new filters like role and author.") . '</p>';
break;
}
return $output;
}
/**
* Implementation of hook_perm().
*/
function cmf_perm() {
return array(
'filter and manage site content',
'view user content list',
);
}
/**
* Implementation of hook_menu().
*/
function cmf_menu($may_cache) {
$items = array();
$manage_access = user_access('filter and manage site content');
$view_access = user_access('view user content list');
$access_profiles = user_access('access user profiles');
// if ($may_cache) {
$items[] = array(
'path' => 'admin/content/filter',
'title' => t('Content Management Filter'),
'description' => t('All-in-one advanced filter and management of your site content.'),
'callback' => 'cmf_admin_content_page',
'access' => $manage_access,
);
if (arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0) {
$items[] = array(
'path' => 'user/' . arg(1) . '/cmf',
'title' => t('CMF'),
'description' => t('User-specific content management filter'),
'callback' => 'cmf_admin_content_page',
'access' => $access_profiles || $view_access,
'type' => MENU_LOCAL_TASK,
);
}
$items[] = array(
'path' => 'cmf/userauto',
'title' => 'User autocomplete',
'callback' => '_cmf_user_autocomplete',
'access' => $manage_access || $view_access || $access_profiles,
'type' => MENU_CALLBACK,
);
// }
return $items;
}
/**
* Called when user goes to example.com/admin/content/filter
*
* @return the HTML generated from the $form data structure
*/
function cmf_admin_content_page() {
if (!isset($_SESSION['cmf_content_kind'])) {
$_SESSION['cmf_content_kind'] = 'node';
}
if (arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0) {
$true = TRUE;
}
$output = drupal_get_form('cmf_filter_form', $true);
// Call the form first, to allow for the form_values array to be populated.
switch ($_SESSION['cmf_content_kind']) {
case 'node':
if ($_POST['operation'] == 'delete' && $_POST['nodes']) {
return drupal_get_form('node_multiple_delete_confirm');
}
else {
$output .= drupal_get_form('cmf_admin_nodes_form');
}
break;
case 'comment':
if ($_POST['operation'] == 'delete' && $_POST['comments']) {
return drupal_get_form('comment_multiple_delete_confirm');
}
else {
$output .= drupal_get_form('cmf_admin_comments_form');
}
break;
case 'both':
$output .= drupal_get_form('cmf_admin_both_form');
}
return $output;
}
/**
* FILTERS
*/
/**
* Defines the form for content administration filters.
*
* @ingroup forms
* @see cmf_filter_form_submit()
*
* @param (optional) TRUE if the filter to be built serves the user profile page.
* @return array with forms properties
*/
function cmf_filter_form($true = NULL) {
$session =& $_SESSION['cmf_overview_filter'];
$session = is_array($session) ? $session : array();
$filters = cmf_filters($true);
drupal_add_css(drupal_get_path('module', 'cmf') . '/cmf.css');
// General settings display (max rows & content kind).
$form['general'] = array(
'#type' => 'fieldset',
'#title' => t('General Settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['general']['max-rows'] = array(
'#type' => 'textfield',
'#title' => t('Max rows'),
'#size' => 5,
'#default_value' => isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50,
'#prefix' => '<div class="container-inline">',
'#suffix' => '</div>',
);
$form['general']['show_nid'] = array(
'#type' => 'radios',
'#title' => t('Show node ID'),
'#options' => array(
0 => t('No'),
1 => t('Yes'),
),
'#default_value' => isset($_SESSION['cmf_show_nid']) ? $_SESSION['cmf_show_nid'] : 0,
'#prefix' => '<div class="container-inline"><div class="cmf-radios">',
'#suffix' => '</div></div><div class="clear-block"></div>',
);
$form['general']['kind'] = array(
'#type' => 'select',
'#title' => t('Content'),
'#options' => array(
'node' => t('node'),
'comment' => t('comment'),
'both' => t('both'),
),
'#default_value' => isset($_SESSION['cmf_content_kind']) ? $_SESSION['cmf_content_kind'] : 'node',
'#prefix' => '<div class="container-inline">',
);
$form['general']['buttons']['apply'] = array(
'#type' => 'submit',
'#value' => t('Apply'),
'#suffix' => '</div>',
);
$i = 0;
$form['filters'] = array(
'#type' => 'fieldset',
'#title' => t('Show only items where'),
'#theme' => 'node_filters',
);
foreach ($session as $filter) {
list($type, $value) = $filter;
if ($type == 'category') {
// Load term name from DB rather than search and parse options array.
$value = taxonomy_get_term($value);
$value = $value->name;
}
elseif ($type == 'title') {
// Just sanitize it and add quotes.
$value = "'" . $value . "'";
}
else {
$value = $filters[$type]['options'][$value];
}
// Avoid not applicable filter verbose. Note '%' does check_plain.
if ($type == 'title') {
if ($i++) {
$form['filters']['current'][] = array(
'#value' => t('<em>and</em> where <strong>%a</strong> contains <strong>%b</strong>', array(
'%a' => $filters[$type]['title'],
'%b' => $value,
)),
);
}
else {
$form['filters']['current'][] = array(
'#value' => t('<strong>%a</strong> contains <strong>%b</strong>', array(
'%a' => $filters[$type]['title'],
'%b' => $value,
)),
);
}
}
else {
if ($i++) {
$form['filters']['current'][] = array(
'#value' => t('<em>and</em> where <strong>%a</strong> is <strong>%b</strong>', array(
'%a' => $filters[$type]['title'],
'%b' => $value,
)),
);
}
else {
$form['filters']['current'][] = array(
'#value' => t('<strong>%a</strong> is <strong>%b</strong>', array(
'%a' => $filters[$type]['title'],
'%b' => $value,
)),
);
}
}
// These ifs remove the respective option if it is already being filtered on.
if ($type == 'type') {
unset($filters['type']);
}
if ($type == 'title') {
unset($filters['title']);
}
if ($type == 'user') {
unset($filters['users']);
unset($filters['user']);
}
if ($type == 'blocked') {
unset($filters['blocked']);
}
if ($type == 'role') {
unset($filters['role']);
}
}
/*
$script = 'document.getElementById(\'edit-user\').style.display="none"';
// $script = 'document.getElementById("edit-user").style.visibility="hidden"';
drupal_add_js($script, 'inline', 'header');
*/
// preparing select boxes
foreach ($filters as $key => $filter) {
$names[$key] = $filter['title'];
switch ($key) {
case 'user':
$form['filters']['status'][$key] = array(
'#type' => 'select',
'#options' => $filter['options'],
);
break;
case 'users':
$form['filters']['status'][$key] = array(
'#type' => 'textfield',
'#autocomplete_path' => 'cmf/userauto',
);
break;
case 'title':
$form['filters']['status'][$key] = array(
'#type' => 'textfield',
);
break;
default:
$form['filters']['status'][$key] = array(
'#type' => 'select',
'#options' => $filter['options'],
);
}
}
// building radio buttons
$keyz = array_keys($names);
$form['filters']['filter'] = array(
'#type' => 'radios',
'#options' => $names,
'#default_value' => $keyz[0],
);
// building buttons depending on the filter state
$form['filters']['buttons']['submit'] = array(
'#type' => 'submit',
'#value' => count($session) ? t('Refine') : t('Filter'),
);
if (count($session)) {
$form['filters']['buttons']['undo'] = array(
'#type' => 'submit',
'#value' => t('Undo'),
);
$form['filters']['buttons']['reset'] = array(
'#type' => 'submit',
'#value' => t('Reset'),
);
}
return $form;
}
/**
* Handle post-validation form submission.
*
* @ingroup forms
* @see cmf_filter_form()
*
* @param the ID of the passed form
* @param array with the form properties values
*/
function cmf_filter_form_submit($form_id, $form_values) {
$filters = cmf_filters();
switch ($form_values['op']) {
case t('Filter'):
case t('Refine'):
if (isset($form_values['filter'])) {
$filter = $form_values['filter'];
// convert AJAX search value to select box value
if ($filter == 'users') {
$users = cmf_get_users();
$uid = db_result(db_query('SELECT uid FROM {users} WHERE name = "%s"', $form_values['users']));
$form_values['user'] = $uid;
$filter = 'user';
}
if ($filter == 'title') {
$string = $form_values['title'];
$filters['title']['options'][$string] = $string;
}
// Flatten the options array to accommodate hierarchical/nested options.
$flat_options = form_options_flatten($filters[$filter]['options']);
if (isset($flat_options[$form_values[$filter]]) || $filter == 'title') {
$_SESSION['cmf_overview_filter'][] = array(
$filter,
$form_values[$filter],
);
}
}
break;
case t('Undo'):
array_pop($_SESSION['cmf_overview_filter']);
break;
case t('Reset'):
$_SESSION['cmf_overview_filter'] = array();
break;
case t('Apply'):
$_SESSION['cmf_max_rows'] = $form_values['max-rows'];
$_SESSION['cmf_show_nid'] = $form_values['show_nid'];
$_SESSION['cmf_content_kind'] = $form_values['kind'];
if (arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0) {
return 'user/' . arg(1) . '/cmf';
}
else {
return 'admin/content/filter';
}
break;
}
}
/**
* Theme cmf administration filter form.
*
* @themable
*/
function theme_cmf_filter_form($form) {
$output .= '<div id="cmf_header">';
$output .= drupal_render($form['general']);
// $output .= drupal_render($form['kind']);
$output .= '</div>';
$output .= '<div id="node-admin-filter">';
$output .= drupal_render($form['filters']);
$output .= '</div>';
$output .= drupal_render($form);
return $output;
}
/**
* List node administration filters that can be applied.
*
* @param (optional) TRUE if the filter to be built serves the user profile page
* @return array with filter properties
*/
function cmf_filters($true = NULL) {
// Regular filters
$filters['status'] = array(
'title' => t('node status'),
'options' => array(
'status-1' => t('published'),
'status-0' => t('not published'),
'promote-1' => t('promoted'),
'promote-0' => t('not promoted'),
'sticky-1' => t('sticky'),
'sticky-0' => t('not sticky'),
),
);
$filters['type'] = array(
'title' => t('node type'),
'options' => node_get_types('names'),
);
// The taxonomy filter
if ($taxonomy = module_invoke('taxonomy', 'form_all', 1)) {
$filters['category'] = array(
'title' => t('category'),
'options' => $taxonomy,
);
}
// Cmf filters.
$filters['title'] = array(
'title' => t('title/subject'),
);
// Don't show these on the user page.
if (!$true) {
$filters['user'] = array(
'title' => t('user list'),
'options' => cmf_get_users(),
);
$filters['users'] = array(
'title' => t('user name'),
);
$filters['role'] = array(
'title' => t('user role'),
'options' => cmf_get_roles('names'),
);
$filters['blocked'] = array(
'title' => t('user status'),
'options' => array(
1 => t('active'),
0 => t('blocked'),
),
);
}
return $filters;
}
/**
* QUERIES
*/
/**
* Build the variable parts of the query to be performed regarding the filter status.
*
* @return associative array with WHERE JOIN qury parts and respective arguments
*/
function cmf_build_filter_query() {
$filters = cmf_filters();
// Build query
$where = $args = array();
$join = '';
foreach ($_SESSION['cmf_overview_filter'] as $index => $filter) {
list($key, $value) = $filter;
switch ($key) {
case 'status':
// Note: no exploitable hole as $key/$value have already been checked when submitted
list($key, $value) = explode('-', $value, 2);
$where[] = 'n.' . $key . ' = %d';
break;
case 'category':
$table = "tn{$index}";
$where[] = "{$table}.tid = %d";
$join .= "INNER JOIN {term_node} {$table} ON n.nid = {$table}.nid ";
break;
case 'type':
$where[] = "n.type = '%s'";
break;
case 'user':
$where[] = "u.uid = %d";
break;
case 'role':
$where[] = "u.uid = ur.uid AND ur.rid = %d";
$join .= "INNER JOIN {users_roles} ur ON u.uid = ur.uid ";
break;
case 'title':
$where[] = "LOWER(n.title) LIKE LOWER('%%%s%%')";
break;
case 'users':
$where[] = "u.name = '%s'";
break;
case 'blocked':
$where[] = "u.status = %d AND u.uid != 0";
break;
}
$args[] = $value;
}
$where = count($where) ? 'WHERE ' . implode(' AND ', $where) : '';
return array(
'where' => $where,
'join' => $join,
'args' => $args,
);
}
/**
* Build the header of the result table.
*
* @return array respecting tablesort_sql()
*/
function cmf_build_header() {
$header = array();
if (user_access('filter and manage site content')) {
$header[] = theme('table_select_header_cell');
}
if ($_SESSION['cmf_show_nid']) {
$header[] = array(
'data' => t('ID'),
'field' => 'nid',
);
}
switch ($_SESSION['cmf_content_kind']) {
case 'node':
$header[] = array(
'data' => t('Title'),
'field' => 'title',
);
$header[] = array(
'data' => t('Kind'),
);
$header[] = array(
'data' => t('Node Type'),
'field' => 'type',
);
if (!(arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0)) {
$header[] = array(
'data' => t('Author'),
'field' => 'username',
);
}
$header[] = array(
'data' => t('Status'),
'field' => 'status',
);
$header[] = array(
'data' => t('Time'),
'field' => 'created',
'sort' => 'desc',
);
break;
case 'comment':
$header[] = array(
'data' => t('Subject'),
'field' => 'subject',
);
$header[] = array(
'data' => t('Kind'),
);
$header[] = array(
'data' => t('Node Type'),
'field' => 'type',
);
if (!(arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0)) {
$header[] = array(
'data' => t('Author'),
'field' => 'username',
);
}
$header[] = array(
'data' => t('Status'),
'field' => 'status',
);
$header[] = array(
'data' => t('Time'),
'field' => 'created',
'sort' => 'desc',
);
break;
case 'both':
$header[] = array(
'data' => t('Title') . '/' . t('Subject'),
'field' => 'title',
);
$header[] = array(
'data' => t('Kind'),
);
$header[] = array(
'data' => t('Node Type'),
'field' => 'type',
);
if (!(arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0)) {
$header[] = array(
'data' => t('Author'),
'field' => 'username',
);
}
$header[] = array(
'data' => t('Node Status'),
'field' => 'status',
);
$header[] = array(
'data' => t('Time'),
'field' => 'created',
'sort' => 'desc',
);
break;
}
if (user_access('filter and manage site content')) {
$header[] = array(
'data' => t('Operations'),
);
}
return $header;
}
/**
* Perform adjusted query.
*
* @param array respecting tablesort_sql()
* @return result of permormed query
*/
function cmf_perform_query($header, $kind = NULL) {
$filter = cmf_build_filter_query();
if (is_null($kind)) {
$kind = $_SESSION['cmf_content_kind'];
}
if (arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0) {
$filter['where'] .= ' AND u.uid = ' . arg(1);
}
switch ($kind) {
case 'node':
return pager_query('SELECT n.nid, n.title, n.type, n.status, n.created, ' . 'n.changed, n.promote, n.sticky, n.moderate, ' . 'u.name AS username, u.uid, r.body ' . 'FROM {node} n ' . 'JOIN {node_revisions} r ON r.vid = n.vid ' . 'INNER JOIN {users} u ON n.uid = u.uid ' . $filter['join'] . $filter['where'] . tablesort_sql($header), isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50, 0, NULL, $filter['args']);
break;
case 'comment':
return pager_query('SELECT c.cid, c.subject, c.nid, c.comment, c.timestamp AS created, ' . 'c.status, c.name, c.homepage, u.name AS username, u.uid, n.type ' . 'FROM {comments} c ' . 'INNER JOIN {node} n ON c.nid = n.nid ' . 'INNER JOIN {users} u ON u.uid = c.uid ' . $filter['join'] . $filter['where'] . tablesort_sql($header), isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50, 0, NULL, $filter['args']);
break;
case 'both':
$args = array_merge($filter['args'], $filter['args']);
$where = $filter['where'];
$cwhere = str_replace(array(
'n.title',
'n.uid',
), array(
'c.subject',
'c.uid',
), $where);
$count_query = 'SELECT (' . 'SELECT COUNT(*) FROM {node} n' . ' INNER JOIN {users} u ON n.uid = u.uid ' . $filter['join'] . ' ' . $where . ') + (' . 'SELECT COUNT(*) FROM {comments} c INNER JOIN {node} n ON c.nid = n.nid ' . ' INNER JOIN {users} u ON u.uid = c.uid ' . $filter['join'] . ' ' . $cwhere . ') AS count';
return pager_query('SELECT 0 AS cid, n.nid, n.title, NULL AS comment, n.type, n.status, n.created, ' . 'n.changed, n.promote, n.sticky, n.moderate, ' . 'u.name AS username, u.uid, r.body ' . 'FROM {node} n ' . 'JOIN {node_revisions} r ON r.vid = n.vid ' . 'INNER JOIN {users} u ON n.uid = u.uid ' . $filter['join'] . ' ' . $where . ' UNION SELECT c.cid, c.nid, c.subject AS title, c.comment, n.type, c.status, c.timestamp AS created, ' . '0 AS changed, 0 AS promote, 0 AS sticky, 0 AS moderate, ' . 'u.name AS username, u.uid, c.comment AS body ' . ' FROM {comments} c INNER JOIN {node} n ON c.nid = n.nid INNER JOIN {users} u ON u.uid = c.uid ' . $filter['join'] . ' ' . $cwhere . tablesort_sql($header), isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50, 0, $count_query, $args);
break;
}
}
/**
* RESULTS
*/
include drupal_get_path('module', 'cmf') . "/node.inc";
include drupal_get_path('module', 'cmf') . "/comment.inc";
include drupal_get_path('module', 'cmf') . "/both.inc";
/**
* AUX
*/
/**
* Builds a list of available users
*
* @param the format in which to return the list
* @return array of all available users
*/
function cmf_get_users() {
$result = db_query('SELECT uid, name FROM {users} WHERE uid <> 0 ORDER BY name');
$users = array();
$users[0] = variable_get('anonymous', t('anonymous'));
while ($account = db_fetch_object($result)) {
$users[$account->uid] = $account->name;
}
return $users;
}
/**
* Menu callback; Retrieve a JSON object containing autocomplete suggestions for existing users.
*/
function _cmf_user_autocomplete($string = '') {
$matches = array();
if ($string) {
$result = db_query("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER('%s%%')", $string);
while ($account = db_fetch_object($result)) {
$matches[$account->name] = check_plain($account->name);
}
}
print drupal_to_js($matches);
exit;
}
/**
* Builds a list of available roles
*
* @param the format in which to return the list
* @return array of all available roles
*/
function cmf_get_roles($op) {
switch ($op) {
case 'names':
$result = db_query('SELECT rid, name FROM {role} ORDER BY name');
break;
}
$roles = array();
for ($i = 0; $i < db_num_rows($result); $i++) {
$role = db_fetch_object($result);
$roles[$role->rid] = $role->name;
}
return $roles;
}
/**
* Get the html code of an image
*
* @param the pretended image
* @return html tag img
*/
function _cmf_get_img($action, $title) {
$path = base_path() . drupal_get_path('module', 'cmf') . '/images/' . $action . '.png';
if ($title == NULL) {
$html = '<img src="' . $path . '" alt="untitled image" />';
}
else {
$html = '<img src="' . $path . '" title="' . $title . '" alt="' . $title . '" />';
}
return $html;
}
/**
* Theme (node) type cell on table result.
*
* @ingroup themable
*
* @param 0 or node type key
* @return formated (node) type
*/
function theme_cmf_type($type) {
return db_result(db_query('SELECT name FROM {node_type} WHERE type = "%s"', $type));
}
/**
* Theme user cell on table result.
*
* @ingroup themable
*
* @param user ID
* @return clickable username with status
*/
function theme_cmf_user($uid) {
if ($uid == 0) {
return variable_get('anonymous', t('anonymous'));
}
$result = db_query('SELECT name, status FROM {users} WHERE uid = %d', $uid);
$user = db_fetch_array($result);
$url_alias = _cmf_get_user_path($uid);
$url = $url_alias ? $url_alias : 'user/' . $uid;
if ($user['status']) {
$output .= l($user['name'], $url, array());
}
else {
$output .= l(_cmf_get_img('blocked', t('blocked')) . ' ' . $user['name'], $url, array(), NULL, NULL, FALSE, TRUE);
}
return $output;
}
/**
* Get the alias path to a user profile
*
* @param user ID
* @return the relative URL of the user profile
*/
function _cmf_get_user_path($uid) {
return db_result(db_query('SELECT dst FROM {url_alias} WHERE src = "%s";', 'user/' . $uid));
}
/**
* Get the term for a forum node
*
* @param node ID
* @return the name and forum description
*/
function _cmf_get_forum($nid) {
$path = array();
$node = node_load($nid);
$parents = taxonomy_get_parents_all($node->tid);
foreach ($parents as $parent) {
$path[] = $parent->name;
}
return implode(' > ', array_reverse($path));
}
Functions
Name![]() |
Description |
---|---|
cmf_admin_content_page | Called when user goes to example.com/admin/content/filter |
cmf_build_filter_query | Build the variable parts of the query to be performed regarding the filter status. |
cmf_build_header | Build the header of the result table. |
cmf_filters | List node administration filters that can be applied. |
cmf_filter_form | Defines the form for content administration filters. |
cmf_filter_form_submit | Handle post-validation form submission. |
cmf_get_roles | Builds a list of available roles |
cmf_get_users | Builds a list of available users |
cmf_help | Implementation of hook_help(). |
cmf_menu | Implementation of hook_menu(). |
cmf_perform_query | Perform adjusted query. |
cmf_perm | Implementation of hook_perm(). |
theme_cmf_filter_form | Theme cmf administration filter form. |
theme_cmf_type | Theme (node) type cell on table result. |
theme_cmf_user | Theme user cell on table result. |
_cmf_get_forum | Get the term for a forum node |
_cmf_get_img | Get the html code of an image |
_cmf_get_user_path | Get the alias path to a user profile |
_cmf_user_autocomplete | Menu callback; Retrieve a JSON object containing autocomplete suggestions for existing users. |