Changeset 3449426
- Timestamp:
- 01/29/2026 09:56:56 AM (6 weeks ago)
- Location:
- slug-search-and-admin-columns
- Files:
-
- 25 added
- 6 edited
-
assets/screenshot-1.png (modified) (previous)
-
tags/2.0.0 (added)
-
tags/2.0.0/admin (added)
-
tags/2.0.0/admin/css (added)
-
tags/2.0.0/admin/css/admin.css (added)
-
tags/2.0.0/admin/css/index.php (added)
-
tags/2.0.0/admin/images (added)
-
tags/2.0.0/admin/images/speedy-go.gif (added)
-
tags/2.0.0/admin/images/wysiwyg-character-limit-for-acf.png (added)
-
tags/2.0.0/admin/index.php (added)
-
tags/2.0.0/admin/js (added)
-
tags/2.0.0/admin/js/admin.js (added)
-
tags/2.0.0/admin/js/index.php (added)
-
tags/2.0.0/admin/templates (added)
-
tags/2.0.0/admin/templates/index.php (added)
-
tags/2.0.0/admin/templates/settings-page.php (added)
-
tags/2.0.0/includes (added)
-
tags/2.0.0/includes/class-ssac-columns.php (added)
-
tags/2.0.0/includes/class-ssac-search.php (added)
-
tags/2.0.0/includes/class-ssac-settings.php (added)
-
tags/2.0.0/includes/helpers.php (added)
-
tags/2.0.0/includes/index.php (added)
-
tags/2.0.0/index.php (added)
-
tags/2.0.0/readme.txt (added)
-
tags/2.0.0/slug-search-and-admin-columns.php (added)
-
tags/2.0.0/uninstall.php (added)
-
trunk/admin/templates/settings-page.php (modified) (1 diff)
-
trunk/includes/class-ssac-search.php (modified) (3 diffs)
-
trunk/includes/class-ssac-settings.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (7 diffs)
-
trunk/slug-search-and-admin-columns.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
slug-search-and-admin-columns/trunk/admin/templates/settings-page.php
r3425226 r3449426 128 128 129 129 <!-- Search --> 130 <div class="ssac-section-card">131 <div class="ssac-section-card-header">132 <h2><?php esc_html_e('Search Settings', 'slug-search-and-admin-columns'); ?></h2>133 <p class="description">134 <?php esc_html_e('Choose how to search for posts.', 'slug-search-and-admin-columns'); ?>135 </p>136 </div>137 138 <div class="ssac-field-row-parent">139 <div class="ssac-field-row">140 <div class="ssac-field-label">141 <?php esc_html_e('Search Mode', 'slug-search-and-admin-columns'); ?>142 <span class="ssac-help-icon" data-tooltip="<?php esc_attr_e('Exact matches the whole slug; Partial searches anywhere within the slug (useful for fragments).', 'slug-search-and-admin-columns'); ?>">143 <span class="dashicons dashicons-editor-help"></span>144 </span>145 </div>146 <div class="ssac-field-control ssac-radio-group">147 <label>148 <input type="radio" name="ssac_settings[search_mode]" value="exact" <?php checked($ssac_settings['search_mode'], 'exact'); ?> />149 <span><?php esc_html_e('Exact Match', 'slug-search-and-admin-columns'); ?></span>150 </label>151 <label>152 <input type="radio" name="ssac_settings[search_mode]" value="partial" <?php checked($ssac_settings['search_mode'], 'partial'); ?> />153 <span><?php esc_html_e('Partial Match', 'slug-search-and-admin-columns'); ?></span>154 </label>155 </div>156 </div>157 <div class="ssac-field-row">158 <div class="ssac-field-label">159 <?php esc_html_e('Case Sensitive?', 'slug-search-and-admin-columns'); ?>160 <span class="ssac-help-icon" data-tooltip="<?php esc_attr_e('Treat uppercase and lowercase as different.', 'slug-search-and-admin-columns'); ?>">161 <span class="dashicons dashicons-editor-help"></span>162 </span>163 </div>164 <div class="ssac-field-control">165 <label>166 <input type="checkbox" name="ssac_settings[case_sensitive]" value="1" <?php checked($ssac_settings['case_sensitive']); ?> />167 <?php esc_html_e('Treat uppercase and lowercase as different.', 'slug-search-and-admin-columns'); ?>168 </label>169 </div>170 </div>171 </div>172 </div>173 174 130 <!-- Capability --> 175 131 <div class="ssac-section-card"> -
slug-search-and-admin-columns/trunk/includes/class-ssac-search.php
r3425226 r3449426 22 22 23 23 /** 24 * Partial slug search term25 *26 * @var string|null27 */28 private static $partial_slug = null;29 30 /**31 * Active WP_Query instance32 *33 * @var WP_Query|null34 */35 private static $active_query = null;36 37 38 /**39 24 * Initialize the search functionality 40 25 * 41 * Hooks into WordPress actions to add search field and handle search queries26 * Hooks into WordPress actions to integrate slug search into global WP admin search 42 27 * 43 28 * @return void … … 45 30 public static function init() 46 31 { 47 add_action('restrict_manage_posts', [__CLASS__, 'add_slug_search_field']); 48 add_action('pre_get_posts', [__CLASS__, 'handle_slug_search']); 32 add_filter('posts_search', [__CLASS__, 'include_slug_in_search'], 10, 2); 49 33 } 50 34 51 35 52 36 /** 53 * Add slug search field to admin post list filters37 * Include post slug in global WordPress admin search 54 38 * 55 * Displays a search input field in the post list table filters area 39 * Modifies the search query to search ONLY in post slugs when users use the 40 * standard WordPress admin search box 56 41 * 57 * Security Note: This method does not use nonce verification because it handles 58 * standard WordPress admin list table filters (like search, category, etc.). 59 * Per WordPress core conventions, list table filters do not require nonces as they: 60 * 1. Are only accessible to logged-in users with appropriate capabilities 61 * 2. Are read-only GET parameters that don't modify data 62 * 3. Follow the same pattern as WordPress' native filters 42 * Security Note: This method sanitizes the search term from WordPress core. 43 * The $search parameter comes from WordPress's native search handling which 44 * already sanitizes the input. This filter only modifies the WHERE clause 45 * for read-only query purposes. 63 46 * 64 * @return void 47 * @param string $search The WHERE clause of the search query 48 * @param WP_Query $query The WP_Query instance 49 * @return string Modified WHERE clause for slug-only search 65 50 */ 66 public static function add_slug_search_field() 67 { 68 global $typenow; 69 70 $settings = SSAC_Settings::get_settings(); 71 72 // Only show on enabled post types 73 if (!in_array($typenow, $settings['post_types'], true)) { 74 return; 75 } 76 77 // Check user capability - only users with the required capability can see this field 78 if (!current_user_can($settings['capability'])) { 79 return; 80 } 81 82 // Lint-safe: Search filters in admin list tables use GET without nonces per WordPress core convention. 83 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- core WP convention 84 $ssac_slug_input = ''; 85 86 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- core WP convention 87 if (isset($_GET['ssac_slug'])) { 88 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 89 $ssac_slug_input = sanitize_text_field(wp_unslash($_GET['ssac_slug'])); 90 } 91 92 // Output search field 93 printf( 94 '<input type="text" name="ssac_slug" placeholder="%s" value="%s" />', 95 esc_attr__('Search by slug…', 'slug-search-and-admin-columns'), 96 esc_attr($ssac_slug_input) 97 ); 98 } 99 100 101 /** 102 * Handle slug search query modification 103 * 104 * Modifies the main query to search by post slug based on user input 105 * 106 * Security Note: This method does not use nonce verification for the following reasons: 107 * 1. It hooks into 'pre_get_posts' which filters read-only query parameters 108 * 2. All data is sanitized with sanitize_text_field() and wp_unslash() 109 * 3. User capability is strictly checked with current_user_can() 110 * 4. This follows WordPress core conventions for list table filters 111 * 5. No data is modified based on $_GET input - only query parameters are altered 112 * 113 * See WordPress Developer Handbook: List Tables and Security 114 * https://developer.wordpress.org/plugins/security/nonces/ 115 * 116 * @param WP_Query $query The WordPress query object 117 * @return void 118 */ 119 public static function handle_slug_search($query) 51 public static function include_slug_in_search($search, $query) 120 52 { 121 53 // Only run in admin on main query 122 54 if (!is_admin() || !$query->is_main_query()) { 123 return ;55 return $search; 124 56 } 125 57 … … 130 62 // Only run on enabled post types 131 63 if (!in_array($ptype, $settings['post_types'])) { 132 return ;64 return $search; 133 65 } 134 66 135 // Check user capability - critical security check 136 // Only users with the required capability can filter by slug 67 // Check user capability 137 68 if (!current_user_can($settings['capability'])) { 138 return ;69 return $search; 139 70 } 140 71 141 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 142 // Reason: WP Admin List Table filters (search, dropdowns, custom GET params) 143 // do not use nonces in core and are safe when sanitized and capability-checked. 144 $ssac_slug = ''; 145 146 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- core WP convention 147 if (isset($_GET['ssac_slug'])) { 148 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- core WP convention 149 $ssac_slug = sanitize_text_field(wp_unslash($_GET['ssac_slug'])); 72 // Only modify if there's a search term 73 $search_term = $query->get('s'); 74 if (empty($search_term)) { 75 return $search; 150 76 } 151 77 152 // Exit if no search term153 if ( empty($ssac_slug)) {154 return ;78 // Check if search term matches slug pattern (lowercase, hyphens, numbers only) 79 if (!preg_match('/^[a-z0-9\-]+$/', $search_term)) { 80 return $search; 155 81 } 156 82 157 $mode = $settings['search_mode'];83 global $wpdb; 158 84 159 // Handle exact match 160 if ($mode === 'exact') { 161 $query->set('name', $ssac_slug); 162 } else { 163 // Handle partial match 164 self::$partial_slug = $ssac_slug; 165 self::$active_query = $query; 166 add_filter('posts_where', [__CLASS__, 'posts_where_partial']); 167 add_filter('posts_request', [__CLASS__, 'remove_partial_filter']); 168 } 85 // Replace the entire search with slug-only search 86 // This searches ONLY the post_name (slug) field 87 $search = $wpdb->prepare("AND ({$wpdb->posts}.post_name LIKE %s)", '%' . $search_term . '%'); 88 89 return $search; 169 90 } 170 91 171 92 172 /**173 * Modify WHERE clause for partial slug search174 *175 * Adds LIKE condition to search for partial slug matches176 *177 * @param string $where The WHERE clause of the query178 * @return string Modified WHERE clause179 */180 public static function posts_where_partial($where)181 {182 global $wpdb;183 184 // Add partial match condition if we have an active search185 if (self::$partial_slug && self::$active_query && self::$active_query->is_main_query()) {186 $where .= $wpdb->prepare(" AND {$wpdb->posts}.post_name LIKE %s", '%' . self::$partial_slug . '%');187 }188 189 return $where;190 }191 192 193 /**194 * Remove partial search filter after query is built195 *196 * Cleans up filters and resets static properties after the query is complete197 *198 * @param string $request The complete SQL query199 * @return string Unmodified SQL query200 */201 public static function remove_partial_filter($request)202 {203 // Remove filters204 remove_filter('posts_where', [__CLASS__, 'posts_where_partial']);205 remove_filter('posts_request', [__CLASS__, 'remove_partial_filter']);206 207 // Reset static properties208 self::$partial_slug = null;209 self::$active_query = null;210 211 return $request;212 }213 214 93 } 215 -
slug-search-and-admin-columns/trunk/includes/class-ssac-settings.php
r3425226 r3449426 39 39 'label_id' => 'ID', 40 40 'label_slug' => 'Slug', 41 'search_mode' => 'partial',42 'case_sensitive' => 0,43 41 'capability' => 'edit_posts', 44 42 ]; … … 158 156 $output['enable_id'] = !empty($input['enable_id']) ? 1 : 0; 159 157 $output['enable_slug'] = !empty($input['enable_slug']) ? 1 : 0; 160 $output['case_sensitive'] = !empty($input['case_sensitive']) ? 1 : 0;161 158 162 159 // Sanitize text labels … … 164 161 $output['label_slug'] = isset($input['label_slug']) ? sanitize_text_field($input['label_slug']) : self::$defaults['label_slug']; 165 162 166 // Sanitize search mode167 $output['search_mode'] = in_array($input['search_mode'], ['exact', 'partial']) ? $input['search_mode'] : 'partial';168 169 163 // Sanitize capability 170 164 $caps = ['manage_options', 'edit_others_posts', 'edit_posts', 'read']; -
slug-search-and-admin-columns/trunk/readme.txt
r3426055 r3449426 6 6 Tested up to: 6.9 7 7 Requires PHP: 7.4 8 Stable tag: 1.0.18 Stable tag: 2.0.0 9 9 License: GPLv2 or later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 20 20 * **Slug Search** - Search posts, pages, and custom post types by their slug (URL path) 21 21 * **Sortable Columns** - Add ID and Slug columns to admin post lists with sorting capability 22 * **Flexible Search Modes** - Choose between exact match or partial match search 22 * **Integrated Search** - Works directly with the default WordPress search box 23 * **Smart Detection** - Automatically detects slug searches without configuration 23 24 * **Post Type Control** - Enable features for specific post types only 24 25 * **User Permissions** - Control which user roles can see the columns and search … … 101 102 2. Select which post types to enable (Posts, Pages, Custom Post Types) 102 103 3. Enable ID and/or Slug columns as needed 103 4. Choose search mode (Exact or Partial match) 104 5. Set user capability level for column visibility105 6. Customize column labels if desired106 7. Click **Save Changes**107 108 That's it! The search field and columns will nowappear in your admin post lists.104 105 4. Set user capability level for column visibility 106 5. Customize column labels if desired 107 6. Click **Save Changes** 108 109 That's it! You can now search by slug directly in the main WordPress search bar, and columns will appear in your admin post lists. 109 110 110 111 == Frequently Asked Questions == … … 120 121 = Will this slow down my admin panel? = 121 122 122 No. The plugin is lightweight and only runs in the WordPress admin area. It uses native WordPress queries and is optimized for performance. For very large sites, using "Exact" search mode is recommended for faster results.123 No. The plugin is lightweight and only runs in the WordPress admin area. It uses native WordPress queries and is optimized for performance. 123 124 124 125 = Can I customize the column labels? = … … 126 127 Yes! You can customize the labels for both the ID and Slug columns from the settings page to match your workflow or language preferences. 127 128 128 = What's the difference between Exact and Partial search? = 129 130 * **Exact Match**: Finds posts where the slug exactly matches your search term (faster) 131 * **Partial Match**: Finds posts where the slug contains your search term anywhere (more flexible) 129 132 130 133 131 = Does it work with Gutenberg and Classic Editor? = … … 157 155 == Screenshots == 158 156 159 1. ** Slug Search Field** - Search by slug input field in the post list table filters157 1. **Integrated Search** - Search by slug directly using the default WordPress search box 160 158 2. **ID and Slug Columns** - Sortable ID and Slug columns in the admin post list 161 159 3. **Settings Page** - Comprehensive settings panel with post type selection 162 160 4. **Column Customization** - Enable/disable columns and customize labels 163 5. **Search Modes** - Choose between exact and partial match search164 161 6. **User Permissions** - Control which user roles can access features 165 162 166 163 == Changelog == 164 165 = 2.0.0 - 2026-01-29 = 166 * Major Update: Search functionality now integrated directly into the main WordPress search box. 167 * Improvement: Removed separate "Slug Search" input field for a cleaner UI. 168 * Improvement: Removed "Search Mode" settings; plugin now automatically handles fuzzy/partial matching for slug-like queries. 169 * Enhancement: Streamlined codebase for better performance. 167 170 168 171 = 1.0.1 - 2025-12-23 = … … 186 189 == Upgrade Notice == 187 190 191 = 2.0.0 = 192 Major update: Search is now integrated into the main WordPress search bar. Separate search field has been removed. 193 188 194 = 1.0.1 = 189 195 Critical update: Fixes fatal error on activation and potential conflicts with other plugins. Upgrade immediately. -
slug-search-and-admin-columns/trunk/slug-search-and-admin-columns.php
r3426055 r3449426 3 3 * Plugin Name: Slug Search and Admin Columns 4 4 * Description: Adds slug search and ID/slug columns to WP admin. Settings included. 5 * Version: 1.0.15 * Version: 2.0.0 6 6 * Author: Code and Core 7 7 * Author URI: https://codeandcore.com
Note: See TracChangeset
for help on using the changeset viewer.