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_Page' ) ) :
 10 /**
 11  * Provides methods to render admin page elements.
 12  *
 13  * @abstract
 14  * @extends AdminPageFramework_Page_MetaBox
 15  * @since 2.0.0
 16  * @since 2.1.0 Extends AdminPageFramework_HelpPane_Page.
 17  * @since 3.0.0 No longer extends AdminPageFramework_HelpPane_Page.
 18  * @package AdminPageFramework
 19  * @subpackage Page
 20  * @staticvar array $_aScreenIconIDs stores the ID selector names for screen icons.
 21  * @staticvar array $_aHookPrefixes stores the prefix strings for filter and action hooks.
 22  * @staticvar array $_aStructure_InPageTabElements represents the array structure of an in-page tab array.
 23  */
 24 abstract class AdminPageFramework_Page extends AdminPageFramework_Page_MetaBox {
 25                 
 26     /**
 27      * Stores the ID selector names for screen icons. <em>generic</em> is not available in WordPress v3.4.x.
 28      * 
 29      * @since 2.0.0
 30      * @var array
 31      * @static
 32      * @access protected
 33      * @internal
 34      */     
 35     protected static $_aScreenIconIDs = array(
 36         'edit', 'post', 'index', 'media', 'upload', 'link-manager', 'link', 'link-category', 
 37         'edit-pages', 'page', 'edit-comments', 'themes', 'plugins', 'users', 'profile', 
 38         'user-edit', 'tools', 'admin', 'options-general', 'ms-admin', 'generic',
 39     );    
 40 
 41     /**
 42      * Represents the array structure of an in-page tab array.
 43      * 
 44      * @since 2.0.0
 45      * @var array
 46      * @static
 47      * @access private
 48      * @internal
 49      */     
 50     private static $_aStructure_InPageTabElements = array(
 51         'page_slug' => null,
 52         'tab_slug' => null,
 53         'title' => null,
 54         'order' => null,
 55         'show_in_page_tab' => true,
 56         'parent_tab_slug' => null, // this needs to be set if the above show_in_page_tab is false so that the framework can mark the parent tab to be active when the hidden page is accessed.
 57     );
 58         
 59     /**
 60      * Registers necessary hooks and sets up properties.
 61      * 
 62      * @internal
 63      */
 64     function __construct( $sOptionKey=null, $sCallerPath=null, $sCapability='manage_options', $sTextDomain='admin-page-framework' ) {    
 65     
 66         parent::__construct( $sOptionKey, $sCallerPath, $sCapability, $sTextDomain );
 67         
 68         if ( $this->oProp->bIsAdminAjax ) {
 69             return;
 70         }     
 71         add_action( "load_after_{$this->oProp->sClassName}", array( $this, '_replyToFinalizeInPageTabs' ), 19 ); // must be called before the _replyToRegisterSettings() method 
 72                 
 73     }
 74     
 75     /**
 76      * Adds in-page tabs.
 77      *
 78      * The parameters accept in-page tab arrays and they must have the following array keys.
 79      * 
 80      * <h4>Example</h4>
 81      * <code>$this->addInPageTabs(
 82      * array(
 83      * 'page_slug' => 'myfirstpage'
 84      * 'tab_slug' => 'firsttab',
 85      * 'title' => __( 'Text Fields', 'my-text-domain' ),
 86      * ),
 87      * array(
 88      * 'page_slug' => 'myfirstpage'
 89      * 'tab_slug' => 'secondtab',
 90      * 'title' => __( 'Selectors and Checkboxes', 'my-text-domain' ),
 91      * )
 92      * );</code>
 93      *
 94      * <code>$this->addInPageTabs(
 95      * 'myfirstpage', // sets the target page slug
 96      * array(
 97      * 'tab_slug' => 'firsttab',
 98      * 'title' => __( 'Text Fields', 'my-text-domain' ),
 99      * ),
100      * array(
101      * 'tab_slug' => 'secondtab',
102      * 'title' => __( 'Selectors and Checkboxes', 'my-text-domain' ),
103      * )
104      * );</code>
105      * @since 2.0.0
106      * @since 3.0.0 Changed the scope to public. Added page slug target support. 
107      * @param array $aTab1 The in-page tab array.
108      * <h4>In-Page Tab Array</h4>
109      * <ul>
110      *     <li><strong>page_slug</strong> - ( string ) the page slug that the tab belongs to.</li>
111      *     <li><strong>tab_slug</strong> -  ( string ) the tab slug. Non-alphabetical characters should not be used including dots(.) and hyphens(-).</li>
112      *     <li><strong>title</strong> - ( string ) the title of the tab.</li>
113      *     <li><strong>order</strong> - ( optional, integer ) the order number of the tab. The lager the number is, the lower the position it is placed in the menu.</li>
114      *     <li><strong>show_in_page_tab</strong> - ( optional, boolean ) default: false. If this is set to false, the tab title will not be displayed in the tab navigation menu; however, it is still accessible from the direct URL.</li>
115      *     <li><strong>parent_tab_slug</strong> - ( optional, string ) this needs to be set if the above show_in_page_tab is true so that the parent tab will be emphasized as active when the hidden page is accessed.</li>
116      * </ul>
117      * @param array $aTab2 Another in-page tab array.
118      * @param array $_and_more Add in-page tab arrays as many as necessary to the next parameters.
119      * @param string (optional) $sPageSlug If the passed parameter item is a string, it will be stored as the target page slug so that it will be applied to the next passed tab arrays as the page_slug element.
120      * @remark Accepts variadic parameters; the number of accepted parameters are not limited to three.
121      * @remark In-page tabs are different from page-heading tabs which is automatically added with page titles.  
122      * @return void
123      */             
124     public function addInPageTabs( $aTab1, $aTab2=null, $_and_more=null ) {
125         foreach( func_get_args() as $asTab ) $this->addInPageTab( $asTab );
126     }
127     
128     /**
129      * Adds an in-page tab.
130      * 
131      * The singular form of the addInPageTabs() method, which takes only one parameter.
132      * 
133      * @since 2.0.0
134      * @since 3.0.0 Changed the scope to public.
135      * @param array|string $asInPageTab The in-page tab array or the target page slug. If the target page slug is set, the page_slug key can be omitted from next calls.
136      * @remark Use this method to add in-page tabs to ensure the array holds all the necessary keys.
137      * @remark In-page tabs are different from page-heading tabs which are automatically added with page titles.
138      * @return void
139      */         
140     public function addInPageTab( $asInPageTab ) {    
141         
142         static $__sTargetPageSlug; // stores the target page slug which will be applied when no page slug is specified.
143         if ( ! is_array( $asInPageTab ) ) {
144             $__sTargetPageSlug = is_string( $asInPageTab ) ? $asInPageTab : $__sTargetPageSlug; // set the target page slug
145             return;
146         }         
147         
148         $aInPageTab = $this->oUtil->uniteArrays( $asInPageTab, self::$_aStructure_InPageTabElements, array( 'page_slug' => $__sTargetPageSlug ) ); // avoid undefined index warnings.     
149         $__sTargetPageSlug = $aInPageTab['page_slug']; // set the target page slug for next calls
150         if ( ! isset( $aInPageTab['page_slug'], $aInPageTab['tab_slug'] ) ) return; // check the required keys.
151         
152         $iCountElement = isset( $this->oProp->aInPageTabs[ $aInPageTab['page_slug'] ] ) ? count( $this->oProp->aInPageTabs[ $aInPageTab['page_slug'] ] ) : 0;
153         $aInPageTab = array( // sanitize some elements
154             'page_slug' => $this->oUtil->sanitizeSlug( $aInPageTab['page_slug'] ),
155             'tab_slug' => $this->oUtil->sanitizeSlug( $aInPageTab['tab_slug'] ),
156             'order' => is_numeric( $aInPageTab['order'] ) ? $aInPageTab['order'] : $iCountElement + 10,
157         ) + $aInPageTab;
158 
159         $this->oProp->aInPageTabs[ $aInPageTab['page_slug'] ][ $aInPageTab['tab_slug'] ] = $aInPageTab;
160     
161     }     
162     
163     /**
164      * Sets whether the page title is displayed or not.
165      * 
166      * <h4>Example</h4>
167      * <code>$this->setPageTitleVisibility( false );    // disables the page title.
168      * </code>
169      * 
170      * @since 2.0.0
171      * @since 3.0.0 Changed the scope to public.
172      * @param boolean $bShow If false, the page title will not be displayed.
173      * @return void
174      */ 
175     public function setPageTitleVisibility( $bShow=true, $sPageSlug='' ) {
176         
177         $sPageSlug = $this->oUtil->sanitizeSlug( $sPageSlug );
178         if ( $sPageSlug ) {
179             $this->oProp->aPages[ $sPageSlug ]['show_page_title'] = $bShow;
180             return;
181         }
182         $this->oProp->bShowPageTitle = $bShow;
183         foreach( $this->oProp->aPages as &$aPage ) 
184             $aPage['show_page_title'] = $bShow;
185         
186     }    
187     
188     /**
189      * Sets whether page-heading tabs are displayed or not.
190      * 
191      * <h4>Example</h4>
192      * <code>$this->setPageHeadingTabsVisibility( false );    // disables the page heading tabs by passing false.
193      * </code>
194      * 
195      * @since 2.0.0
196      * @since 3.0.0 Changed the scope to public.
197      * @param boolean $bShow If false, page-heading tabs will be disabled; otherwise, enabled.
198      * @param string $sPageSlug The page to apply the visibility setting. If not set, it applies to all the pages.
199      * @remark Page-heading tabs and in-page tabs are different. The former displays page titles and the latter displays tab titles.
200      * @remark If the second parameter is omitted, it sets the default value.
201      */ 
202     public function setPageHeadingTabsVisibility( $bShow=true, $sPageSlug='' ) {
203         
204         $sPageSlug = $this->oUtil->sanitizeSlug( $sPageSlug );
205         if ( $sPageSlug ) {
206             $this->oProp->aPages[ $sPageSlug ]['show_page_heading_tabs'] = $bShow;
207             return;     
208         }     
209         $this->oProp->bShowPageHeadingTabs = $bShow;
210         foreach( $this->oProp->aPages as &$aPage ) 
211             $aPage['show_page_heading_tabs'] = $bShow;
212         
213     }
214     
215     /**
216      * Sets whether in-page tabs are displayed or not.
217      * 
218      * Sometimes, it is required to disable in-page tabs in certain pages. In that case, use the second parameter.
219      * 
220      * @since 2.1.1
221      * @since 3.0.0 Changed the scope to public. Changed the name from showInPageTabs() to setInPageTabsVisibility().
222      * @param boolean $bShow If false, in-page tabs will be disabled.
223      * @param string $sPageSlug The page to apply the visibility setting. If not set, it applies to all the pages.
224      * @remark If the second parameter is omitted, it sets the default value.
225      */
226     public function setInPageTabsVisibility( $bShow=true, $sPageSlug='' ) {
227         
228         $sPageSlug = $this->oUtil->sanitizeSlug( $sPageSlug );
229         if ( $sPageSlug ) {
230             $this->oProp->aPages[ $sPageSlug ]['show_in_page_tabs'] = $bShow;
231             return;
232         }
233         $this->oProp->bShowInPageTabs = $bShow;
234         foreach( $this->oProp->aPages as &$aPage )
235             $aPage['show_in_page_tabs'] = $bShow;
236         
237     }
238     
239     /**
240      * Sets in-page tab's HTML tag.
241      * 
242      * <h4>Example</h4>
243      * <code>$this->setInPageTabTag( 'h2' );
244      * </code>
245      * 
246      * @since 2.0.0
247      * @since 3.0.0 Changed the scope to public.
248      * @param string $sTag The HTML tag that encloses each in-page tab title. Default: h3.
249      * @param string $sPageSlug The page slug that applies the setting.    
250      * @remark If the second parameter is omitted, it sets the default value.
251      */     
252     public function setInPageTabTag( $sTag='h3', $sPageSlug='' ) {
253         
254         $sPageSlug = $this->oUtil->sanitizeSlug( $sPageSlug );
255         if ( $sPageSlug ) {
256             $this->oProp->aPages[ $sPageSlug ]['in_page_tab_tag'] = $sTag;
257             return;
258         }
259         $this->oProp->sInPageTabTag = $sTag;
260         foreach( $this->oProp->aPages as &$aPage )
261             $aPage['in_page_tab_tag'] = $sTag;
262         
263     }
264     
265     /**
266      * Sets page-heading tab's HTML tag.
267      * 
268      * <h4>Example</h4>
269      * <code>$this->setPageHeadingTabTag( 'h2' );
270      * </code>
271      * 
272      * @since 2.1.2
273      * @since 3.0.0 Changed the scope to public.
274      * @param string $sTag The HTML tag that encloses the page-heading tab title. Default: h2.
275      * @param string $sPageSlug The page slug that applies the setting.    
276      * @remark If the second parameter is omitted, it sets the default value.
277      */
278     public function setPageHeadingTabTag( $sTag='h2', $sPageSlug='' ) {
279         
280         $sPageSlug = $this->oUtil->sanitizeSlug( $sPageSlug );
281         if ( $sPageSlug ) {
282             $this->oProp->aPages[ $sPageSlug ]['page_heading_tab_tag'] = $sTag;
283             return;
284         }
285         $this->oProp->sPageHeadingTabTag = $sTag;
286         foreach( $this->oProp->aPages as &$aPage )
287             $aPage[ $sPageSlug ]['page_heading_tab_tag'] = $sTag;
288         
289     }
290     
291     /*
292      * Internal Methods
293      */
294     
295     /**
296      * Renders the admin page.
297      * 
298      * @remark This is not intended for the users to use.
299      * @since 2.0.0
300      * @access protected
301      * @return void
302      * @internal
303      */ 
304     protected function _renderPage( $sPageSlug, $sTabSlug=null ) {
305 
306         // Do actions before rendering the page. In this order, global -> page -> in-page tab
307         $this->oUtil->addAndDoActions( 
308             $this,     // the caller object
309             $this->oUtil->getFilterArrayByPrefix( 'do_before_', $this->oProp->sClassName, $sPageSlug, $sTabSlug, true ), // the action hooks
310             $this // the argument 1
311         );
312         ?>
313         <div class="wrap">
314             <?php
315                 // Screen icon, page heading tabs(page title), and in-page tabs.
316                 $sContentTop = $this->_getScreenIcon( $sPageSlug );    
317                 $sContentTop .= $this->_getPageHeadingTabs( $sPageSlug, $this->oProp->sPageHeadingTabTag );
318                 $sContentTop .= $this->_getInPageTabs( $sPageSlug, $this->oProp->sInPageTabTag );
319 
320                 // Apply filters in this order, in-page tab -> page -> global.
321                 echo $this->oUtil->addAndApplyFilters( $this, $this->oUtil->getFilterArrayByPrefix( 'content_foot_', $this->oProp->sClassName, $sPageSlug, $sTabSlug, false ), $sContentTop );
322 
323             ?>
324             <div class="admin-page-framework-container">    
325                 <?php
326                     $this->oUtil->addAndDoActions( 
327                         $this, // the caller object
328                         $this->oUtil->getFilterArrayByPrefix( 'do_form_', $this->oProp->sClassName, $sPageSlug, $sTabSlug, true ), // the action hooks
329                         $this // the argument 1
330                     );
331                     $this->_printFormOpeningTag( $this->oProp->bEnableForm ); // <form ... >
332                 ?>
333                 <div id="poststuff">
334                     <div id="post-body" class="metabox-holder columns-<?php echo $this->_getNumberOfColumns(); ?>">
335                     <?php
336                         $this->_printMainContent( $sPageSlug, $sTabSlug );
337                         $this->_printMetaBox( 'side', 1 ); // defined in the parrent class.
338                         $this->_printMetaBox( 'normal', 2 );
339                         $this->_printMetaBox( 'advanced', 3 );
340                     ?>     
341                     </div><!-- #post-body -->    
342                 </div><!-- #poststuff -->
343                 
344             <?php echo $this->_printFormClosingTag( $sPageSlug, $sTabSlug, $this->oProp->bEnableForm );  // </form> ?>
345             </div><!-- .admin-page-framework-container -->
346                 
347             <?php    
348                 // Apply the content_bottom filters.
349                 echo $this->oUtil->addAndApplyFilters( $this, $this->oUtil->getFilterArrayByPrefix( 'content_bottom_', $this->oProp->sClassName, $sPageSlug, $sTabSlug, false ), '' ); // empty string
350             ?>
351         </div><!-- .wrap -->
352         <?php
353         // Do actions after rendering the page.
354         $this->oUtil->addAndDoActions( 
355             $this, // the caller object
356             $this->oUtil->getFilterArrayByPrefix( 'do_after_', $this->oProp->sClassName, $sPageSlug, $sTabSlug, true ), // the action hooks
357             $this // the argument 1
358         );
359         
360     }
361 
362         /**
363          * Renders the main content of the admin page.
364          * @since 3.0.0
365          */
366         private function _printMainContent( $sPageSlug, $sTabSlug ) {
367             
368             /* Check if a sidebar meta box is registered */
369             $_bIsSideMetaboxExist = ( isset( $GLOBALS['wp_meta_boxes'][ $GLOBALS['page_hook'] ][ 'side' ] ) && count( $GLOBALS['wp_meta_boxes'][ $GLOBALS['page_hook'] ][ 'side' ] ) > 0 );
370 
371             echo "<!-- main admin page content -->";
372             echo "<div class='admin-page-framework-content'>";
373             if ( $_bIsSideMetaboxExist ) {
374                 echo "<div id='post-body-content'>";
375             }
376     
377             /* Capture the output buffer */
378             ob_start(); // start buffer
379                                         
380             // Render the form elements.
381             if ( $this->oProp->bEnableForm ) {
382                 
383                 // do_settings_sections( $sPageSlug ); // deprecated     
384                 if ( $this->oForm->isPageAdded( $sPageSlug ) ) {
385 
386                     $this->aFieldErrors = isset( $this->aFieldErrors ) ? $this->aFieldErrors : $this->_getFieldErrors( $sPageSlug ); 
387                     $oFieldsTable = new AdminPageFramework_FormTable( $this->oProp->aFieldTypeDefinitions, $this->aFieldErrors, $this->oMsg );
388                     $this->oForm->setCurrentPageSlug( $sPageSlug );
389                     $this->oForm->setCurrentTabSlug( $sTabSlug );
390                     $this->oForm->applyConditions();
391                     $this->oForm->applyFiltersToFields( $this, $this->oProp->sClassName ); // applies filters to the conditioned field definition arrays.
392                     $this->oForm->setDynamicElements( $this->oProp->aOptions ); // will update $this->oForm->aConditionedFields
393                     echo $oFieldsTable->getFormTables( $this->oForm->aConditionedSections, $this->oForm->aConditionedFields, array( $this, '_replyToGetSectionHeaderOutput' ), array( $this, '_replyToGetFieldOutput' ) );
394 
395                 } 
396                 
397             }     
398              
399             $_sContent = ob_get_contents(); // assign the content buffer to a variable
400             ob_end_clean(); // end buffer and remove the buffer
401                         
402             // Apply the content filters.
403             echo $this->oUtil->addAndApplyFilters( $this, $this->oUtil->getFilterArrayByPrefix( 'content_', $this->oProp->sClassName, $sPageSlug, $sTabSlug, false ), $_sContent );
404 
405             // Do the page actions.
406             $this->oUtil->addAndDoActions(
407                 $this, // the caller object
408                 $this->oUtil->getFilterArrayByPrefix( 'do_', $this->oProp->sClassName, $sPageSlug, $sTabSlug, true ), // the action hooks
409                 $this // the argument 1
410             );     
411             
412             if ( $_bIsSideMetaboxExist )
413                 echo "</div><!-- #post-body-content -->";
414             echo "</div><!-- .admin-page-framework-content -->";
415         }
416     
417         /**
418          * Retrieves the form opening tag.
419          * 
420          * @since 2.0.0
421          * @since 3.1.0 Changed to echo the output. Changed to remove disallowed query keys in the target action url.
422          * @internal
423          * @return void
424          */ 
425         private function _printFormOpeningTag( $fEnableForm=true ) {    
426             
427             if ( ! $fEnableForm ) {
428                 return;
429             }
430     
431             echo "<form " 
432                     . $this->oUtil->generateAttributes(
433                         array(
434                             'method' => 'post',
435                             'enctype' => $this->oProp->sFormEncType,
436                             'id' => 'admin-page-framework-form',
437                             'action' => wp_unslash( remove_query_arg( 'settings-updated', $this->oProp->sTargetFormPage ) ),
438                         )    
439                     ) 
440                 . ">";
441             settings_fields( $this->oProp->sOptionKey );
442             
443         }
444         /**
445          * Retrieves the form closing tag.
446          * 
447          * @since 2.0.0
448          * @since 3.1.0 Prints out the output.
449          * @internal
450          * @return void
451          */     
452         private function _printFormClosingTag( $sPageSlug, $sTabSlug, $fEnableForm=true ) {
453             
454             if ( ! $fEnableForm ) {
455                 return;
456             }
457             
458             $_sNonce = '_admin_page_framework_form_nonce_' . uniqid();
459             $this->oUtil->setTransient( 'form_' . md5( $this->oProp->sClassName . get_current_user_id() ), $_sNonce, 60*60 ); // 60 minutes
460             echo "<input type='hidden' name='page_slug' value='{$sPageSlug}' />" . PHP_EOL
461                 . "<input type='hidden' name='tab_slug' value='{$sTabSlug}' />" . PHP_EOL     
462                 . "<input type='hidden' name='_is_admin_page_framework' value='{$_sNonce}' />" . PHP_EOL
463                 . "</form><!-- End Form -->" . PHP_EOL;
464             
465         }    
466     
467         /**
468          * Retrieves the screen icon output as HTML.
469          * 
470          * @remark     the screen object is supported in WordPress 3.3 or above.
471          * @since 2.0.0
472          */     
473         private function _getScreenIcon( $sPageSlug ) {
474 
475             // If the icon path is explicitly set, use it.
476             if ( isset( $this->oProp->aPages[ $sPageSlug ]['href_icon_32x32'] ) ) 
477                 return '<div class="icon32" style="background-image: url(' . $this->oProp->aPages[ $sPageSlug ]['href_icon_32x32'] . ');"><br /></div>';
478             
479             // If the screen icon ID is explicitly set, use it.
480             if ( isset( $this->oProp->aPages[ $sPageSlug ]['screen_icon_id'] ) )
481                 return '<div class="icon32" id="icon-' . $this->oProp->aPages[ $sPageSlug ]['screen_icon_id'] . '"><br /></div>';
482                 
483             // Retrieve the screen object for the current page.
484             $oScreen = get_current_screen();
485             $sIconIDAttribute = $this->_getScreenIDAttribute( $oScreen );
486 
487             $sClass = 'icon32';
488             if ( empty( $sIconIDAttribute ) && $oScreen->post_type ) 
489                 $sClass .= ' ' . sanitize_html_class( 'icon32-posts-' . $oScreen->post_type );
490             
491             if ( empty( $sIconIDAttribute ) || $sIconIDAttribute == $this->oProp->sClassName )
492                 $sIconIDAttribute = 'generic'; // the default value
493             
494             return '<div id="icon-' . $sIconIDAttribute . '" class="' . $sClass . '"><br /></div>';
495                 
496         }
497             /**
498              * Retrieves the screen ID attribute from the given screen object.
499              * 
500              * @since 2.0.0
501              */     
502             private function _getScreenIDAttribute( $oScreen ) {
503                 
504                 if ( ! empty( $oScreen->parent_base ) )
505                     return $oScreen->parent_base;
506             
507                 if ( 'page' == $oScreen->post_type )
508                     return 'edit-pages';     
509                     
510                 return esc_attr( $oScreen->base );
511                 
512             }
513 
514         /**
515          * Retrieves the output of page heading tab navigation bar as HTML.
516          * 
517          * @since 2.0.0
518          * @return string     the output of page heading tabs.
519          */         
520         private function _getPageHeadingTabs( $sCurrentPageSlug, $sTag='h2', $aOutput=array() ) {
521             
522             // If the page title is disabled, return an empty string.
523             if ( ! $this->oProp->aPages[ $sCurrentPageSlug ][ 'show_page_title' ] ) return "";
524 
525             $sTag = $this->oProp->aPages[ $sCurrentPageSlug ][ 'page_heading_tab_tag' ]
526                 ? $this->oProp->aPages[ $sCurrentPageSlug ][ 'page_heading_tab_tag' ]
527                 : $sTag;
528         
529             // If the page heading tab visibility is disabled, or only one page is registered, return the title.
530             if ( ! $this->oProp->aPages[ $sCurrentPageSlug ][ 'show_page_heading_tabs' ] || count( $this->oProp->aPages ) == 1 )
531                 return "<{$sTag}>" . $this->oProp->aPages[ $sCurrentPageSlug ]['title'] . "</{$sTag}>";     
532 
533             foreach( $this->oProp->aPages as $aSubPage ) {
534                 
535                 // For added sub-pages
536                 if ( isset( $aSubPage['page_slug'] ) && $aSubPage['show_page_heading_tab'] ) {
537                     // Check if the current tab number matches the iteration number. If not match, then assign blank; otherwise put the active class name.
538                     $sClassActive =  $sCurrentPageSlug == $aSubPage['page_slug']  ? 'nav-tab-active' : '';     
539                     $aOutput[] = "<a class='nav-tab {$sClassActive}' "
540                         . "href='" . $this->oUtil->getQueryAdminURL( array( 'page' => $aSubPage['page_slug'], 'tab' => false ), $this->oProp->aDisallowedQueryKeys ) 
541                         . "'>"
542                         . $aSubPage['title']
543                         . "</a>";    
544                 }
545                 
546                 // For added menu links
547                 if ( 
548                     isset( $aSubPage['href'] )
549                     && $aSubPage['type'] == 'link' 
550                     && $aSubPage['show_page_heading_tab']
551                 ) 
552                     $aOutput[] = 
553                         "<a class='nav-tab link' "
554                         . "href='{$aSubPage['href']}'>"
555                             . $aSubPage['title']
556                         . "</a>";     
557                 
558             }     
559             return "<div class='admin-page-framework-page-heading-tab'><{$sTag} class='nav-tab-wrapper'>" 
560                 .  implode( '', $aOutput ) 
561                 . "</{$sTag}></div>";
562             
563         }
564 
565         /**
566          * Retrieves the output of in-page tab navigation bar as HTML.
567          * 
568          * @since 2.0.0
569          * @return string     the output of in-page tabs.
570          */     
571         private function _getInPageTabs( $sCurrentPageSlug, $sTag='h3', $aOutput=array() ) {
572             
573             // If in-page tabs are not set, return an empty string.
574             if ( empty( $this->oProp->aInPageTabs[ $sCurrentPageSlug ] ) ) { 
575                 return implode( '', $aOutput ); 
576             }
577                     
578             // Determine the current tab slug.
579             $sCurrentTabSlug = isset( $_GET['tab'] ) ? $_GET['tab'] : $this->oProp->getDefaultInPageTab( $sCurrentPageSlug );
580             $sCurrentTabSlug = $this->_getParentTabSlug( $sCurrentPageSlug, $sCurrentTabSlug );
581 
582             $sTag = $this->oProp->aPages[ $sCurrentPageSlug ][ 'in_page_tab_tag' ]
583                 ? $this->oProp->aPages[ $sCurrentPageSlug ][ 'in_page_tab_tag' ]
584                 : $sTag;
585         
586             // If the in-page tabs' visibility is set to false, returns the title.
587             if ( ! $this->oProp->aPages[ $sCurrentPageSlug ][ 'show_in_page_tabs' ] ) {
588                 return isset( $this->oProp->aInPageTabs[ $sCurrentPageSlug ][ $sCurrentTabSlug ]['title'] ) 
589                     ? "<{$sTag}>{$this->oProp->aInPageTabs[ $sCurrentPageSlug ][ $sCurrentTabSlug ]['title']}</{$sTag}>" 
590                     : "";
591             }
592 
593             // Get the actual string buffer.
594             foreach( $this->oProp->aInPageTabs[ $sCurrentPageSlug ] as $sTabSlug => $aInPageTab ) {
595                         
596                 // If it's hidden and its parent tab is not set, skip
597                 if ( ! $aInPageTab['show_in_page_tab'] && ! isset( $aInPageTab['parent_tab_slug'] ) ) { continue; }
598                 
599                 // The parent tab means the root tab when there is a hidden tab that belongs to it. Also check it the specified parent tab exists.
600                 $sInPageTabSlug = isset( $aInPageTab['parent_tab_slug'], $this->oProp->aInPageTabs[ $sCurrentPageSlug ][ $aInPageTab['parent_tab_slug'] ] ) 
601                     ? $aInPageTab['parent_tab_slug'] 
602                     : $aInPageTab['tab_slug'];
603                     
604                 // Check if the current tab slug matches the iteration slug. If not match, assign blank; otherwise, put the active class name.
605                 $bIsActiveTab = ( $sCurrentTabSlug == $sInPageTabSlug );
606 
607                 $aOutput[ $sInPageTabSlug ] = "<a class='nav-tab " . ( $bIsActiveTab ? "nav-tab-active" : "" ) . "' "
608                     . "href='" . $this->oUtil->getQueryAdminURL( array( 'page' => $sCurrentPageSlug, 'tab' => $sInPageTabSlug ), $this->oProp->aDisallowedQueryKeys ) 
609                     . "'>"
610                     . $this->oProp->aInPageTabs[ $sCurrentPageSlug ][ $sInPageTabSlug ]['title'] // "{$aInPageTab['title']}"
611                     . "</a>";
612             
613             }     
614             
615             return empty( $aOutput )
616                 ? ""
617                 : "<div class='admin-page-framework-in-page-tab'><{$sTag} class='nav-tab-wrapper in-page-tab'>" 
618                         . implode( '', $aOutput )
619                     . "</{$sTag}></div>";
620                 
621         }
622 
623             /**
624              * Retrieves the parent tab slug from the given tab slug.
625              * 
626              * @since 2.0.0
627              * @since 2.1.2 If the parent slug has the show_in_page_tab to be true, it returns an empty string.
628              * @return string     the parent tab slug.
629              */     
630             private function _getParentTabSlug( $sPageSlug, $sTabSlug ) {
631                 
632                 $sParentTabSlug = isset( $this->oProp->aInPageTabs[ $sPageSlug ][ $sTabSlug ]['parent_tab_slug'] ) 
633                     ? $this->oProp->aInPageTabs[ $sPageSlug ][ $sTabSlug ]['parent_tab_slug']
634                     : $sTabSlug;
635  
636                 return isset( $this->oProp->aInPageTabs[ $sPageSlug ][ $sParentTabSlug ]['show_in_page_tab'] ) && $this->oProp->aInPageTabs[ $sPageSlug ][ $sParentTabSlug ]['show_in_page_tab']
637                     ? $sParentTabSlug
638                     : '';
639 
640             }
641 
642     /**
643      * Finalizes the in-page tab property array.
644      * 
645      * This finalizes the added in-page tabs and sets the default in-page tab for each page.
646      * Also this sorts the in-page tab property array.
647      * This must be done before registering settings sections because the default tab needs to be determined in the process.
648      * 
649      * @since 2.0.0
650      * @remark A callback for the <em>admin_menu</em> hook. It must be called earlier than _replyToRegisterSettings() method.
651      * @return void
652      */         
653     public function _replyToFinalizeInPageTabs() {
654 
655         if ( ! $this->oProp->isPageAdded() ) { return; }
656 
657         foreach( $this->oProp->aPages as $sPageSlug => $aPage ) {
658             
659             if ( ! isset( $this->oProp->aInPageTabs[ $sPageSlug ] ) ) { continue; }
660             
661             // Apply filters to let modify the in-page tab array.
662             $this->oProp->aInPageTabs[ $sPageSlug ] = $this->oUtil->addAndApplyFilter( // Parameters: $oCallerObject, $sFilter, $vInput, $vArgs...
663                 $this,
664                 "tabs_{$this->oProp->sClassName}_{$sPageSlug}",
665                 $this->oProp->aInPageTabs[ $sPageSlug ]     
666             );    
667             // Added in-page arrays may be missing necessary keys so merge them with the default array structure.
668             foreach( $this->oProp->aInPageTabs[ $sPageSlug ] as &$aInPageTab ) {
669                 $aInPageTab = $aInPageTab + self::$_aStructure_InPageTabElements;
670                 $aInPageTab['order'] = is_null( $aInPageTab['order'] ) ? 10 : $aInPageTab['order'];
671             }
672                         
673             // Sort the in-page tab array.
674             uasort( $this->oProp->aInPageTabs[ $sPageSlug ], array( $this, '_sortByOrder' ) );
675             
676             // Set the default tab for the page.
677             // Read the value as reference; otherwise, a strange bug occurs. It may be due to the variable name, $aInPageTab, is also used as reference in the above foreach.
678             foreach( $this->oProp->aInPageTabs[ $sPageSlug ] as $sTabSlug => &$aInPageTab ) {     
679             
680                 if ( ! isset( $aInPageTab['tab_slug'] ) ) { continue; }
681                 
682                 // Regardless of whether it's a hidden tab, it is stored as the default in-page tab.
683                 $this->oProp->aDefaultInPageTabs[ $sPageSlug ] = $aInPageTab['tab_slug'];
684                     
685                 break; // The first iteration item is the default one.
686             }
687         }
688 
689     }     
690     
691 }
692 endif;
Admin Page Framework Documentation API documentation generated by ApiGen 2.8.0