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_MetaBox_Page' ) ) :
10 /**
11 * Provides methods for creating meta boxes in pages added by the framework.
12 *
13 * <h2>Hooks</h2>
14 * <p>The class automatically creates WordPress action and filter hooks associated with the class methods.
15 * The class methods corresponding to the name of the below actions and filters can be extended to modify the page output. Those methods are the callbacks of the filters and actions.</p>
16 * <h3>Methods and Action Hooks</h3>
17 * <ul>
18 * <li><strong>start_{extended class name}</strong> – triggered at the end of the class constructor.</li>
19 * <li><strong>do_{extended class name}</strong> – triggered when the meta box gets rendered.</li>
20 * </ul>
21 * <h3>Methods and Filter Hooks</h3>
22 * <ul>
23 * <li><strong>field_types_{extended class name}</strong> – receives the field type definition array. The first parameter: the field type definition array.</li>
24 * <li><strong>field_{extended class name}_{field ID}</strong> – receives the form input field output of the given input field ID. The first parameter: output string. The second parameter: the array of option.</li>
25 * <li><strong>content_{extended class name}</strong> – receives the entire output of the meta box. The first parameter: the output HTML string.</li>
26 * <li><strong>style_common_{extended class name}</strong> – receives the output of the base CSS rules applied to the pages of the associated post types with the meta box.</li>
27 * <li><strong>style_ie_common_{extended class name}</strong> – receives the output of the base CSS rules for Internet Explorer applied to the pages of the associated post types with the meta box.</li>
28 * <li><strong>style_{extended class name}</strong> – receives the output of the CSS rules applied to the pages of the associated post types with the meta box.</li>
29 * <li><strong>style_ie_{extended class name}</strong> – receives the output of the CSS rules for Internet Explorer applied to the pages of the associated post types with the meta box.</li>
30 * <li><strong>script_common_{extended class name}</strong> – receives the output of the base JavaScript scripts applied to the pages of the associated post types with the meta box.</li>
31 * <li><strong>script_{extended class name}</strong> – receives the output of the JavaScript scripts applied to the pages of the associated post types with the meta box.</li>
32 * <li><strong>validation_{extended class name}</strong> – receives the form submission values as array. The first parameter: submitted input array. The second parameter: the original array stored in the database.</li>
33 * </ul>
34 *
35 * @abstract
36 * @since 3.0.0
37 * @use AdminPageFramework_Utility
38 * @use AdminPageFramework_Message
39 * @use AdminPageFramework_Debug
40 * @use AdminPageFramework_Property_Page
41 * @package AdminPageFramework
42 * @subpackage MetaBox
43 */
44 abstract class AdminPageFramework_MetaBox_Page extends AdminPageFramework_MetaBox_Base {
45
46 /**
47 * Defines the fields type.
48 * @since 3.0.0
49 * @internal
50 */
51 static protected $_sFieldsType = 'page_meta_box';
52
53 /**
54 * Registers necessary hooks and internal properties.
55 *
56 * <h4>Examples</h4>
57 * <code>
58 * new APF_MetaBox_For_Pages_Normal(
59 * 'apf_metabox_for_pages_normal', // meta box id
60 * __( 'Sample Meta Box For Admin Pages Inserted in Normal Area' ), // title
61 * 'apf_first_page', // page slugs
62 * 'normal', // context
63 * 'default' // priority
64 * );
65 * include_once( APFDEMO_DIRNAME . '/example/APF_MetaBox_For_Pages_Advanced.php' );
66 * new APF_MetaBox_For_Pages_Advanced(
67 * 'apf_metabox_for_pages_advanced', // meta box id
68 * __( 'Sample Meta Box For Admin Pages Inserted in Advanced Area' ), // title
69 * 'apf_first_page', // page slugs
70 * 'advanced', // context
71 * 'default' // priority
72 * );
73 * include_once( APFDEMO_DIRNAME . '/example/APF_MetaBox_For_Pages_Side.php' );
74 * new APF_MetaBox_For_Pages_Side(
75 * 'apf_metabox_for_pages_side', // meta box id
76 * __( 'Sample Meta Box For Admin Pages Inserted in Advanced Area' ), // title
77 * array( 'apf_first_page', 'apf_second_page' ), // page slugs - setting multiple slugs is possible
78 * 'side', // context
79 * 'default' // priority
80 * );
81 * </code>
82 * @since 3.0.0
83 *
84 * @param string $sMetaBoxID The meta box ID to be created.
85 * @param string $sTitle The meta box title.
86 * @param array|string $asPageSlugs the page slug(s) that the meta box belongs to. If the element is an array, it will be considered as a tab array.
87 * <code>
88 $asPageSlugs = array(
89 'settings' => array( // if the key is not numeric and the value is an array, it will be considered as a tab array.
90 'help', // enabled in the tab whose slug is 'help' which belongs to the page whose slug is 'settings'
91 'about', // enabled in the tab whose slug is 'about' which belongs to the page whose slug is 'settings'
92 'general', // enabled in the tab whose slug is 'general' which belongs to the page whose slug is 'settings'
93 ),
94 'manage', // if the numeric key with a string value is given, the condition applies to the page slug of this string value.
95 );
96 * </code>
97 * @param string $sContext The context, either 'normal', 'advanced', or 'side'.
98 * @param string $sPriority The priority, either 'high', 'core', 'default' or 'low'.
99 * @param string $sCapability The capability. See <a href="https://codex.wordpress.org/Roles_and_Capabilities" target="_blank">Roles and Capabilities</a>.
100 */
101 function __construct( $sMetaBoxID, $sTitle, $asPageSlugs=array(), $sContext='normal', $sPriority='default', $sCapability='manage_options', $sTextDomain='admin-page-framework' ) {
102
103 if ( empty( $asPageSlugs ) ) return;
104
105 /* The property object needs to be done first */
106 $this->oProp = new AdminPageFramework_Property_MetaBox_Page( $this, get_class( $this ), $sCapability );
107
108 parent::__construct( $sMetaBoxID, $sTitle, $asPageSlugs, $sContext, $sPriority, $sCapability, $sTextDomain );
109
110 $this->oProp->aPageSlugs = is_string( $asPageSlugs ) ? array( $asPageSlugs ) : $asPageSlugs; // must be set before the isInThePage() method is used.
111 $this->oProp->sFieldsType = self::$_sFieldsType;
112
113 if ( $this->_isInThePage() ) :
114
115 /* These classes use methods that determine the current tab and page slugs based from the added pages. */
116 $this->oHeadTag = new AdminPageFramework_HeadTag_MetaBox_Page( $this->oProp );
117 $this->oHelpPane = new AdminPageFramework_HelpPane_MetaBox( $this->oProp );
118
119
120 $this->oForm = new AdminPageFramework_FormElement( $this->oProp->sFieldsType, $sCapability );
121
122 /* Validation hook */
123 foreach( $this->oProp->aPageSlugs as $_sIndexOrPageSlug => $_asTabArrayOrPageSlug ) {
124
125 if ( is_string( $_asTabArrayOrPageSlug ) ) {
126 $_sPageSlug = $_asTabArrayOrPageSlug;
127 add_filter( "validation_saved_options_{$_sPageSlug}", array( $this, '_replyToFilterPageOptions' ) );
128 add_filter( "validation_{$_sPageSlug}", array( $this, '_replyToValidateOptions' ), 10, 2 );
129 continue;
130 }
131
132 // At this point, the array key is the page slug.
133 $_sPageSlug = $_sIndexOrPageSlug;
134 $_aTabs = $_asTabArrayOrPageSlug;
135 add_filter( "validation_{$_sPageSlug}", array( $this, '_replyToValidateOptions' ), 10, 2 );
136 foreach( $_aTabs as $_sTabSlug )
137 add_filter( "validation_saved_options_{$_sPageSlug}_{$_sTabSlug}", array( $this, '_replyToFilterPageOptions' ) );
138
139 }
140
141 endif;
142
143 $this->oUtil->addAndDoAction( $this, "start_{$this->oProp->sClassName}" );
144
145 }
146
147 /**
148 * Determines whether the meta box belongs to the loading page.
149 *
150 * @since 3.0.3
151 * @internal
152 */
153 protected function _isInThePage() {
154
155 if ( in_array( $GLOBALS['pagenow'], array( 'options.php' ) ) ) {
156 return true;
157 }
158
159 if ( ! isset( $_GET['page'] ) ) {
160 return false;
161 }
162
163 return in_array( $_GET['page'], $this->oProp->aPageSlugs );
164
165 }
166
167 /*
168 * Head Tag Methods
169 */
170 /**
171 * Enqueues styles by page slug and tab slug.
172 *
173 * @since 3.0.0
174 */
175 public function enqueueStyles( $aSRCs, $sPageSlug='', $sTabSlug='', $aCustomArgs=array() ) {
176 return $this->oHeadTag->_enqueueStyles( $aSRCs, $sPageSlug, $sTabSlug, $aCustomArgs );
177 }
178 /**
179 * Enqueues a style by page slug and tab slug.
180 *
181 * @since 3.0.0
182 * @see http://codex.wordpress.org/Function_Reference/wp_enqueue_style
183 * @param string The URL of the stylesheet to enqueue, the absolute file path, or the relative path to the root directory of WordPress. Example: '/css/mystyle.css'.
184 * @param string (optional) The page slug that the stylesheet should be added to. If not set, it applies to all the pages created by the framework.
185 * @param string (optional) The tab slug that the stylesheet should be added to. If not set, it applies to all the in-page tabs in the page.
186 * @param array (optional) The argument array for more advanced parameters.
187 * @return string The script handle ID. If the passed url is not a valid url string, an empty string will be returned.
188 */
189 public function enqueueStyle( $sSRC, $sPageSlug='', $sTabSlug='', $aCustomArgs=array() ) {
190 return $this->oHeadTag->_enqueueStyle( $sSRC, $sPageSlug, $sTabSlug, $aCustomArgs );
191 }
192 /**
193 * Enqueues scripts by page slug and tab slug.
194 *
195 * @since 2.1.5
196 */
197 public function enqueueScripts( $aSRCs, $sPageSlug='', $sTabSlug='', $aCustomArgs=array() ) {
198 return $this->oHeadTag->_enqueueScripts( $sSRC, $sPageSlug, $sTabSlug, $aCustomArgs );
199 }
200 /**
201 * Enqueues a script by page slug and tab slug.
202 *
203 * @since 3.0.0
204 * @see http://codex.wordpress.org/Function_Reference/wp_enqueue_script
205 * @param string The URL of the stylesheet to enqueue, the absolute file path, or the relative path to the root directory of WordPress. Example: '/js/myscript.js'.
206 * @param string (optional) The page slug that the script should be added to. If not set, it applies to all the pages created by the framework.
207 * @param string (optional) The tab slug that the script should be added to. If not set, it applies to all the in-page tabs in the page.
208 * @param array (optional) The argument array for more advanced parameters.
209 * @return string The script handle ID. If the passed url is not a valid url string, an empty string will be returned.
210 */
211 public function enqueueScript( $sSRC, $sPageSlug='', $sTabSlug='', $aCustomArgs=array() ) {
212 return $this->oHeadTag->_enqueueScript( $sSRC, $sPageSlug, $sTabSlug, $aCustomArgs );
213 }
214
215 /**
216 * Returns the field output.
217 *
218 * @since 3.0.0
219 * @internal
220 */
221 protected function getFieldOutput( $aField ) {
222
223 /* Since meta box fields don't have the option_key key which is required to compose the name attribute in the regular pages. */
224 $sOptionKey = $this->_getOptionKey();
225 $aField['option_key'] = $sOptionKey ? $sOptionKey : null;
226 $aField['page_slug'] = isset( $_GET['page'] ) ? $_GET['page'] : ''; // set an empty string to make it yield true for isset() so that saved options will be checked.
227
228 return parent::getFieldOutput( $aField );
229
230 }
231
232 /**
233 * Returns the currently loading page's option key if the page has the admin page object.
234 * @since 3.0.0
235 * @internal
236 */
237 private function _getOptionkey() {
238 return isset( $_GET['page'] )
239 ? $this->oProp->getOptionKey( $_GET['page'] )
240 : null;
241 }
242
243
244 /**
245 * Adds the defined meta box.
246 *
247 * @internal
248 * @since 3.0.0
249 * @remark uses <em>add_meta_box()</em>.
250 * @remark Before this method is called, the pages and in-page tabs need to be registered already.
251 * @remark A callback for the <em>add_meta_boxes</em> hook.
252 * @return void
253 */
254 public function _replyToAddMetaBox() {
255
256 foreach( $this->oProp->aPageSlugs as $sKey => $asPage ) {
257
258 if ( is_string( $asPage ) ) {
259 $this->_addMetaBox( $asPage );
260 continue;
261 }
262 if ( ! is_array( $asPage ) ) continue;
263
264 $sPageSlug = $sKey;
265 foreach( $asPage as $sTabSlug ) {
266
267 if ( ! $this->oProp->isCurrentTab( $sTabSlug ) ) continue;
268
269 $this->_addMetaBox( $sPageSlug );
270
271 }
272
273 }
274
275 }
276 /**
277 * Adds meta box with the given page slug.
278 * @since 3.0.0
279 * @internal
280 */
281 private function _addMetaBox( $sPageSlug ) {
282
283 add_meta_box(
284 $this->oProp->sMetaBoxID, // id
285 $this->oProp->sTitle, // title
286 array( $this, '_replyToPrintMetaBoxContents' ), // callback
287 $this->oProp->_getScreenIDOfPage( $sPageSlug ), // screen ID
288 $this->oProp->sContext, // context
289 $this->oProp->sPriority, // priority
290 null // argument // deprecated
291 );
292
293 }
294
295 /**
296 * Filters the page option array.
297 *
298 * This is triggered from the system validation method of the main class with the validation_saved_options_{page slug} filter hook.
299 *
300 * @since 3.0.0
301 * @param array
302 */
303 public function _replyToFilterPageOptions( $aPageOptions ) {
304
305 return $this->oForm->dropRepeatableElements( $aPageOptions );
306
307 }
308
309 /**
310 * Validates the submitted option values.
311 *
312 * @internal
313 * @sicne 3.0.0
314 * @param array $aNewPageOptions The array holing the field values of the page sent from the framework page class (the main class).
315 * @param array $aOldPageOptions The array holing the saved options of the page. Note that this will be empty if non of generic page fields are created.
316 */
317 public function _replyToValidateOptions( $aNewPageOptions, $aOldPageOptions ) {
318
319 // The field values of this class will not be included in the parameter array. So get them.
320 $_aFieldsModel = $this->oForm->getFieldsModel();
321 $_aNewMetaBoxInput = $this->oUtil->castArrayContents( $_aFieldsModel, $_POST );
322 $_aOldMetaBoxInput = $this->oUtil->castArrayContents( $_aFieldsModel, $aOldPageOptions );
323
324 // Apply filters - third party scripts will have access to the input.
325 $_aNewMetaBoxInput = stripslashes_deep( $_aNewMetaBoxInput ); // fixes magic quotes
326 $_aNewMetaBoxInput = $this->oUtil->addAndApplyFilters( $this, "validation_{$this->oProp->sClassName}", $_aNewMetaBoxInput, $_aOldMetaBoxInput );
327
328 // Now merge the input values with the passed page options.
329 return $this->oUtil->uniteArrays( $_aNewMetaBoxInput, $aNewPageOptions );
330
331 }
332
333 /**
334 * Registers form fields and sections.
335 *
336 * @since 3.0.0
337 * @internal
338 */
339 public function _replyToRegisterFormElements() {
340
341 // Schedule to add head tag elements and help pane contents.
342 if ( ! $this->_isInThePage() ) return;
343
344 // Format the fields array.
345 $this->oForm->format();
346 $this->oForm->applyConditions(); // will create the conditioned elements.
347 // $this->oForm->applyFiltersToFields( $this, $this->oProp->sClassName );
348
349 // Add the repeatable section elements to the fields definition array.
350 $this->oForm->setDynamicElements( $this->oProp->aOptions ); // will update $this->oForm->aConditionedFields
351
352 $this->_registerFields( $this->oForm->aConditionedFields );
353
354 }
355
356 }
357 endif;