Plugin Directory

Changeset 3490094


Ignore:
Timestamp:
03/24/2026 02:16:10 PM (5 days ago)
Author:
devpriyanshu
Message:

Release 1.0.2: fix taxonomy term create/edit access mapping and improve menu query-string matching

Location:
dp-admin-access-menu
Files:
3 edited
10 copied

Legend:

Unmodified
Added
Removed
  • dp-admin-access-menu/tags/1.0.2/dp-admin-access-menu.php

    r3487377 r3490094  
    44 * Plugin URI: https://wordpress.org/plugins/dp-admin-access-menu
    55 * Description: Control which WordPress backend menu items are visible to specific users. Perfect for managing user access and customizing admin experience.
    6  * Version: 1.0.1
     6 * Version: 1.0.2
    77 * Author: devpriyanshu
    88 * Author URI: https://profiles.wordpress.org/devpriyanshu/
     
    2121
    2222// Define plugin constants
    23 define('DPAMA_VERSION', '1.0.1');
     23define('DPAMA_VERSION', '1.0.2');
    2424define('DPAMA_PLUGIN_DIR', plugin_dir_path(__FILE__));
    2525define('DPAMA_PLUGIN_URL', plugin_dir_url(__FILE__));
  • dp-admin-access-menu/tags/1.0.2/includes/class-dpama-menu-filter.php

    r3487377 r3490094  
    4444       
    4545        $allowed_menus = $settings[$current_user_id];
     46        $normalized_allowed_menus = $this->normalize_menu_ids($allowed_menus);
    4647        global $menu, $submenu;
    4748       
     
    5960               
    6061                // Only show menus that are explicitly in the allowed list
    61                 if (!in_array($menu_id, $allowed_menus)) {
     62                if (!$this->is_menu_allowed($menu_id, $normalized_allowed_menus)) {
    6263                    // Mark for removal
    6364                    $menus_to_remove[] = $menu_key;
     
    7677                           
    7778                            // Only show child menus that are explicitly in the allowed list
    78                             if (!in_array($submenu_id, $allowed_menus)) {
     79                            if (!$this->is_menu_allowed($submenu_id, $normalized_allowed_menus)) {
    7980                                $children_to_remove[] = $submenu_key;
    8081                            }
     
    189190       
    190191        $allowed_menus = $settings[$current_user_id];
     192        $normalized_allowed_menus = $this->normalize_menu_ids($allowed_menus);
    191193       
    192194        // Get current page being accessed
     
    215217        foreach ($current_page_candidates as $candidate_page) {
    216218            // Direct match
    217             if (in_array($candidate_page, $allowed_menus, true)) {
     219            if ($this->is_menu_allowed($candidate_page, $normalized_allowed_menus)) {
    218220                $page_allowed = true;
    219221                break;
     
    221223           
    222224            // Check for partial matches (for query string variations)
    223             foreach ($allowed_menus as $allowed_menu) {
     225            foreach ($normalized_allowed_menus as $allowed_menu) {
    224226                // If current page starts with allowed menu or vice versa
    225227                if (strpos($candidate_page, $allowed_menu) === 0 || strpos($allowed_menu, $candidate_page) === 0) {
     
    308310        }
    309311       
    310         // For taxonomy pages
     312        // For taxonomy listing/create pages
    311313        if ($pagenow === 'edit-tags.php') {
    312314            // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Not processing form data, just reading URL parameters
     
    315317            $post_type = isset($_GET['post_type']) ? sanitize_text_field(wp_unslash($_GET['post_type'])) : 'post';
    316318           
    317             if ($post_type === 'post') {
    318                 return 'edit.php';
    319             } elseif ($post_type === 'page') {
    320                 return 'edit.php?post_type=page';
    321             } else {
    322                 return 'edit.php?post_type=' . $post_type;
    323             }
     319            if (!empty($taxonomy)) {
     320                if ($post_type === 'post') {
     321                    return 'edit-tags.php?taxonomy=' . $taxonomy;
     322                }
     323                return 'edit-tags.php?taxonomy=' . $taxonomy . '&post_type=' . $post_type;
     324            }
     325           
     326            // Fallback when taxonomy is missing.
     327            return 'edit-tags.php';
     328        }
     329       
     330        // For taxonomy term edit pages (e.g. WooCommerce product category edit).
     331        if ($pagenow === 'term.php') {
     332            // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Not processing form data, just reading URL parameter
     333            $taxonomy = isset($_GET['taxonomy']) ? sanitize_text_field(wp_unslash($_GET['taxonomy'])) : '';
     334            // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Not processing form data, just reading URL parameter
     335            $post_type = isset($_GET['post_type']) ? sanitize_text_field(wp_unslash($_GET['post_type'])) : 'post';
     336           
     337            if (!empty($taxonomy)) {
     338                if ($post_type === 'post') {
     339                    return 'term.php?taxonomy=' . $taxonomy;
     340                }
     341                return 'term.php?taxonomy=' . $taxonomy . '&post_type=' . $post_type;
     342            }
     343           
     344            return 'term.php';
    324345        }
    325346       
     
    373394        }
    374395       
     396        // Taxonomy listing/create pages should allow related term edit pages and vice versa.
     397        if (strpos($current_page, 'edit-tags.php?taxonomy=') === 0) {
     398            $candidates[] = str_replace('edit-tags.php?', 'term.php?', $current_page);
     399        } elseif (strpos($current_page, 'term.php?taxonomy=') === 0) {
     400            $candidates[] = str_replace('term.php?', 'edit-tags.php?', $current_page);
     401        }
     402       
    375403        return array_values(array_unique($candidates));
    376404    }
     
    393421        return $target_user_id > 0 && $target_user_id === (int) $superadmin_id;
    394422    }
     423   
     424    /**
     425     * Normalize a list of menu IDs for reliable matching.
     426     *
     427     * @param array $menu_ids Raw menu IDs.
     428     * @return array
     429     */
     430    private function normalize_menu_ids($menu_ids) {
     431        if (!is_array($menu_ids)) {
     432            return array();
     433        }
     434       
     435        $normalized = array();
     436        foreach ($menu_ids as $menu_id) {
     437            $normalized[] = $this->normalize_menu_id($menu_id);
     438        }
     439       
     440        return array_values(array_unique(array_filter($normalized)));
     441    }
     442   
     443    /**
     444     * Normalize one menu ID (slug + sorted query string).
     445     *
     446     * @param string $menu_id Raw menu ID.
     447     * @return string
     448     */
     449    private function normalize_menu_id($menu_id) {
     450        $menu_id = html_entity_decode((string) $menu_id, ENT_QUOTES, 'UTF-8');
     451       
     452        if (strpos($menu_id, '?') === false) {
     453            return $menu_id;
     454        }
     455       
     456        $parts = wp_parse_url($menu_id);
     457        if (!is_array($parts) || empty($parts['path'])) {
     458            return $menu_id;
     459        }
     460       
     461        if (empty($parts['query'])) {
     462            return $parts['path'];
     463        }
     464       
     465        $query_args = array();
     466        wp_parse_str($parts['query'], $query_args);
     467        ksort($query_args);
     468       
     469        return $parts['path'] . '?' . http_build_query($query_args, '', '&');
     470    }
     471   
     472    /**
     473     * Check if menu slug is in the allowed list.
     474     *
     475     * @param string $menu_id Menu slug to validate.
     476     * @param array  $normalized_allowed_menus Normalized allowed menu IDs.
     477     * @return bool
     478     */
     479    private function is_menu_allowed($menu_id, $normalized_allowed_menus) {
     480        $normalized_menu_id = $this->normalize_menu_id($menu_id);
     481        return in_array($normalized_menu_id, $normalized_allowed_menus, true);
     482    }
    395483}
    396484
  • dp-admin-access-menu/tags/1.0.2/readme.txt

    r3487377 r3490094  
    44Requires at least: 5.0
    55Tested up to: 6.9
    6 Stable tag: 1.0.1
     6Stable tag: 1.0.2
    77Requires PHP: 7.0
    88License: GPLv2 or later
     
    146146== Changelog ==
    147147
     148= 1.0.2 =
     149* Fixed taxonomy access mapping so allowed Category/Tag permissions correctly allow create and edit term pages (`edit-tags.php` and `term.php`) including WooCommerce product taxonomies.
     150* Improved normalized matching for menu slugs with query parameters to avoid false permission denials.
     151
    148152= 1.0.1 =
    149153* Fixed user management access mapping so Users menu access correctly allows `user-edit.php` and `user-new.php`.
     
    160164== Upgrade Notice ==
    161165
     166= 1.0.2 =
     167Fixes Category/Tag create-edit permissions for taxonomy pages and improves query-string menu matching.
     168
    162169= 1.0.1 =
    163170Fixes user edit access behavior for allowed Users menu and adds stricter superadmin account protection.
  • dp-admin-access-menu/trunk/dp-admin-access-menu.php

    r3487377 r3490094  
    44 * Plugin URI: https://wordpress.org/plugins/dp-admin-access-menu
    55 * Description: Control which WordPress backend menu items are visible to specific users. Perfect for managing user access and customizing admin experience.
    6  * Version: 1.0.1
     6 * Version: 1.0.2
    77 * Author: devpriyanshu
    88 * Author URI: https://profiles.wordpress.org/devpriyanshu/
     
    2121
    2222// Define plugin constants
    23 define('DPAMA_VERSION', '1.0.1');
     23define('DPAMA_VERSION', '1.0.2');
    2424define('DPAMA_PLUGIN_DIR', plugin_dir_path(__FILE__));
    2525define('DPAMA_PLUGIN_URL', plugin_dir_url(__FILE__));
  • dp-admin-access-menu/trunk/includes/class-dpama-menu-filter.php

    r3487377 r3490094  
    4444       
    4545        $allowed_menus = $settings[$current_user_id];
     46        $normalized_allowed_menus = $this->normalize_menu_ids($allowed_menus);
    4647        global $menu, $submenu;
    4748       
     
    5960               
    6061                // Only show menus that are explicitly in the allowed list
    61                 if (!in_array($menu_id, $allowed_menus)) {
     62                if (!$this->is_menu_allowed($menu_id, $normalized_allowed_menus)) {
    6263                    // Mark for removal
    6364                    $menus_to_remove[] = $menu_key;
     
    7677                           
    7778                            // Only show child menus that are explicitly in the allowed list
    78                             if (!in_array($submenu_id, $allowed_menus)) {
     79                            if (!$this->is_menu_allowed($submenu_id, $normalized_allowed_menus)) {
    7980                                $children_to_remove[] = $submenu_key;
    8081                            }
     
    189190       
    190191        $allowed_menus = $settings[$current_user_id];
     192        $normalized_allowed_menus = $this->normalize_menu_ids($allowed_menus);
    191193       
    192194        // Get current page being accessed
     
    215217        foreach ($current_page_candidates as $candidate_page) {
    216218            // Direct match
    217             if (in_array($candidate_page, $allowed_menus, true)) {
     219            if ($this->is_menu_allowed($candidate_page, $normalized_allowed_menus)) {
    218220                $page_allowed = true;
    219221                break;
     
    221223           
    222224            // Check for partial matches (for query string variations)
    223             foreach ($allowed_menus as $allowed_menu) {
     225            foreach ($normalized_allowed_menus as $allowed_menu) {
    224226                // If current page starts with allowed menu or vice versa
    225227                if (strpos($candidate_page, $allowed_menu) === 0 || strpos($allowed_menu, $candidate_page) === 0) {
     
    308310        }
    309311       
    310         // For taxonomy pages
     312        // For taxonomy listing/create pages
    311313        if ($pagenow === 'edit-tags.php') {
    312314            // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Not processing form data, just reading URL parameters
     
    315317            $post_type = isset($_GET['post_type']) ? sanitize_text_field(wp_unslash($_GET['post_type'])) : 'post';
    316318           
    317             if ($post_type === 'post') {
    318                 return 'edit.php';
    319             } elseif ($post_type === 'page') {
    320                 return 'edit.php?post_type=page';
    321             } else {
    322                 return 'edit.php?post_type=' . $post_type;
    323             }
     319            if (!empty($taxonomy)) {
     320                if ($post_type === 'post') {
     321                    return 'edit-tags.php?taxonomy=' . $taxonomy;
     322                }
     323                return 'edit-tags.php?taxonomy=' . $taxonomy . '&post_type=' . $post_type;
     324            }
     325           
     326            // Fallback when taxonomy is missing.
     327            return 'edit-tags.php';
     328        }
     329       
     330        // For taxonomy term edit pages (e.g. WooCommerce product category edit).
     331        if ($pagenow === 'term.php') {
     332            // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Not processing form data, just reading URL parameter
     333            $taxonomy = isset($_GET['taxonomy']) ? sanitize_text_field(wp_unslash($_GET['taxonomy'])) : '';
     334            // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Not processing form data, just reading URL parameter
     335            $post_type = isset($_GET['post_type']) ? sanitize_text_field(wp_unslash($_GET['post_type'])) : 'post';
     336           
     337            if (!empty($taxonomy)) {
     338                if ($post_type === 'post') {
     339                    return 'term.php?taxonomy=' . $taxonomy;
     340                }
     341                return 'term.php?taxonomy=' . $taxonomy . '&post_type=' . $post_type;
     342            }
     343           
     344            return 'term.php';
    324345        }
    325346       
     
    373394        }
    374395       
     396        // Taxonomy listing/create pages should allow related term edit pages and vice versa.
     397        if (strpos($current_page, 'edit-tags.php?taxonomy=') === 0) {
     398            $candidates[] = str_replace('edit-tags.php?', 'term.php?', $current_page);
     399        } elseif (strpos($current_page, 'term.php?taxonomy=') === 0) {
     400            $candidates[] = str_replace('term.php?', 'edit-tags.php?', $current_page);
     401        }
     402       
    375403        return array_values(array_unique($candidates));
    376404    }
     
    393421        return $target_user_id > 0 && $target_user_id === (int) $superadmin_id;
    394422    }
     423   
     424    /**
     425     * Normalize a list of menu IDs for reliable matching.
     426     *
     427     * @param array $menu_ids Raw menu IDs.
     428     * @return array
     429     */
     430    private function normalize_menu_ids($menu_ids) {
     431        if (!is_array($menu_ids)) {
     432            return array();
     433        }
     434       
     435        $normalized = array();
     436        foreach ($menu_ids as $menu_id) {
     437            $normalized[] = $this->normalize_menu_id($menu_id);
     438        }
     439       
     440        return array_values(array_unique(array_filter($normalized)));
     441    }
     442   
     443    /**
     444     * Normalize one menu ID (slug + sorted query string).
     445     *
     446     * @param string $menu_id Raw menu ID.
     447     * @return string
     448     */
     449    private function normalize_menu_id($menu_id) {
     450        $menu_id = html_entity_decode((string) $menu_id, ENT_QUOTES, 'UTF-8');
     451       
     452        if (strpos($menu_id, '?') === false) {
     453            return $menu_id;
     454        }
     455       
     456        $parts = wp_parse_url($menu_id);
     457        if (!is_array($parts) || empty($parts['path'])) {
     458            return $menu_id;
     459        }
     460       
     461        if (empty($parts['query'])) {
     462            return $parts['path'];
     463        }
     464       
     465        $query_args = array();
     466        wp_parse_str($parts['query'], $query_args);
     467        ksort($query_args);
     468       
     469        return $parts['path'] . '?' . http_build_query($query_args, '', '&');
     470    }
     471   
     472    /**
     473     * Check if menu slug is in the allowed list.
     474     *
     475     * @param string $menu_id Menu slug to validate.
     476     * @param array  $normalized_allowed_menus Normalized allowed menu IDs.
     477     * @return bool
     478     */
     479    private function is_menu_allowed($menu_id, $normalized_allowed_menus) {
     480        $normalized_menu_id = $this->normalize_menu_id($menu_id);
     481        return in_array($normalized_menu_id, $normalized_allowed_menus, true);
     482    }
    395483}
    396484
  • dp-admin-access-menu/trunk/readme.txt

    r3487377 r3490094  
    44Requires at least: 5.0
    55Tested up to: 6.9
    6 Stable tag: 1.0.1
     6Stable tag: 1.0.2
    77Requires PHP: 7.0
    88License: GPLv2 or later
     
    146146== Changelog ==
    147147
     148= 1.0.2 =
     149* Fixed taxonomy access mapping so allowed Category/Tag permissions correctly allow create and edit term pages (`edit-tags.php` and `term.php`) including WooCommerce product taxonomies.
     150* Improved normalized matching for menu slugs with query parameters to avoid false permission denials.
     151
    148152= 1.0.1 =
    149153* Fixed user management access mapping so Users menu access correctly allows `user-edit.php` and `user-new.php`.
     
    160164== Upgrade Notice ==
    161165
     166= 1.0.2 =
     167Fixes Category/Tag create-edit permissions for taxonomy pages and improves query-string menu matching.
     168
    162169= 1.0.1 =
    163170Fixes user edit access behavior for allowed Users menu and adds stricter superadmin account protection.
Note: See TracChangeset for help on using the changeset viewer.