Admin Page Framework Documentation
  • Package
  • Class
  • Tree

Packages

  • AdminPageFramework
    • FieldType
    • MetaBox
    • NetworkAdmin
      • Page
    • Page
    • PageMetaBox
    • PostType
    • TaxonomyField
  • None

Classes

  • AdminPageFramework
  • AdminPageFramework_Menu
  • AdminPageFramework_Page
  • AdminPageFramework_Setting
  1 <?php
  2 /**
  3  * Admin Page Framework
  4  * 
  5  * http://en.michaeluno.jp/admin-page-framework/
  6  * Copyright (c) 2013-2014 Michael Uno; Licensed MIT
  7  * 
  8  */
  9 if ( ! class_exists( 'AdminPageFramework_Menu' ) ) :
 10 /**
 11  * Provides methods to manipulate menu items.
 12  *
 13  * @abstract
 14  * @since 2.0.0
 15  * @extends AdminPageFramework_Page
 16  * @package AdminPageFramework
 17  * @subpackage Page
 18  * @staticvar array $_aStructure_SubMenuPageForUser represents the structure of the sub-menu page array.
 19  */
 20 abstract class AdminPageFramework_Menu extends AdminPageFramework_Page {
 21     
 22     /**
 23      * Used to refer the built-in root menu slugs.
 24      * 
 25      * @since 2.0.0
 26      * @since 3.1.0 Changed it non-static.
 27      * @remark Not for the user.
 28      * @var array Holds the built-in root menu slugs.
 29      * @internal
 30      */ 
 31     protected $_aBuiltInRootMenuSlugs = array(
 32         // All keys must be lower case to support case insensitive look-ups.
 33         'dashboard' =>             'index.php',
 34         'posts' =>                 'edit.php',
 35         'media' =>                 'upload.php',
 36         'links' =>                 'link-manager.php',
 37         'pages' =>                 'edit.php?post_type=page',
 38         'comments' =>             'edit-comments.php',
 39         'appearance' =>         'themes.php',
 40         'plugins' =>             'plugins.php',
 41         'users' =>                 'users.php',
 42         'tools' =>                 'tools.php',
 43         'settings' =>             'options-general.php',
 44         'network admin' =>         "network_admin_menu",
 45     );     
 46 
 47     /**    
 48      * Represents the structure of the sub-menu link array for the users.
 49      * @since 2.0.0
 50      * @since 2.1.4 Changed to be static since it is used from multiple classes.
 51      * @since 3.0.0 Moved from the link class.
 52      * @remark The scope is public because this is accessed from an extended class.
 53      * @internal
 54      */ 
 55     protected static $_aStructure_SubMenuLinkForUser = array(     
 56         'type' => 'link',    
 57         'title' => null, // required
 58         'href' => null, // required
 59         'capability' => null, // optional
 60         'order' => null, // optional
 61         'show_page_heading_tab' => true,
 62         'show_in_menu' => true,
 63     );
 64         
 65     /**
 66      * Represents the structure of sub-menu page array for the users.
 67      * 
 68      * @since 2.0.0
 69      * @remark Not for the user.
 70      * @var array Holds array structure of sub-menu page.
 71      * @static
 72      * @internal
 73      */ 
 74     protected static $_aStructure_SubMenuPageForUser = array(
 75         'type' => 'page', // this is used to compare with the link type.
 76         'title' => null, 
 77         'page_slug' => null, 
 78         'screen_icon' => null, // this will become either href_icon_32x32 or screen_icon_id
 79         'capability' => null, 
 80         'order' => null,
 81         'show_page_heading_tab' => true, // if this is false, the page title won't be displayed in the page heading tab.
 82         'show_in_menu'                 => true, // if this is false, the menu label will not be displayed in the sidebar menu.     
 83         'href_icon_32x32' => null,
 84         'screen_icon_id' => null,
 85         // 'show_menu' => null, <-- not sure what this was for.
 86         'show_page_title' => null,
 87         'show_page_heading_tabs' => null,
 88         'show_in_page_tabs' => null,
 89         'in_page_tab_tag' => null,
 90         'page_heading_tab_tag' => null,
 91     );
 92          
 93      /**
 94       * Registers necessary callbacks and sets up properties.
 95       * 
 96       * @internal
 97       */
 98     function __construct( $sOptionKey=null, $sCallerPath=null, $sCapability='manage_options', $sTextDomain='admin-page-framework' ) {
 99         
100         parent::__construct( $sOptionKey, $sCallerPath, $sCapability, $sTextDomain );
101         
102         if ( $this->oProp->bIsAdminAjax ) {
103             return;
104         }
105         
106         add_action( 'admin_menu', array( $this, '_replyToBuildMenu' ), 98 );     
107     } 
108      
109     /**
110      * Sets to which top level page is going to be adding sub-pages.
111      * 
112      * <h4>Example</h4>
113      * <code>$this->setRootMenuPage( 'Settings' );
114      * </code>
115      * <code>$this->setRootMenuPage( 
116      *     'APF Form',
117      *     plugins_url( 'image/screen_icon32x32.jpg', __FILE__ )
118      * );</code>
119      * 
120      * @acecss public
121      * @since 2.0.0
122      * @since 2.1.6 The $sIcon16x16 parameter accepts a file path.
123      * @since 3.0.0 The scope was changed to public from protected.
124      * @remark Only one root page can be set per one class instance.
125      * @param string If the method cannot find the passed string from the following listed items, it will create a top level menu item with the passed string. ( case insensitive )
126      * <blockquote>Dashboard, Posts, Media, Links, Pages, Comments, Appearance, Plugins, Users, Tools, Settings, Network Admin</blockquote>
127      * @param string ( optional ) the source of menu icon with either of the following forms:
128      * <ul>
129      *  <li>the URL of the menu icon with the size of 16 by 16 in pixel.</li>
130      *  <li>the file path of the menu icon with the size of 16 by 16 in pixel.</li>
131      *  <li>the name of a Dashicons helper class to use a font icon, e.g. <code>dashicons-editor-customchar</code>.</li>
132      *  <li>the string, 'none', to leave div.wp-menu-image empty so an icon can be added via CSS.</li>
133      *  <li>a base64-encoded SVG using a data URI, which will be colored to match the color scheme. This should begin with 'data:image/svg+xml;base64,'.</li>
134      * </ul>
135      * @param string ( optional ) the position number that is passed to the <var>$position</var> parameter of the <a href="http://codex.wordpress.org/Function_Reference/add_menu_page">add_menu_page()</a> function.
136      * @return void
137      */
138     public function setRootMenuPage( $sRootMenuLabel, $sIcon16x16=null, $iMenuPosition=null ) {
139 
140         $sRootMenuLabel = trim( $sRootMenuLabel );
141         $_sSlug = $this->_isBuiltInMenuItem( $sRootMenuLabel ); // if true, this method returns the slug
142         $this->oProp->aRootMenu = array(
143             'sTitle' => $sRootMenuLabel,
144             'sPageSlug'         => $_sSlug ? $_sSlug : $this->oProp->sClassName,    
145             'sIcon16x16' => $this->oUtil->resolveSRC( $sIcon16x16 ),
146             'iPosition' => $iMenuPosition,
147             'fCreateRoot' => $_sSlug ? false : true,
148         );    
149                     
150     }
151         /**
152          * Checks if a menu item is a WordPress built-in menu item from the given menu label.
153          * 
154          * @since 2.0.0
155          * @internal
156          * @return void|string Returns the associated slug string, if true.
157          */ 
158         private function _isBuiltInMenuItem( $sMenuLabel ) {
159             
160             $sMenuLabelLower = strtolower( $sMenuLabel );
161             if ( array_key_exists( $sMenuLabelLower, $this->_aBuiltInRootMenuSlugs ) )
162                 return $this->_aBuiltInRootMenuSlugs[ $sMenuLabelLower ];
163             
164         }    
165 
166     /**
167      * Sets the top level menu page by page slug.
168      * 
169      * The page should be already created or scheduled to be created separately.
170      * 
171      * <h4>Example</h4>
172      * <code>$this->setRootMenuPageBySlug( 'edit.php?post_type=apf_posts' );
173      * </code>
174      * 
175      * @since 2.0.0
176      * @since 3.0.0 The scope was changed to public from protected.
177      * @access public
178      * @param string The page slug of the top-level root page.
179      * @return void
180      */ 
181     public function setRootMenuPageBySlug( $sRootMenuSlug ) {
182         
183         $this->oProp->aRootMenu['sPageSlug'] = $sRootMenuSlug; // do not sanitize the slug here because post types includes a question mark.
184         $this->oProp->aRootMenu['fCreateRoot'] = false; // indicates to use an existing menu item. 
185         
186     }
187     
188     /**
189     * Adds sub-menu items on the left sidebar menu of the administration panel. 
190     * 
191     * It supports pages and links. Each of them has the specific array structure.
192     * 
193     * <h4>Example</h4>
194     * <code>$this->addSubMenuItems(
195     * array(
196     * 'title' => 'Various Form Fields',
197     * 'page_slug' => 'first_page',
198     * 'screen_icon' => 'options-general',
199     * ),
200     * array(
201     * 'title' => 'Manage Options',
202     * 'page_slug' => 'second_page',
203     * 'screen_icon' => 'link-manager',
204     * ),
205     * array(
206     * 'title' => 'Google',
207     * 'href' => 'http://www.google.com',    
208     * 'show_page_heading_tab' => false, // this removes the title from the page heading tabs.
209     * ),
210     * );</code>
211     * 
212     * @since 2.0.0
213     * @since 3.0.0 Changed the scope to public.
214     * @remark The sub menu page slug should be unique because add_submenu_page() can add one callback per page slug.
215     * @remark Accepts variadic parameters; the number of accepted parameters are not limited to three.
216     * @param array a first sub-menu array. A sub-menu array can be a link or a page. The array structures are as follows:
217     * <h4>Sub-menu Page Array</h4>
218     * <ul>
219     * <li><strong>title</strong> - ( string ) the page title of the page.</li>
220     * <li><strong>page_slug</strong> - ( string ) the page slug of the page. Non-alphabetical characters should not be used including dots(.) and hyphens(-).</li>
221     * <li><strong>screen_icon</strong> - ( optional, string ) either the ID selector name from the following list or the icon URL. The size of the icon should be 32 by 32 in pixel. This is for WordPress 3.7.x or below.
222     * <pre>edit, post, index, media, upload, link-manager, link, link-category, edit-pages, page, edit-comments, themes, plugins, users, profile, user-edit, tools, admin, options-general, ms-admin, generic</pre>
223     * <p>( Notes: the <em>generic</em> icon is available WordPress version 3.5 or above.)</p> 
224     * </li>
225     * <li><strong>capability</strong> - ( optional, string ) the access level to the created admin pages defined <a href="http://codex.wordpress.org/Roles_and_Capabilities">here</a>. If not set, the overall capability assigned in the class constructor, which is *manage_options* by default, will be used.</li>
226     * <li><strong>order</strong> - ( optional, integer ) the order number of the page. The lager the number is, the lower the position it is placed in the menu.</li>
227     * <li><strong>show_page_heading_tab</strong> - ( optional, boolean ) if this is set to false, the page title won't be displayed in the page heading tab. Default: true.</li>
228     * </ul>
229     * <h4>Sub-menu Link Array</h4>
230     * <ul>
231     * <li><strong>title</strong> - ( string ) the link title.</li>
232     * <li><strong>href</strong> - ( string ) the URL of the target link.</li>
233     * <li><strong>capability</strong> - ( optional, string ) the access level to show the item, defined <a href="http://codex.wordpress.org/Roles_and_Capabilities">here</a>. If not set, the overall capability assigned in the class constructor, which is *manage_options* by default, will be used.</li>
234     * <li><strong>order</strong> - ( optional, integer ) the order number of the page. The lager the number is, the lower the position it is placed in the menu.</li>
235     * <li><strong>show_page_heading_tab</strong> - ( optional, boolean ) if this is set to false, the page title won't be displayed in the page heading tab. Default: true.</li>
236     * </ul>
237     * @param array ( optional ) a second sub-menu array.
238     * @param array ( optional ) a third and add items as many as necessary with next parameters.
239     * @access             public
240     * @return void
241     */     
242     public function addSubMenuItems( $aSubMenuItem1, $aSubMenuItem2=null, $_and_more=null ) {
243         foreach ( func_get_args() as $aSubMenuItem ) 
244             $this->addSubMenuItem( $aSubMenuItem );     
245     }
246     
247     /**
248     * Adds the given sub-menu item on the left sidebar menu of the administration panel.
249     * 
250     * It supports pages and links. Each of them has the specific array structure.
251     * 
252     * @since 2.0.0
253     * @since 3.0.0 Changed the scope to public.
254     * @remark The sub menu page slug should be unique because add_submenu_page() can add one callback per page slug.
255     * @param array a sub-menu array. It can be a page or a link. The array structures are as follows:
256     * <h4>Sub-menu Page Array</h4>
257     * <ul>
258     * <li><strong>title</strong> - ( string ) the page title of the page.</li>
259     * <li><strong>page_slug</strong> - ( string ) the page slug of the page. Non-alphabetical characters should not be used including dots(.) and hyphens(-).</li>
260     * <li><strong>screen_icon</strong> - ( optional, string ) either the ID selector name from the following list or the icon URL. The size of the icon should be 32 by 32 in pixel. This is for WordPress 3.7.x or below.
261     * <pre>edit, post, index, media, upload, link-manager, link, link-category, edit-pages, page, edit-comments, themes, plugins, users, profile, user-edit, tools, admin, options-general, ms-admin, generic</pre>
262     * <p>( Notes: the <em>generic</em> icon is available WordPress version 3.5 or above.)</p> 
263     * </li>
264     * <li><strong>capability</strong> - ( optional, string ) the access level to the created admin pages defined <a href="http://codex.wordpress.org/Roles_and_Capabilities">here</a>. If not set, the overall capability assigned in the class constructor, which is *manage_options* by default, will be used.</li>
265     * <li><strong>order</strong> - ( optional, integer ) the order number of the page. The lager the number is, the lower the position it is placed in the menu.</li>
266     * <li><strong>show_page_heading_tab</strong> - ( optional, boolean ) if this is set to false, the page title won't be displayed in the page heading tab. Default: true.</li>
267     * </ul>
268     * <h4>Sub-menu Link Array</h4>
269     * <ul>
270     * <li><strong>title</strong> - ( string ) the link title.</li>
271     * <li><strong>href</strong> - ( string ) the URL of the target link.</li>
272     * <li><strong>capability</strong> - ( optional, string ) the access level to show the item, defined <a href="http://codex.wordpress.org/Roles_and_Capabilities">here</a>. If not set, the overall capability assigned in the class constructor, which is *manage_options* by default, will be used.</li>
273     * <li><strong>order</strong> - ( optional, integer ) the order number of the page. The lager the number is, the lower the position it is placed in the menu.</li>
274     * <li><strong>show_page_heading_tab</strong> - ( optional, boolean ) if this is set to false, the page title won't be displayed in the page heading tab. Default: true.</li>
275     * </ul>
276     * @access             public
277     * @return void
278     */    
279     public function addSubMenuItem( array $aSubMenuItem ) {
280         if ( isset( $aSubMenuItem['href'] ) ) 
281             $this->addSubMenuLink( $aSubMenuItem );
282         else 
283             $this->addSubMenuPage( $aSubMenuItem );
284     }
285 
286     /**
287     * Adds the given link into the menu on the left sidebar of the administration panel.
288     * 
289     * @since 2.0.0
290     * @since 3.0.0 Changed the scope to public from protected.
291     * @param string     the menu title.
292     * @param string     the URL linked to the menu.
293     * @param string ( optional ) the <a href="http://codex.wordpress.org/Roles_and_Capabilities" target="_blank">access level</a>.
294     * @param string ( optional ) the order number. The larger it is, the lower the position it gets.
295     * @param string ( optional ) if set to false, the menu title will not be listed in the tab navigation menu at the top of the page.
296     * @access             protected
297     * @return void
298     * @internal
299     */    
300     protected function addSubMenuLink( array $aSubMenuLink ) {
301         
302         // If required keys are not set, return.
303         if ( ! isset( $aSubMenuLink['href'], $aSubMenuLink['title'] ) ) return;
304         
305         // If the set URL is not valid, return.
306         if ( ! filter_var( $aSubMenuLink['href'], FILTER_VALIDATE_URL ) ) return;
307 
308         $this->oProp->aPages[ $aSubMenuLink['href'] ] = $this->_formatSubmenuLinkArray( $aSubMenuLink );
309             
310     }    
311     
312     /**
313      * Adds sub-menu pages.
314      * 
315      * It is recommended to use addSubMenuItems() instead, which supports external links.
316      * 
317      * @since 2.0.0
318      * @since 3.0.0 The scope was changed to public from protected.
319      * @internal
320      * @return void
321      * @remark The sub menu page slug should be unique because add_submenu_page() can add one callback per page slug.
322      */ 
323     protected function addSubMenuPages() {
324         foreach ( func_get_args() as $aSubMenuPage ) 
325             $this->addSubMenuPage( $aSubMenuPage );
326     }
327     
328     /**
329      * Adds a single sub-menu page.
330      * 
331      * <h4>Example</h4>
332      * <code>
333         $this->addSubMenuPage(
334             array(
335                 'title' => __( 'First Page', 'admin-page-framework-demo' ),
336                 'page_slug' => 'apf_first_page',
337             ),
338             array(
339                 'title' => __( 'Second Page', 'admin-page-framework-demo' ),
340                 'page_slug' => 'apf_second_page',
341             )
342         );</code>
343      * 
344      * 
345      * @access public
346      * @since 2.0.0
347      * @since 2.1.2 A key name was changed.
348      * @since 2.1.6 $sScreenIcon accepts a file path.
349      * @since 3.0.0 The scope was changed to public from protected. Deprecated all the parameters made it to accept them as an array. A key name was changed.
350      * @remark The sub menu page slug should be unique because add_submenu_page() can add one callback per page slug.
351      * @param array The sub menu page array.
352      * <h4>Sub Menu Page Array</h4>
353      * <ul>
354      *     <li>title - ( required ) the title of the page.</li>
355      *     <li>page_slug - ( required ) the slug of the page. Do not use hyphens as it serves as the callback method name.</li>
356      *     <li>screen icon - ( optional ) Either a screen icon ID, a url of the icon, or a file path to the icon, with the size of 32 by 32 in pixel. The accepted icon IDs are as follows.</li>
357      * <blockquote>edit, post, index, media, upload, link-manager, link, link-category, edit-pages, page, edit-comments, themes, plugins, users, profile, user-edit, tools, admin, options-general, ms-admin, generic</blockquote>
358      * ( Note: the <em>generic</em> ID is available since WordPress 3.5. )
359      *     <li>capability - ( optional ) The <a href="http://codex.wordpress.org/Roles_and_Capabilities">access level</a> to the page.</li>
360      *     <li>order - ( optional ) the order number of the page. The lager the number is, the lower the position it is placed in the menu.</li>
361      *     <li>show_page_heading_tab - ( optional ) If this is set to false, the page title won't be displayed in the page heading tab. Default: true.</li>
362      *     <li>show_in_menu - ( optional ) If this is set to false, the page title won't be displayed in the sidebar menu while the page is still accessible. Default: true.</li>
363      * </ul>
364      * @return void
365      * @internal
366      */ 
367     protected function addSubMenuPage( array $aSubMenuPage ) {
368 
369         if ( ! isset( $aSubMenuPage['page_slug'] ) ) return;
370             
371         $aSubMenuPage['page_slug'] = $this->oUtil->sanitizeSlug( $aSubMenuPage['page_slug'] );
372         $this->oProp->aPages[ $aSubMenuPage['page_slug'] ] = $this->_formatSubMenuPageArray( $aSubMenuPage );
373         
374     }
375                     
376     /**
377      * Builds the sidebar menu of the added pages.
378      * 
379      * @since 2.0.0
380      * @internal
381      */
382     public function _replyToBuildMenu() {
383 
384         // If the root menu label is not set but the slug is set, 
385         if ( $this->oProp->aRootMenu['fCreateRoot'] ) {
386             $this->_registerRootMenuPage();
387         }
388         
389         // Apply filters to let other scripts add sub menu pages.
390         $this->oProp->aPages = $this->oUtil->addAndApplyFilter( // Parameters: $oCallerObject, $sFilter, $vInput, $vArgs...
391             $this,
392             "pages_{$this->oProp->sClassName}", 
393             $this->oProp->aPages
394         );
395         
396         // Sort the page array.
397         uasort( $this->oProp->aPages, array( $this, '_sortByOrder' ) ); 
398         
399         // Set the default page, the first element.
400         foreach ( $this->oProp->aPages as $aPage ) {
401             
402             if ( ! isset( $aPage['page_slug'] ) ) continue;
403             $this->oProp->sDefaultPageSlug = $aPage['page_slug'];
404             break;
405             
406         }
407         
408         // Register them.
409         foreach ( $this->oProp->aPages as &$aSubMenuItem ) {
410             $aSubMenuItem = $this->_formatSubMenuItemArray( $aSubMenuItem ); // needs to be sanitized because there are hook filters applied to this array.
411             $aSubMenuItem['_page_hook'] = $this->_registerSubMenuItem( $aSubMenuItem ); // store the page hook; this is same as the value stored in the global $page_hook or $hook_suffix variable. 
412         }
413 
414         // After adding the sub menus, if the root menu is created, remove the page that is automatically created when registering the root menu.
415         if ( $this->oProp->aRootMenu['fCreateRoot'] ) {
416             remove_submenu_page( $this->oProp->aRootMenu['sPageSlug'], $this->oProp->aRootMenu['sPageSlug'] );
417         }
418 
419         $this->oProp->_bBuiltMenu = true;
420         
421     }    
422         
423         /**
424          * Registers the root menu page.
425          * 
426          * @since 2.0.0
427          * @internal
428          */ 
429         private function _registerRootMenuPage() {
430             $this->oProp->aRootMenu['_page_hook'] = add_menu_page(  
431                 $this->oProp->sClassName, // Page title - will be invisible anyway
432                 $this->oProp->aRootMenu['sTitle'], // Menu title - should be the root page title.
433                 $this->oProp->sCapability, // Capability - access right
434                 $this->oProp->aRootMenu['sPageSlug'], // Menu ID 
435                 '', //array( $this, $this->oProp->sClassName ),     // Page content displaying function - the root page will be removed so no need to register a function.
436                 $this->oProp->aRootMenu['sIcon16x16'], // icon path
437                 isset( $this->oProp->aRootMenu['iPosition'] ) ? $this->oProp->aRootMenu['iPosition'] : null // menu position
438             );
439         }
440         
441         /**
442          * Formats the sub-menu item arrays.
443          * @since 3.0.0
444          * @internal
445          */
446         private function _formatSubMenuItemArray( $aSubMenuItem ) {
447             
448             if ( isset( $aSubMenuItem['page_slug'] ) )
449                 return $this->_formatSubMenuPageArray( $aSubMenuItem );
450                 
451             if ( isset( $aSubMenuItem['href'] ) )
452                 return $this->_formatSubmenuLinkArray( $aSubMenuItem ); 
453                 
454             return array();
455             
456         }
457         
458         /**
459          * Formats the given sub-menu link array.
460          * @since 3.0.0
461          * @internal
462          */
463         private function _formatSubmenuLinkArray( $aSubMenuLink ) {
464             
465             // If the set URL is not valid, return.
466             if ( ! filter_var( $aSubMenuLink['href'], FILTER_VALIDATE_URL ) ) return array();
467             
468             return $this->oUtil->uniteArrays(     
469                 array(  
470                     'capability' => isset( $aSubMenuLink['capability'] ) ? $aSubMenuLink['capability'] : $this->oProp->sCapability,
471                     'order' => isset( $aSubMenuLink['order'] ) && is_numeric( $aSubMenuLink['order'] ) ? $aSubMenuLink['order'] : count( $this->oProp->aPages ) + 10,
472                 ),
473                 $aSubMenuLink + self::$_aStructure_SubMenuLinkForUser
474             );     
475             
476         }
477         /**
478          * Formats the given sub-menu page array.
479          * @since 3.0.0
480          * @internal
481          */
482         private function _formatSubMenuPageArray( $aSubMenuPage ) {
483             
484             $aSubMenuPage = $aSubMenuPage + self::$_aStructure_SubMenuPageForUser;
485 
486             $aSubMenuPage['screen_icon_id'] = trim( $aSubMenuPage['screen_icon_id'] );     
487             return $this->oUtil->uniteArrays(
488                 array( 
489                     'href_icon_32x32' => $this->oUtil->resolveSRC( $aSubMenuPage['screen_icon'], true ),
490                     'screen_icon_id' => in_array( $aSubMenuPage['screen_icon'], self::$_aScreenIconIDs ) ? $aSubMenuPage['screen_icon'] : 'generic', // $_aScreenIconIDs is defined in the page class.
491                     'capability' => isset( $aSubMenuPage['capability'] ) ? $aSubMenuPage['capability'] : $this->oProp->sCapability,
492                     'order' => is_numeric( $aSubMenuPage['order'] ) ? $aSubMenuPage['order'] : count( $this->oProp->aPages ) + 10,
493                 ),
494                 $aSubMenuPage,
495                 array(
496                     'show_page_title' => $this->oProp->bShowPageTitle, // boolean
497                     'show_page_heading_tabs' => $this->oProp->bShowPageHeadingTabs, // boolean
498                     'show_in_page_tabs' => $this->oProp->bShowInPageTabs, // boolean
499                     'in_page_tab_tag' => $this->oProp->sInPageTabTag, // string
500                     'page_heading_tab_tag' => $this->oProp->sPageHeadingTabTag, // string
501                 )
502             );     
503             
504         }
505         
506         /**
507          * Registers the sub-menu item.
508          * 
509          * @since 2.0.0
510          * @since 3.0.0 Changed the name from registerSubMenuPage().
511          * @remark Used in the buildMenu() method. 
512          * @remark Within the <em>admin_menu</em> hook callback process.
513          * @remark The sub menu page slug should be unique because add_submenu_page() can add one callback per page slug.
514          * @internal
515          */ 
516         private function _registerSubMenuItem( $aArgs ) {
517 
518             if ( ! isset( $aArgs['type'] ) ) return;
519 
520             // Variables
521             $sType = $aArgs['type']; // page or link
522             $sTitle = $sType == 'page' ? $aArgs['title'] : $aArgs['title'];
523             $sCapability = isset( $aArgs['capability'] ) ? $aArgs['capability'] : $this->oProp->sCapability;
524             $_sPageHook = '';
525 
526             // Check the capability
527             if ( ! current_user_can( $sCapability ) ) {     
528                 return;     
529             }
530             
531             // Add the sub-page to the sub-menu     
532             $sRootPageSlug = $this->oProp->aRootMenu['sPageSlug'];
533             $sMenuLabel = plugin_basename( $sRootPageSlug ); // Make it compatible with the add_submenu_page() function.
534             
535             // If it's a page - it's possible that the page_slug key is not set if the user uses a method like setPageHeadingTabsVisibility() prior to addSubMenuItam().
536             if ( $sType == 'page' && isset( $aArgs['page_slug'] ) ) {     
537                 
538                 $sPageSlug = $aArgs['page_slug'];
539                 $_sPageHook = add_submenu_page( 
540                     $sRootPageSlug, // the root(parent) page slug
541                     $sTitle, // page_title
542                     $sTitle, // menu_title
543                     $sCapability,              // capability
544                     $sPageSlug, // menu_slug
545                     // In admin.php ( line 149 of WordPress v3.6.1 ), do_action($page_hook) ( where $page_hook is $_sPageHook )
546                     // will be executed and it triggers the __call() magic method with the method name of "md5 class hash + _page_ + this page slug".
547                     array( $this, $this->oProp->sClassHash . '_page_' . $sPageSlug )
548                 );     
549                 
550                 // Ensure only it is added one time per page slug.
551                 if ( ! isset( $this->oProp->aPageHooks[ $_sPageHook ] ) ) {
552                     add_action( 'current_screen' , array( $this, "load_pre_" . $sPageSlug ) );    
553                 }
554                 $this->oProp->aPageHooks[ $sPageSlug ] = is_network_admin() ? $_sPageHook . '-network' : $_sPageHook;
555 
556                 // If the visibility option is false, remove the one just added from the sub-menu array
557                 if ( ! $aArgs['show_in_menu'] ) {
558 
559                     foreach( ( array ) $GLOBALS['submenu'][ $sMenuLabel ] as $iIndex => $aSubMenu ) {
560                         
561                         if ( ! isset( $aSubMenu[ 3 ] ) ) continue;
562                         
563                         // the array structure is defined in plugin.php - $submenu[$parent_slug][] = array ( $menu_title, $capability, $menu_slug, $page_title ) 
564                         if ( $aSubMenu[0] == $sTitle && $aSubMenu[3] == $sTitle && $aSubMenu[2] == $sPageSlug ) {
565 
566                             // Remove from the menu. If the current page is being accessed, do not remove it from the menu.
567                             // If it is in the network admin area, do not remove the menu; otherwise, it gets not accessible. 
568                             if ( is_network_admin() ) {
569                                 unset( $GLOBALS['submenu'][ $sMenuLabel ][ $iIndex ] );
570                             } else if ( ! isset( $_GET['page'] ) || isset( $_GET['page'] ) && $sPageSlug != $_GET['page'] ) {
571                                 unset( $GLOBALS['submenu'][ $sMenuLabel ][ $iIndex ] );
572                             }
573 
574                             // The page title in the browser window title bar will miss the page title as this is left as it is.
575                             $this->oProp->aHiddenPages[ $sPageSlug ] = $sTitle;
576                             add_filter( 'admin_title', array( $this, '_replyToFixPageTitleForHiddenPages' ), 10, 2 );
577                             
578                             break;
579                         }
580                     }
581                 } 
582                     
583             } 
584             // If it's a link,
585             if ( $sType == 'link' && $aArgs['show_in_menu'] ) {
586                 
587                 if ( ! isset( $GLOBALS['submenu'][ $sMenuLabel ] ) )
588                     $GLOBALS['submenu'][ $sMenuLabel ] = array();
589                 
590                 $GLOBALS['submenu'][ $sMenuLabel ][] = array ( 
591                     $sTitle, 
592                     $sCapability, 
593                     $aArgs['href'],
594                 );    
595             }
596         
597             return $_sPageHook; // will be stored in the $this->oProp->aPages property.
598 
599         }     
600         
601         /**
602          * A callback function for the admin_title filter to fix the page title for hidden pages.
603          * @since 2.1.4
604          * @internal
605          */
606         public function _replyToFixPageTitleForHiddenPages( $sAdminTitle, $sPageTitle ) {
607 
608             if ( isset( $_GET['page'], $this->oProp->aHiddenPages[ $_GET['page'] ] ) )
609                 return $this->oProp->aHiddenPages[ $_GET['page'] ] . $sAdminTitle;
610                 
611             return $sAdminTitle;
612             
613         }     
614 }
615 endif;
Admin Page Framework Documentation API documentation generated by ApiGen 2.8.0