| @@ -31,8 +31,29 @@ | ||
| 31 | 31 | $this->route(); |
| 32 | 32 | } |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | + /** | |
| 36 | + * Render the page by delegating to the routed controller. | |
| 37 | + * | |
| 38 | + * Menu callbacks must be registered as array($this, 'renderPage') rather than | |
| 39 | + * array(&$this->controller, '_doAction'). $this->controller is still NULL when | |
| 40 | + * add_menu_page()/add_submenu_page() run -- it is only populated later by | |
| 41 | + * getPage() on the load-{$pageHookId} hook. Since WordPress 7.1, | |
| 42 | + * _wp_filter_build_unique_id() returns NULL for a callback whose object is NULL | |
| 43 | + * and WP_Hook::add_filter() silently discards it, so the page hook ends up with | |
| 44 | + * no callbacks and menu-header.php falls back to linking the bare menu slug | |
| 45 | + * (e.g /wp-admin/cjtoolbox instead of /wp-admin/admin.php?page=cjtoolbox). | |
| 46 | + * | |
| 47 | + * @return void | |
| 48 | + */ | |
| 49 | + public function renderPage() { | |
| 50 | + // getPage() runs on load-{$pageHookId}, before the page hook fires. | |
| 51 | + if ($this->controller) { | |
| 52 | + $this->controller->_doAction(); | |
| 53 | + } | |
| 54 | + } | |
| 55 | + | |
| 35 | 56 | } // End class. |
| 36 | 57 | |
| 37 | 58 | // Hookable! |
| 38 | 59 | CJTPageAccessPoint::define('CJTPageAccessPoint', array('hookType' => CJTWordpressEvents::HOOK_FILTER)); |