Make WordPress Core

Ticket #60832: poc-bug.php

File poc-bug.php, 7.8 KB (added by malcure, 9 months ago)

A PoC plugin with possible fix

Line 
1<?php
2/**
3 * PoC Bug: add_meta_box breaks if add_menu_page has dynamic title
4 *
5 * @package     Dynamic add_menu_page Title
6 *
7 * @wordpress-plugin
8 * Plugin Name: Dynamic add_menu_page Title
9 * Description: PoC Bug: add_meta_box breaks if add_menu_page has dynamic title
10 * Version:     0.1
11 * Author:      Malcure
12 * License:     MIT
13 */
14if ( ! defined( 'ABSPATH' ) ) {
15        exit;
16}
17
18
19class MyPlugin {
20        private $cap = 'activate_plugins';
21
22        private function __construct() {
23        }
24
25        static function get_instance() {
26                static $instance = null;
27                if ( is_null( $instance ) ) {
28                        $instance = new self();
29                        $instance->init();
30                }
31                return $instance;
32        }
33
34        function init() {
35                add_action( 'admin_menu', array( $this, 'menu' ) );
36                add_action( 'current_screen', array( $this, 'handle_screen' ) );
37        }
38
39        function menu() {
40                add_filter( 'sanitize_title', array( $this, 'screen_obj_fix' ), 9, 3 );
41
42                // Dynamic Menu Title
43                $count          = $this->count();
44                $top_menu_title = empty( $count ) ? 'My Plugin' : 'My Plugin <span class="menu-counter">' . $count . '</span>';
45
46                add_menu_page(
47                        'My Plugin', // page_title
48                        $top_menu_title, // menu_title
49                        $this->cap, // capability
50                        'myplugintop', // menu_slug
51                        array( $this, 'top_page' ), // function
52                        'dashicons-admin-generic', // icon_url
53                        6 // position
54                );
55                $count = $this->count();
56                // Dynamic Sub-Menu Title
57                $sub_menu_title = empty( $count ) ? 'Sub-Page' : 'Sub-Page <span class="menu-counter">' . $count . '</span>';
58                // add_submenu_page( string $parent_slug, string $page_title, string $menu_title, string $capability, string $menu_slug, callable $callback = ”, int|float $position = null ): string|false
59                add_submenu_page(
60                        'myplugintop', // parent_slug
61                        'My Plugin Page', // page_title
62                        $top_menu_title, // menu_title
63                        $this->cap, // capability
64                        'myplugintop', // menu_slug
65                        array( $this, 'top_page' )// function
66                );
67                add_submenu_page( 'myplugintop', 'My Plugin Sub-Page', $sub_menu_title, $this->cap, 'mypluginsub', array( $this, 'sub_page' ) );
68
69                remove_filter( 'sanitize_title', array( $this, 'screen_obj_fix' ), 9 );
70        }
71
72        function top_page() {
73                $screen = get_current_screen();
74                ?>
75                <div class="wrap">
76                        <h1 id="page_title">Top Page Heading</h1>
77                        <div id="poststuff">
78                                <div class="metabox-holder columns-2" id="post-body">
79                                        <div class="postbox-container" id="post-body-content">
80                                                        <?php
81                                                        do_meta_boxes( $screen->id, 'main', null );
82                                                        // This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
83                                                        ?>
84                                        </div>
85                                        <!-- #postbox-container -->
86                                        <div id="postbox-container-1" class="postbox-container">
87                                                <?php
88                                                        do_meta_boxes( $screen->id, 'side', null );
89                                                        // This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
90                                                ?>
91                                        </div>
92                                </div>
93                        </div>
94                </div>
95                <script type="text/javascript">
96                        jQuery(document).ready(function($) { //wrapper
97                                // close postboxes that should be closed
98                                $('.if-js-closed').removeClass('if-js-closed').addClass('closed');
99                                // postboxes setup
100                                postboxes.add_postbox_toggles('<?php echo $screen->id; ?>');
101                                $('#main-sortables .postbox').not(':first').addClass('closed');
102                        });
103                </script>
104                <?php
105        }
106
107        function sub_page() {
108                $screen = get_current_screen();
109                ?>
110                <div class="wrap myplugin-test">
111                        <h1>Sub-Page Heading</h1>
112                        <div id="poststuff">
113                                <div class="metabox-holder columns-2" id="post-body">
114                                        <div class="postbox-container" id="post-body-content">
115                                                <?php
116                                                do_meta_boxes( $screen->id, 'main', null );
117                                                // This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
118                                                ?>
119                                        </div>
120                                        <!-- #postbox-container -->
121                                        <div id="postbox-container-1" class="postbox-container">
122                                                <?php
123                                                        do_meta_boxes( $screen->id, 'side', null );
124                                                        // This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
125                                                ?>
126                                        </div>
127                                </div>
128                        </div>
129                </div>
130                <script type="text/javascript">
131                        jQuery(document).ready(function($) { //wrapper
132                                // close postboxes that should be closed
133                                $('.if-js-closed').removeClass('if-js-closed').addClass('closed');
134                                // postboxes setup
135                                postboxes.add_postbox_toggles('<?php echo $screen->id; ?>');
136                                $('#main-sortables .postbox').not(':first').addClass('closed');
137                        });
138                </script>
139                <?php
140        }
141
142        function handle_screen( $screen ) {
143                flog( $screen->id );
144                if ( preg_match( '/myplugin/', $screen->id ) ) {
145                        $this->add_action_meta_boxes();
146                        $this->do_action_meta_boxes();
147                        $this->myplugin_enqueue_js_dependencies();
148                }
149        }
150
151        function myplugin_enqueue_js_dependencies() {
152                wp_enqueue_script( 'jquery' );
153                wp_enqueue_script( 'common' );
154                wp_enqueue_script( 'wp-lists' );
155                wp_enqueue_script( 'postbox' );
156        }
157
158        function count() {
159                // return an random int
160                return random_int( 0, 10 );
161        }
162
163        function screen_obj_fix( $title, $raw_title, $context ) {
164                // Comment Out The Next Line To Fix The Issus
165                return $title;
166                error_log( '$title' . $title );
167                $title = trim( preg_replace( '/<[^>]*?>.*?<\/[^>]*?>/si', '', $title ) );
168                error_log( '$title' . $title );
169                return $title;
170        }
171
172        function do_action_meta_boxes() {
173                do_action( 'add_meta_boxes', 'toplevel_page_myplugin', '' ); // This is a way to trigger the 'add_meta_boxes' hook. WordPress core calls this action hook during the page load of admin screens that can have meta boxes. By using do_action(), you can manually trigger all functions attached to the 'add_meta_boxes' hook. This is useful for dynamically adding meta boxes based on certain conditions. However, it's more common to see WordPress itself triggering this action rather than being manually called in most themes and plugins.
174        }
175
176        function add_action_meta_boxes() {
177                add_action( 'add_meta_boxes', array( $this, 'myplugin_add_metaboxes' ) ); // This function is used to register a callback function to the 'add_meta_boxes' hook. This is how you tell WordPress, "Hey, when you're at the point of adding meta boxes, also add this one that I'm specifying here." The callback function you register will typically use the add_meta_box() function to define the meta box (its ID, title, callback for rendering its content, the screen it should appear on, and its context).
178        }
179
180        function myplugin_add_metaboxes() {
181                add_meta_box( 'myplugin_test_box', 'Test Meta Box', array( $this, 'meta_box_logs_test' ), 'toplevel_page_myplugintop', 'main', 'high' );
182                add_meta_box( 'myplugin_test_box', 'Test Meta Box', array( $this, 'meta_box_logs_test' ), 'my-plugin_page_mypluginsub', 'main', 'high' );
183        }
184
185        function meta_box_logs_test() {
186                ?>
187                This is a test metabox.
188                <?php
189        }
190}
191
192function myplugin() {
193        return MyPlugin::get_instance();
194}
195
196myplugin();