WP-PageNavi - Version 2.88

Version Description

  • NEW: Added filters for altering class names. Props @bookwyrm
Download this release

Release Info

Developer GamerZ
Plugin Icon WP-PageNavi
Version 2.88
Comparing to
See all releases

Code changes from version 2.87 to 2.88

Files changed (15) hide show
  1. core.php +28 -14
  2. readme.txt +65 -2
  3. scb/AdminPage.php +159 -93
  4. scb/BoxesPage.php +111 -30
  5. scb/Cron.php +73 -37
  6. scb/Forms.php +219 -100
  7. scb/Hooks.php +56 -9
  8. scb/Options.php +90 -43
  9. scb/PostMetabox.php +187 -23
  10. scb/Table.php +41 -6
  11. scb/Util.php +235 -64
  12. scb/Widget.php +66 -17
  13. scb/load-composer.php +3 -2
  14. scb/load.php +30 -18
  15. wp-pagenavi.php +1 -1
core.php CHANGED
@@ -62,6 +62,20 @@ function wp_pagenavi( $args = array() ) {
62
  if ( $start_page < 1 )
63
  $start_page = 1;
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  $out = '';
66
  switch ( intval( $options['style'] ) ) {
67
  // Normal
@@ -72,28 +86,28 @@ function wp_pagenavi( $args = array() ) {
72
  array( "%CURRENT_PAGE%", "%TOTAL_PAGES%" ),
73
  array( number_format_i18n( $paged ), number_format_i18n( $total_pages ) ),
74
  __( $options['pages_text'], 'wp-pagenavi' ) );
75
- $out .= "<span class='pages'>$pages_text</span>";
76
  }
77
 
78
  if ( $start_page >= 2 && $pages_to_show < $total_pages ) {
79
  // First
80
  $first_text = str_replace( '%TOTAL_PAGES%', number_format_i18n( $total_pages ), __( $options['first_text'], 'wp-pagenavi' ) );
81
  $out .= $instance->get_single( 1, $first_text, array(
82
- 'class' => 'first'
83
  ), '%TOTAL_PAGES%' );
84
  }
85
 
86
  // Previous
87
  if ( $paged > 1 && !empty( $options['prev_text'] ) ) {
88
  $out .= $instance->get_single( $paged - 1, $options['prev_text'], array(
89
- 'class' => 'previouspostslink',
90
  'rel' => 'prev'
91
  ) );
92
  }
93
 
94
  if ( $start_page >= 2 && $pages_to_show < $total_pages ) {
95
  if ( !empty( $options['dotleft_text'] ) )
96
- $out .= "<span class='extend'>{$options['dotleft_text']}</span>";
97
  }
98
 
99
  // Smaller pages
@@ -106,25 +120,25 @@ function wp_pagenavi( $args = array() ) {
106
  foreach ( $larger_pages_array as $larger_page ) {
107
  if ( $larger_page < ($start_page - $half_page_start) && $larger_page_start < $larger_page_to_show ) {
108
  $out .= $instance->get_single( $larger_page, $options['page_text'], array(
109
- 'class' => 'smaller page',
110
  ) );
111
  $larger_page_start++;
112
  }
113
  }
114
 
115
  if ( $larger_page_start )
116
- $out .= "<span class='extend'>{$options['dotleft_text']}</span>";
117
 
118
  // Page numbers
119
  $timeline = 'smaller';
120
  foreach ( range( $start_page, $end_page ) as $i ) {
121
  if ( $i == $paged && !empty( $options['current_text'] ) ) {
122
  $current_page_text = str_replace( '%PAGE_NUMBER%', number_format_i18n( $i ), $options['current_text'] );
123
- $out .= "<span class='current'>$current_page_text</span>";
124
  $timeline = 'larger';
125
  } else {
126
  $out .= $instance->get_single( $i, $options['page_text'], array(
127
- 'class' => "page $timeline",
128
  ) );
129
  }
130
  }
@@ -135,26 +149,26 @@ function wp_pagenavi( $args = array() ) {
135
  foreach ( $larger_pages_array as $larger_page ) {
136
  if ( $larger_page > ($end_page + $half_page_end) && $larger_page_end < $larger_page_to_show ) {
137
  $larger_page_out .= $instance->get_single( $larger_page, $options['page_text'], array(
138
- 'class' => 'larger page',
139
  ) );
140
  $larger_page_end++;
141
  }
142
  }
143
 
144
  if ( $larger_page_out ) {
145
- $out .= "<span class='extend'>{$options['dotright_text']}</span>";
146
  }
147
  $out .= $larger_page_out;
148
 
149
  if ( $end_page < $total_pages ) {
150
  if ( !empty( $options['dotright_text'] ) )
151
- $out .= "<span class='extend'>{$options['dotright_text']}</span>";
152
  }
153
 
154
  // Next
155
  if ( $paged < $total_pages && !empty( $options['next_text'] ) ) {
156
  $out .= $instance->get_single( $paged + 1, $options['next_text'], array(
157
- 'class' => 'nextpostslink',
158
  'rel' => 'next'
159
  ) );
160
  }
@@ -162,7 +176,7 @@ function wp_pagenavi( $args = array() ) {
162
  if ( $end_page < $total_pages ) {
163
  // Last
164
  $out .= $instance->get_single( $total_pages, __( $options['last_text'], 'wp-pagenavi' ), array(
165
- 'class' => 'last',
166
  ), '%TOTAL_PAGES%' );
167
  }
168
  break;
@@ -179,7 +193,7 @@ function wp_pagenavi( $args = array() ) {
179
 
180
  if ( $i == $paged ) {
181
  $current_page_text = str_replace( '%PAGE_NUMBER%', number_format_i18n( $i ), $options['current_text'] );
182
- $out .= '<option value="'.esc_url( $instance->get_url( $page_num ) ).'" selected="selected" class="current">'.$current_page_text."</option>\n";
183
  } else {
184
  $page_text = str_replace( '%PAGE_NUMBER%', number_format_i18n( $i ), $options['page_text'] );
185
  $out .= '<option value="'.esc_url( $instance->get_url( $page_num ) ).'">'.$page_text."</option>\n";
62
  if ( $start_page < 1 )
63
  $start_page = 1;
64
 
65
+ // Support for filters to change class names
66
+ $class_names = array(
67
+ 'pages' => apply_filters( 'wp_pagenavi_class_pages', 'pages'),
68
+ 'first' => apply_filters( 'wp_pagenavi_class_first', 'first' ),
69
+ 'previouspostslink' => apply_filters( 'wp_pagenavi_class_previouspostslink', 'previouspostslink' ),
70
+ 'extend' => apply_filters( 'wp_pagenavi_class_extend', 'extend' ),
71
+ 'smaller' => apply_filters( 'wp_pagenavi_class_smaller', 'smaller' ),
72
+ 'page' => apply_filters( 'wp_pagenavi_class_page', 'page' ),
73
+ 'current' => apply_filters( 'wp_pagenavi_class_current', 'current'),
74
+ 'larger' => apply_filters( 'wp_pagenavi_class_larger', 'larger' ),
75
+ 'nextpostslink' => apply_filters( 'wp_pagenavi_class_nextpostslink', 'nextpostslink'),
76
+ 'last' => apply_filters( 'wp_pagenavi_class_last', 'last'),
77
+ );
78
+
79
  $out = '';
80
  switch ( intval( $options['style'] ) ) {
81
  // Normal
86
  array( "%CURRENT_PAGE%", "%TOTAL_PAGES%" ),
87
  array( number_format_i18n( $paged ), number_format_i18n( $total_pages ) ),
88
  __( $options['pages_text'], 'wp-pagenavi' ) );
89
+ $out .= "<span class='{$class_names['pages']}'>$pages_text</span>";
90
  }
91
 
92
  if ( $start_page >= 2 && $pages_to_show < $total_pages ) {
93
  // First
94
  $first_text = str_replace( '%TOTAL_PAGES%', number_format_i18n( $total_pages ), __( $options['first_text'], 'wp-pagenavi' ) );
95
  $out .= $instance->get_single( 1, $first_text, array(
96
+ 'class' => $class_names['first']
97
  ), '%TOTAL_PAGES%' );
98
  }
99
 
100
  // Previous
101
  if ( $paged > 1 && !empty( $options['prev_text'] ) ) {
102
  $out .= $instance->get_single( $paged - 1, $options['prev_text'], array(
103
+ 'class' => $class_names['previouspostslink'],
104
  'rel' => 'prev'
105
  ) );
106
  }
107
 
108
  if ( $start_page >= 2 && $pages_to_show < $total_pages ) {
109
  if ( !empty( $options['dotleft_text'] ) )
110
+ $out .= "<span class='{$class_names['extend']}'>{$options['dotleft_text']}</span>";
111
  }
112
 
113
  // Smaller pages
120
  foreach ( $larger_pages_array as $larger_page ) {
121
  if ( $larger_page < ($start_page - $half_page_start) && $larger_page_start < $larger_page_to_show ) {
122
  $out .= $instance->get_single( $larger_page, $options['page_text'], array(
123
+ 'class' => "{$class_names['smaller']} {$class_names['page']}",
124
  ) );
125
  $larger_page_start++;
126
  }
127
  }
128
 
129
  if ( $larger_page_start )
130
+ $out .= "<span class='{$class_names['extend']}'>{$options['dotleft_text']}</span>";
131
 
132
  // Page numbers
133
  $timeline = 'smaller';
134
  foreach ( range( $start_page, $end_page ) as $i ) {
135
  if ( $i == $paged && !empty( $options['current_text'] ) ) {
136
  $current_page_text = str_replace( '%PAGE_NUMBER%', number_format_i18n( $i ), $options['current_text'] );
137
+ $out .= "<span class='{$class_names['current']}'>$current_page_text</span>";
138
  $timeline = 'larger';
139
  } else {
140
  $out .= $instance->get_single( $i, $options['page_text'], array(
141
+ 'class' => "{$class_names['page']} {$class_names[$timeline]}",
142
  ) );
143
  }
144
  }
149
  foreach ( $larger_pages_array as $larger_page ) {
150
  if ( $larger_page > ($end_page + $half_page_end) && $larger_page_end < $larger_page_to_show ) {
151
  $larger_page_out .= $instance->get_single( $larger_page, $options['page_text'], array(
152
+ 'class' => "{$class_names['larger']} {$class_names['page']}",
153
  ) );
154
  $larger_page_end++;
155
  }
156
  }
157
 
158
  if ( $larger_page_out ) {
159
+ $out .= "<span class='{$class_names['extend']}'>{$options['dotright_text']}</span>";
160
  }
161
  $out .= $larger_page_out;
162
 
163
  if ( $end_page < $total_pages ) {
164
  if ( !empty( $options['dotright_text'] ) )
165
+ $out .= "<span class='{$class_names['extend']}'>{$options['dotright_text']}</span>";
166
  }
167
 
168
  // Next
169
  if ( $paged < $total_pages && !empty( $options['next_text'] ) ) {
170
  $out .= $instance->get_single( $paged + 1, $options['next_text'], array(
171
+ 'class' => $class_names['nextpostslink'],
172
  'rel' => 'next'
173
  ) );
174
  }
176
  if ( $end_page < $total_pages ) {
177
  // Last
178
  $out .= $instance->get_single( $total_pages, __( $options['last_text'], 'wp-pagenavi' ), array(
179
+ 'class' => $class_names['last'],
180
  ), '%TOTAL_PAGES%' );
181
  }
182
  break;
193
 
194
  if ( $i == $paged ) {
195
  $current_page_text = str_replace( '%PAGE_NUMBER%', number_format_i18n( $i ), $options['current_text'] );
196
+ $out .= '<option value="'.esc_url( $instance->get_url( $page_num ) ).'" selected="selected" class="'.$class_names['current'].'">'.$current_page_text."</option>\n";
197
  } else {
198
  $page_text = str_replace( '%PAGE_NUMBER%', number_format_i18n( $i ), $options['page_text'] );
199
  $out .= '<option value="'.esc_url( $instance->get_url( $page_num ) ).'">'.$page_text."</option>\n";
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: GamerZ, scribu
3
  Donate link: http://lesterchan.net/site/donation/
4
  Tags: navigation, pagination, paging, pages
5
  Requires at least: 3.2
6
- Tested up to: 4.2
7
- Stable tag: 2.87
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -66,6 +66,66 @@ If you need to configure the CSS style of WP-PageNavi, you can copy the `pagenav
66
 
67
  Alternatively, you can uncheck the "Use pagenavi.css?" option from the settings page and add the styles to your theme's style.css file directly.
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
  == Screenshots ==
71
 
@@ -98,6 +158,9 @@ You can do that like so:
98
  `<?php wp_pagenavi( array( 'options' => PageNavi_Core::$options->get_defaults() ) ); ?>`
99
 
100
  == Changelog ==
 
 
 
101
  = 2.87 =
102
  * NEW: Uses WordPress native uninstall.php
103
 
3
  Donate link: http://lesterchan.net/site/donation/
4
  Tags: navigation, pagination, paging, pages
5
  Requires at least: 3.2
6
+ Tested up to: 4.3
7
+ Stable tag: 2.88
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
66
 
67
  Alternatively, you can uncheck the "Use pagenavi.css?" option from the settings page and add the styles to your theme's style.css file directly.
68
 
69
+ = Changing Class Names =
70
+
71
+ There are [filters](http://codex.wordpress.org/Glossary#Filter) that can be used to change the default class names that are assigned to page navigation elements.
72
+
73
+ #### Filters
74
+
75
+ * `wp_pagenavi_class_pages`
76
+ * `wp_pagenavi_class_first`
77
+ * `wp_pagenavi_class_previouspostslink`
78
+ * `wp_pagenavi_class_extend`
79
+ * `wp_pagenavi_class_smaller`
80
+ * `wp_pagenavi_class_page`
81
+ * `wp_pagenavi_class_current`
82
+ * `wp_pagenavi_class_larger`
83
+ * `wp_pagenavi_class_nextpostslink`
84
+ * `wp_pagenavi_class_last`
85
+
86
+ #### Filter Usage
87
+
88
+ ```php
89
+ // Simple Usage - 1 callback per filter
90
+ add_filter('wp_pagenavi_class_previouspostslink', 'theme_pagination_previouspostslink_class');
91
+ add_filter('wp_pagenavi_class_nextpostslink', 'theme_pagination_nextpostslink_class');
92
+ add_filter('wp_pagenavi_class_page', 'theme_pagination_page_class');
93
+
94
+ function theme_pagination_previouspostslink_class($class_name) {
95
+ return 'pagination__control-link pagination__control-link--previous';
96
+ }
97
+
98
+ function theme_pagination_nextpostslink_class($class_name) {
99
+ return 'pagination__control-link pagination__control-link--next';
100
+ }
101
+
102
+ function theme_pagination_page_class($class_name) {
103
+ return 'pagination__current-page';
104
+ }
105
+
106
+
107
+ // More Concise Usage - 1 callback for all filters
108
+ add_filter('wp_pagenavi_class_previouspostslink', 'theme_pagination_class');
109
+ add_filter('wp_pagenavi_class_nextpostslink', 'theme_pagination_class');
110
+ add_filter('wp_pagenavi_class_page', 'theme_pagination_class');
111
+
112
+ function theme_pagination_class($class_name) {
113
+ switch($class_name) {
114
+ case 'previouspostslink':
115
+ $class_name = 'pagination__control-link pagination__control-link--previous';
116
+ break;
117
+ case 'nextpostslink':
118
+ $class_name = 'pagination__control-link pagination__control-link--next';
119
+ break;
120
+ case 'page':
121
+ $class_name = 'pagination__current'
122
+ break;
123
+ }
124
+ return $class_name;
125
+ }
126
+ ```
127
+
128
+
129
 
130
  == Screenshots ==
131
 
158
  `<?php wp_pagenavi( array( 'options' => PageNavi_Core::$options->get_defaults() ) ); ?>`
159
 
160
  == Changelog ==
161
+ = 2.88 =
162
+ * NEW: Added filters for altering class names. Props @bookwyrm
163
+
164
  = 2.87 =
165
  * NEW: Uses WordPress native uninstall.php
166
 
scb/AdminPage.php CHANGED
@@ -1,7 +1,6 @@
1
  <?php
2
-
3
  /**
4
- * Administration page base class
5
  */
6
  abstract class scbAdminPage {
7
  /** Page args
@@ -43,17 +42,20 @@ abstract class scbAdminPage {
43
  private static $registered = array();
44
 
45
  /**
46
- * @param string $class
47
- * @param string $file
48
- * @param scbOptions $options
 
 
49
  *
50
  * @return bool
51
  */
52
- static function register( $class, $file, $options = null ) {
53
- if ( isset( self::$registered[$class] ) )
54
  return false;
 
55
 
56
- self::$registered[$class] = array( $file, $options );
57
 
58
  add_action( '_admin_menu', array( __CLASS__, '_pages_init' ) );
59
 
@@ -61,38 +63,50 @@ abstract class scbAdminPage {
61
  }
62
 
63
  /**
 
 
64
  * @param string $old_class
65
  * @param string $new_class
66
  *
67
  * @return bool
68
  */
69
- static function replace( $old_class, $new_class ) {
70
- if ( ! isset( self::$registered[$old_class] ) )
71
  return false;
 
72
 
73
- self::$registered[$new_class] = self::$registered[$old_class];
74
- unset( self::$registered[$old_class] );
75
 
76
  return true;
77
  }
78
 
79
  /**
 
 
80
  * @param string $class
81
  *
82
  * @return bool
83
  */
84
- static function remove( $class ) {
85
- if ( ! isset( self::$registered[$class] ) )
86
  return false;
 
87
 
88
- unset( self::$registered[$class] );
89
 
90
  return true;
91
  }
92
 
93
- static function _pages_init() {
94
- foreach ( self::$registered as $class => $args )
 
 
 
 
 
95
  new $class( $args[0], $args[1] );
 
96
  }
97
 
98
 
@@ -100,14 +114,17 @@ abstract class scbAdminPage {
100
 
101
 
102
  /**
103
- * Constructor
104
  *
105
- * @param string|bool $file
106
- * @param scbOptions $options
 
 
107
  */
108
- function __construct( $file = false, $options = null ) {
109
- if ( is_a( $options, 'scbOptions' ) )
110
  $this->options = $options;
 
111
 
112
  $this->setup();
113
  $this->check_args();
@@ -124,82 +141,96 @@ abstract class scbAdminPage {
124
  $this->file = $file;
125
  $this->plugin_url = plugin_dir_url( $file );
126
 
127
- if ( $this->args['action_link'] )
128
  add_filter( 'plugin_action_links_' . plugin_basename( $file ), array( $this, '_action_link' ) );
 
129
  }
130
  }
131
 
132
  /**
133
- * This is where all the page args can be set
 
 
134
  */
135
- function setup(){}
136
 
137
  /**
138
  * Called when the page is loaded, but before any rendering.
139
- *
140
  * Useful for calling $screen->add_help_tab() etc.
 
 
141
  */
142
- function page_loaded() {
143
  $this->form_handler();
144
  }
145
 
146
  /**
147
- * This is where the css and js go
148
- * Both wp_enqueue_*() and inline code can be added
 
 
149
  */
150
- function page_head(){}
151
 
152
  /**
153
- * This is where the contextual help goes
 
154
  * @return string
155
  */
156
- function page_help(){}
157
 
158
  /**
159
- * A generic page header
 
 
160
  */
161
- function page_header() {
162
  echo "<div class='wrap'>\n";
163
  screen_icon( $this->args['screen_icon'] );
164
  echo html( 'h2', $this->args['page_title'] );
165
  }
166
 
167
  /**
168
- * This is where the page content goes
 
 
169
  */
170
- abstract function page_content();
171
 
172
  /**
173
- * A generic page footer
 
 
174
  */
175
- function page_footer() {
176
  echo "</div>\n";
177
  }
178
 
179
  /**
180
- * This is where the form data should be validated
181
  *
182
  * @param array $new_data
183
  * @param array $old_data
184
  *
185
  * @return array
186
  */
187
- function validate( $new_data, $old_data ) {
188
  return $new_data;
189
  }
190
 
191
  /**
192
- * Manually handle option saving ( use Settings API instead )
193
  *
194
  * @return bool
195
  */
196
- function form_handler() {
197
- if ( empty( $_POST['submit'] ) && empty( $_POST['action'] ) )
198
  return false;
 
199
 
200
  check_admin_referer( $this->nonce );
201
 
202
- if ( !isset($this->options) ) {
203
  trigger_error( 'options handler not set', E_USER_WARNING );
204
  return false;
205
  }
@@ -218,14 +249,17 @@ abstract class scbAdminPage {
218
  }
219
 
220
  /**
221
- * Manually generate a standard admin notice ( use Settings API instead )
222
  *
223
- * @param string $msg
224
- * @param string $class
 
 
225
  */
226
- function admin_msg( $msg = '', $class = 'updated' ) {
227
- if ( empty( $msg ) )
228
  $msg = __( 'Settings <strong>saved</strong>.', $this->textdomain );
 
229
 
230
  echo scb_admin_notice( $msg, $class );
231
  }
@@ -235,15 +269,15 @@ abstract class scbAdminPage {
235
 
236
 
237
  /**
238
- * Generates a form submit button
239
  *
240
- * @param string|array $value button text or array of arguments
241
- * @param string $action
242
- * @param string $class
243
  *
244
  * @return string
245
  */
246
- function submit_button( $value = '', $action = 'submit', $class = 'button' ) {
247
 
248
  $args = is_array( $value ) ? $value : compact( 'value', 'action', 'class' );
249
  $args = wp_parse_args( $args, array(
@@ -271,20 +305,20 @@ abstract class scbAdminPage {
271
  * @see scbForms::form_wrap()
272
  *
273
  * @param string $content
274
- * @param boolean|string|array $submit_button
275
  *
276
  * @return string
277
  */
278
- function form_wrap( $content, $submit_button = true ) {
279
  if ( is_array( $submit_button ) ) {
280
  $content .= $this->submit_button( $submit_button );
281
- } elseif ( true === $submit_button ) {
282
  $content .= $this->submit_button();
283
- } elseif ( false !== strpos( $submit_button, '<input' ) ) {
284
  $content .= $submit_button;
285
- } elseif ( false !== strpos( $submit_button, '<button' ) ) {
286
  $content .= $submit_button;
287
- } elseif ( false !== $submit_button ) {
288
  $button_args = array_slice( func_get_args(), 1 );
289
  $content .= call_user_func_array( array( $this, 'submit_button' ), $button_args );
290
  }
@@ -293,17 +327,18 @@ abstract class scbAdminPage {
293
  }
294
 
295
  /**
296
- * Generates a table wrapped in a form
297
  *
298
  * @param array $rows
299
- * @param array|boolean $formdata
300
  *
301
  * @return string
302
  */
303
- function form_table( $rows, $formdata = false ) {
304
  $output = '';
305
- foreach ( $rows as $row )
306
  $output .= $this->table_row( $row, $formdata );
 
307
 
308
  $output = $this->form_table_wrap( $output );
309
 
@@ -317,7 +352,7 @@ abstract class scbAdminPage {
317
  *
318
  * @return string
319
  */
320
- function form_table_wrap( $content ) {
321
  $output = $this->table_wrap( $content );
322
  $output = $this->form_wrap( $output );
323
 
@@ -325,17 +360,18 @@ abstract class scbAdminPage {
325
  }
326
 
327
  /**
328
- * Generates a form table
329
  *
330
  * @param array $rows
331
- * @param array|boolean $formdata
332
  *
333
  * @return string
334
  */
335
- function table( $rows, $formdata = false ) {
336
  $output = '';
337
- foreach ( $rows as $row )
338
  $output .= $this->table_row( $row, $formdata );
 
339
 
340
  $output = $this->table_wrap( $output );
341
 
@@ -343,19 +379,19 @@ abstract class scbAdminPage {
343
  }
344
 
345
  /**
346
- * Generates a table row
347
  *
348
  * @param array $args
349
- * @param array|boolean $formdata
350
  *
351
  * @return string
352
  */
353
- function table_row( $args, $formdata = false ) {
354
  return $this->row_wrap( $args['title'], $this->input( $args, $formdata ) );
355
  }
356
 
357
  /**
358
- * Mimic scbForms inheritance
359
  *
360
  * @see scbForms
361
  *
@@ -364,37 +400,39 @@ abstract class scbAdminPage {
364
  *
365
  * @return mixed
366
  */
367
- function __call( $method, $args ) {
368
  if ( in_array( $method, array( 'input', 'form' ) ) ) {
369
- if ( empty( $args[1] ) && isset( $this->options ) )
370
  $args[1] = $this->options->get();
 
371
 
372
- if ( 'form' == $method )
373
  $args[2] = $this->nonce;
 
374
  }
375
 
376
  return call_user_func_array( array( 'scbForms', $method ), $args );
377
  }
378
 
379
  /**
380
- * Wraps a string in a <script> tag
381
  *
382
  * @param string $string
383
  *
384
  * @return string
385
  */
386
- function js_wrap( $string ) {
387
  return html( "script type='text/javascript'", $string );
388
  }
389
 
390
  /**
391
- * Wraps a string in a <style> tag
392
  *
393
  * @param string $string
394
  *
395
  * @return string
396
  */
397
- function css_wrap( $string ) {
398
  return html( "style type='text/css'", $string );
399
  }
400
 
@@ -403,9 +441,11 @@ abstract class scbAdminPage {
403
 
404
 
405
  /**
406
- * Registers a page
 
 
407
  */
408
- function page_init() {
409
 
410
  if ( ! $this->args['toplevel'] ) {
411
  $this->pagehook = add_submenu_page(
@@ -438,21 +478,33 @@ abstract class scbAdminPage {
438
  );
439
  }
440
 
441
- if ( ! $this->pagehook )
442
  return;
 
443
 
444
  add_action( 'load-' . $this->pagehook, array( $this, 'page_loaded' ) );
445
 
446
  add_action( 'admin_print_styles-' . $this->pagehook, array( $this, 'page_head' ) );
447
  }
448
 
449
- function option_init() {
 
 
 
 
 
450
  register_setting( $this->option_name, $this->option_name, array( $this, 'validate' ) );
451
  }
452
 
 
 
 
 
 
453
  private function check_args() {
454
- if ( empty( $this->args['page_title'] ) )
455
  trigger_error( 'Page title cannot be empty', E_USER_WARNING );
 
456
 
457
  $this->args = wp_parse_args( $this->args, array(
458
  'toplevel' => '',
@@ -468,46 +520,60 @@ abstract class scbAdminPage {
468
  'admin_action_priority' => 10,
469
  ) );
470
 
471
- if ( empty( $this->args['submenu_title'] ) )
472
  $this->args['submenu_title'] = $this->args['menu_title'];
 
473
 
474
- if ( empty( $this->args['page_slug'] ) )
475
  $this->args['page_slug'] = sanitize_title_with_dashes( $this->args['menu_title'] );
 
476
 
477
- if ( empty( $this->args['nonce'] ) )
478
  $this->nonce = $this->args['page_slug'];
 
479
  }
480
 
481
  /**
 
 
482
  * @param string $help
483
  * @param string|object $screen
484
  *
485
  * @return string
486
  */
487
- function _contextual_help( $help, $screen ) {
488
- if ( is_object( $screen ) )
489
  $screen = $screen->id;
 
490
 
491
  $actual_help = $this->page_help();
492
 
493
- if ( $screen == $this->pagehook && $actual_help )
494
  return $actual_help;
 
495
 
496
  return $help;
497
  }
498
 
499
- function _page_content_hook() {
 
 
 
 
 
500
  $this->page_header();
501
  $this->page_content();
502
  $this->page_footer();
503
  }
504
 
505
  /**
 
 
506
  * @param array $links
507
  *
508
  * @return array
509
  */
510
- function _action_link( $links ) {
511
  $url = add_query_arg( 'page', $this->args['page_slug'], admin_url( $this->args['parent'] ) );
512
 
513
  $links[] = html_link( $url, $this->args['action_link'] );
1
  <?php
 
2
  /**
3
+ * Administration page base class.
4
  */
5
  abstract class scbAdminPage {
6
  /** Page args
42
  private static $registered = array();
43
 
44
  /**
45
+ * Registers class of page.
46
+ *
47
+ * @param string $class
48
+ * @param string $file
49
+ * @param object $options (optional) A scbOptions object.
50
  *
51
  * @return bool
52
  */
53
+ public static function register( $class, $file, $options = null ) {
54
+ if ( isset( self::$registered[ $class ] ) ) {
55
  return false;
56
+ }
57
 
58
+ self::$registered[ $class ] = array( $file, $options );
59
 
60
  add_action( '_admin_menu', array( __CLASS__, '_pages_init' ) );
61
 
63
  }
64
 
65
  /**
66
+ * Replaces class of page.
67
+ *
68
  * @param string $old_class
69
  * @param string $new_class
70
  *
71
  * @return bool
72
  */
73
+ public static function replace( $old_class, $new_class ) {
74
+ if ( ! isset( self::$registered[ $old_class ] ) ) {
75
  return false;
76
+ }
77
 
78
+ self::$registered[ $new_class ] = self::$registered[ $old_class ];
79
+ unset( self::$registered[ $old_class ] );
80
 
81
  return true;
82
  }
83
 
84
  /**
85
+ * Removes class of page.
86
+ *
87
  * @param string $class
88
  *
89
  * @return bool
90
  */
91
+ public static function remove( $class ) {
92
+ if ( ! isset( self::$registered[ $class ] ) ) {
93
  return false;
94
+ }
95
 
96
+ unset( self::$registered[ $class ] );
97
 
98
  return true;
99
  }
100
 
101
+ /**
102
+ * Instantiates classes of pages.
103
+ *
104
+ * @return void
105
+ */
106
+ public static function _pages_init() {
107
+ foreach ( self::$registered as $class => $args ) {
108
  new $class( $args[0], $args[1] );
109
+ }
110
  }
111
 
112
 
114
 
115
 
116
  /**
117
+ * Constructor.
118
  *
119
+ * @param string|bool $file (optional)
120
+ * @param object $options (optional) A scbOptions object.
121
+ *
122
+ * @return void
123
  */
124
+ public function __construct( $file = false, $options = null ) {
125
+ if ( is_a( $options, 'scbOptions' ) ) {
126
  $this->options = $options;
127
+ }
128
 
129
  $this->setup();
130
  $this->check_args();
141
  $this->file = $file;
142
  $this->plugin_url = plugin_dir_url( $file );
143
 
144
+ if ( $this->args['action_link'] ) {
145
  add_filter( 'plugin_action_links_' . plugin_basename( $file ), array( $this, '_action_link' ) );
146
+ }
147
  }
148
  }
149
 
150
  /**
151
+ * This is where all the page args can be set.
152
+ *
153
+ * @return void
154
  */
155
+ protected function setup() { }
156
 
157
  /**
158
  * Called when the page is loaded, but before any rendering.
 
159
  * Useful for calling $screen->add_help_tab() etc.
160
+ *
161
+ * @return void
162
  */
163
+ public function page_loaded() {
164
  $this->form_handler();
165
  }
166
 
167
  /**
168
+ * This is where the css and js go.
169
+ * Both wp_enqueue_*() and inline code can be added.
170
+ *
171
+ * @return void
172
  */
173
+ public function page_head() { }
174
 
175
  /**
176
+ * This is where the contextual help goes.
177
+ *
178
  * @return string
179
  */
180
+ protected function page_help() { }
181
 
182
  /**
183
+ * A generic page header.
184
+ *
185
+ * @return void
186
  */
187
+ protected function page_header() {
188
  echo "<div class='wrap'>\n";
189
  screen_icon( $this->args['screen_icon'] );
190
  echo html( 'h2', $this->args['page_title'] );
191
  }
192
 
193
  /**
194
+ * This is where the page content goes.
195
+ *
196
+ * @return void
197
  */
198
+ abstract protected function page_content();
199
 
200
  /**
201
+ * A generic page footer.
202
+ *
203
+ * @return void
204
  */
205
+ protected function page_footer() {
206
  echo "</div>\n";
207
  }
208
 
209
  /**
210
+ * This is where the form data should be validated.
211
  *
212
  * @param array $new_data
213
  * @param array $old_data
214
  *
215
  * @return array
216
  */
217
+ public function validate( $new_data, $old_data ) {
218
  return $new_data;
219
  }
220
 
221
  /**
222
+ * Manually handle option saving ( use Settings API instead ).
223
  *
224
  * @return bool
225
  */
226
+ protected function form_handler() {
227
+ if ( empty( $_POST['submit'] ) && empty( $_POST['action'] ) ) {
228
  return false;
229
+ }
230
 
231
  check_admin_referer( $this->nonce );
232
 
233
+ if ( ! isset( $this->options ) ) {
234
  trigger_error( 'options handler not set', E_USER_WARNING );
235
  return false;
236
  }
249
  }
250
 
251
  /**
252
+ * Manually generate a standard admin notice ( use Settings API instead ).
253
  *
254
+ * @param string $msg (optional)
255
+ * @param string $class (optional)
256
+ *
257
+ * @return void
258
  */
259
+ public function admin_msg( $msg = '', $class = 'updated' ) {
260
+ if ( empty( $msg ) ) {
261
  $msg = __( 'Settings <strong>saved</strong>.', $this->textdomain );
262
+ }
263
 
264
  echo scb_admin_notice( $msg, $class );
265
  }
269
 
270
 
271
  /**
272
+ * Generates a form submit button.
273
  *
274
+ * @param string|array $value (optional) Button text or array of arguments.
275
+ * @param string $action (optional)
276
+ * @param string $class (optional)
277
  *
278
  * @return string
279
  */
280
+ public function submit_button( $value = '', $action = 'submit', $class = 'button' ) {
281
 
282
  $args = is_array( $value ) ? $value : compact( 'value', 'action', 'class' );
283
  $args = wp_parse_args( $args, array(
305
  * @see scbForms::form_wrap()
306
  *
307
  * @param string $content
308
+ * @param boolean|string|array $submit_button (optional)
309
  *
310
  * @return string
311
  */
312
+ public function form_wrap( $content, $submit_button = true ) {
313
  if ( is_array( $submit_button ) ) {
314
  $content .= $this->submit_button( $submit_button );
315
+ } else if ( true === $submit_button ) {
316
  $content .= $this->submit_button();
317
+ } else if ( false !== strpos( $submit_button, '<input' ) ) {
318
  $content .= $submit_button;
319
+ } else if ( false !== strpos( $submit_button, '<button' ) ) {
320
  $content .= $submit_button;
321
+ } else if ( false !== $submit_button ) {
322
  $button_args = array_slice( func_get_args(), 1 );
323
  $content .= call_user_func_array( array( $this, 'submit_button' ), $button_args );
324
  }
327
  }
328
 
329
  /**
330
+ * Generates a table wrapped in a form.
331
  *
332
  * @param array $rows
333
+ * @param array|boolean $formdata (optional)
334
  *
335
  * @return string
336
  */
337
+ public function form_table( $rows, $formdata = false ) {
338
  $output = '';
339
+ foreach ( $rows as $row ) {
340
  $output .= $this->table_row( $row, $formdata );
341
+ }
342
 
343
  $output = $this->form_table_wrap( $output );
344
 
352
  *
353
  * @return string
354
  */
355
+ public function form_table_wrap( $content ) {
356
  $output = $this->table_wrap( $content );
357
  $output = $this->form_wrap( $output );
358
 
360
  }
361
 
362
  /**
363
+ * Generates a form table.
364
  *
365
  * @param array $rows
366
+ * @param array|boolean $formdata (optional)
367
  *
368
  * @return string
369
  */
370
+ public function table( $rows, $formdata = false ) {
371
  $output = '';
372
+ foreach ( $rows as $row ) {
373
  $output .= $this->table_row( $row, $formdata );
374
+ }
375
 
376
  $output = $this->table_wrap( $output );
377
 
379
  }
380
 
381
  /**
382
+ * Generates a table row.
383
  *
384
  * @param array $args
385
+ * @param array|boolean $formdata (optional)
386
  *
387
  * @return string
388
  */
389
+ public function table_row( $args, $formdata = false ) {
390
  return $this->row_wrap( $args['title'], $this->input( $args, $formdata ) );
391
  }
392
 
393
  /**
394
+ * Mimic scbForms inheritance.
395
  *
396
  * @see scbForms
397
  *
400
  *
401
  * @return mixed
402
  */
403
+ public function __call( $method, $args ) {
404
  if ( in_array( $method, array( 'input', 'form' ) ) ) {
405
+ if ( empty( $args[1] ) && isset( $this->options ) ) {
406
  $args[1] = $this->options->get();
407
+ }
408
 
409
+ if ( 'form' == $method ) {
410
  $args[2] = $this->nonce;
411
+ }
412
  }
413
 
414
  return call_user_func_array( array( 'scbForms', $method ), $args );
415
  }
416
 
417
  /**
418
+ * Wraps a string in a <script> tag.
419
  *
420
  * @param string $string
421
  *
422
  * @return string
423
  */
424
+ public function js_wrap( $string ) {
425
  return html( "script type='text/javascript'", $string );
426
  }
427
 
428
  /**
429
+ * Wraps a string in a <style> tag.
430
  *
431
  * @param string $string
432
  *
433
  * @return string
434
  */
435
+ public function css_wrap( $string ) {
436
  return html( "style type='text/css'", $string );
437
  }
438
 
441
 
442
 
443
  /**
444
+ * Registers a page.
445
+ *
446
+ * @return void
447
  */
448
+ public function page_init() {
449
 
450
  if ( ! $this->args['toplevel'] ) {
451
  $this->pagehook = add_submenu_page(
478
  );
479
  }
480
 
481
+ if ( ! $this->pagehook ) {
482
  return;
483
+ }
484
 
485
  add_action( 'load-' . $this->pagehook, array( $this, 'page_loaded' ) );
486
 
487
  add_action( 'admin_print_styles-' . $this->pagehook, array( $this, 'page_head' ) );
488
  }
489
 
490
+ /**
491
+ * Registers a option.
492
+ *
493
+ * @return void
494
+ */
495
+ public function option_init() {
496
  register_setting( $this->option_name, $this->option_name, array( $this, 'validate' ) );
497
  }
498
 
499
+ /**
500
+ * Checks page args.
501
+ *
502
+ * @return void
503
+ */
504
  private function check_args() {
505
+ if ( empty( $this->args['page_title'] ) ) {
506
  trigger_error( 'Page title cannot be empty', E_USER_WARNING );
507
+ }
508
 
509
  $this->args = wp_parse_args( $this->args, array(
510
  'toplevel' => '',
520
  'admin_action_priority' => 10,
521
  ) );
522
 
523
+ if ( empty( $this->args['submenu_title'] ) ) {
524
  $this->args['submenu_title'] = $this->args['menu_title'];
525
+ }
526
 
527
+ if ( empty( $this->args['page_slug'] ) ) {
528
  $this->args['page_slug'] = sanitize_title_with_dashes( $this->args['menu_title'] );
529
+ }
530
 
531
+ if ( empty( $this->args['nonce'] ) ) {
532
  $this->nonce = $this->args['page_slug'];
533
+ }
534
  }
535
 
536
  /**
537
+ * Adds contextual help.
538
+ *
539
  * @param string $help
540
  * @param string|object $screen
541
  *
542
  * @return string
543
  */
544
+ public function _contextual_help( $help, $screen ) {
545
+ if ( is_object( $screen ) ) {
546
  $screen = $screen->id;
547
+ }
548
 
549
  $actual_help = $this->page_help();
550
 
551
+ if ( $screen == $this->pagehook && $actual_help ) {
552
  return $actual_help;
553
+ }
554
 
555
  return $help;
556
  }
557
 
558
+ /**
559
+ * Displays page content.
560
+ *
561
+ * @return void
562
+ */
563
+ public function _page_content_hook() {
564
  $this->page_header();
565
  $this->page_content();
566
  $this->page_footer();
567
  }
568
 
569
  /**
570
+ * Adds an action link.
571
+ *
572
  * @param array $links
573
  *
574
  * @return array
575
  */
576
+ public function _action_link( $links ) {
577
  $url = add_query_arg( 'page', $this->args['page_slug'], admin_url( $this->args['parent'] ) );
578
 
579
  $links[] = html_link( $url, $this->args['action_link'] );
scb/BoxesPage.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
-
3
- // Admin screen with metaboxes base class
4
-
5
  abstract class scbBoxesPage extends scbAdminPage {
6
  /*
7
  A box definition looks like this:
@@ -11,22 +11,41 @@ abstract class scbBoxesPage extends scbAdminPage {
11
  */
12
  protected $boxes = array();
13
 
14
- function __construct( $file = false, $options = null ) {
 
 
 
 
 
 
 
 
15
  parent::__construct( $file, $options );
16
 
17
  scbUtil::add_uninstall_hook( $this->file, array( $this, 'uninstall' ) );
18
  }
19
 
20
- function page_init() {
21
- if ( !isset( $this->args['columns'] ) )
 
 
 
 
 
22
  $this->args['columns'] = 2;
 
23
 
24
  parent::page_init();
25
 
26
  add_action( 'load-' . $this->pagehook, array( $this, 'boxes_init' ) );
27
  }
28
 
29
- function default_css() {
 
 
 
 
 
30
  ?>
31
  <style type="text/css">
32
  .postbox-container + .postbox-container {
@@ -66,11 +85,20 @@ abstract class scbBoxesPage extends scbAdminPage {
66
  padding: 0 !important;
67
  margin-bottom: 0 !important;
68
  }
 
 
 
 
69
  </style>
70
  <?php
71
  }
72
 
73
- function page_content() {
 
 
 
 
 
74
  $this->default_css();
75
 
76
  global $screen_layout_columns;
@@ -79,29 +107,33 @@ abstract class scbBoxesPage extends scbAdminPage {
79
  $hide2 = $hide3 = $hide4 = '';
80
  switch ( $screen_layout_columns ) {
81
  case 4:
82
- if( !isset( $this->args['column_widths'] ) )
83
  $this->args['column_widths'] = array( 24.5, 24.5, 24.5, 24.5 );
 
84
  break;
85
  case 3:
86
- if( !isset( $this->args['column_widths'] ) )
87
  $this->args['column_widths'] = array( 32.67, 32.67, 32.67 );
 
88
  $hide4 = 'display:none;';
89
  break;
90
  case 2:
91
- if( !isset( $this->args['column_widths'] ) )
92
  $this->args['column_widths'] = array( 49, 49 );
 
93
  $hide3 = $hide4 = 'display:none;';
94
  break;
95
  default:
96
- if( !isset( $this->args['column_widths'] ) )
97
  $this->args['column_widths'] = array( 98 );
 
98
  $hide2 = $hide3 = $hide4 = 'display:none;';
99
  }
100
 
101
  $this->args['column_widths'] = array_pad( $this->args['column_widths'], 4, 0 );
102
  }
103
  ?>
104
- <div id='<?php echo $this->pagehook ?>-widgets' class='metabox-holder'>
105
  <?php
106
  echo "\t<div class='postbox-container' style='width:{$this->args['column_widths'][0]}%'>\n";
107
  do_meta_boxes( $this->pagehook, 'normal', '' );
@@ -119,14 +151,25 @@ abstract class scbBoxesPage extends scbAdminPage {
119
  <?php
120
  }
121
 
122
- function page_footer() {
 
 
 
 
 
123
  parent::page_footer();
124
  $this->_boxes_js_init();
125
  }
126
 
127
- function form_handler() {
128
- if ( empty( $_POST ) )
 
 
 
 
 
129
  return;
 
130
 
131
  check_admin_referer( $this->nonce );
132
 
@@ -136,18 +179,25 @@ abstract class scbBoxesPage extends scbAdminPage {
136
 
137
  $handler = $box[0] . '_handler';
138
 
139
- if ( method_exists( $this, $handler ) )
140
  call_user_func_array( array( $this, $handler ), $args );
 
141
  }
142
  }
143
 
144
- function uninstall() {
 
 
 
 
 
145
  global $wpdb;
146
 
147
  $hook = str_replace( '-', '', $this->pagehook );
148
 
149
- foreach ( array( 'metaboxhidden', 'closedpostboxes', 'wp_metaboxorder', 'screen_layout' ) as $option )
150
  $keys[] = "'{$option}_{$hook}'";
 
151
 
152
  $keys = '( ' . implode( ', ', $keys ) . ' )';
153
 
@@ -157,7 +207,12 @@ abstract class scbBoxesPage extends scbAdminPage {
157
  " );
158
  }
159
 
160
- function boxes_init() {
 
 
 
 
 
161
  wp_enqueue_script( 'postbox' );
162
 
163
  add_screen_option( 'layout_columns', array(
@@ -202,37 +257,65 @@ abstract class scbBoxesPage extends scbAdminPage {
202
  }
203
  }
204
 
 
 
 
 
 
 
 
 
205
  private static function numeric_to_assoc( $argv, $keys ) {
206
  $args = array();
207
 
208
  foreach ( $keys as $i => $key ) {
209
- if ( isset( $argv[ $i ] ) )
210
  $args[ $key ] = $argv[ $i ];
 
211
  }
212
 
213
  return $args;
214
  }
215
 
216
- // Since we don't pass an object to do_meta_boxes(),
217
- // pass $box['args'] directly to each method.
218
- function _intermediate_callback( $_, $box ) {
 
 
 
 
 
 
 
219
  list( $name ) = explode( '-', $box['id'] );
220
 
221
  call_user_func_array( array( $this, $name . '_box' ), $box['args'] );
222
  }
223
 
 
 
 
 
 
 
 
224
  private function _increment( $name ) {
225
  $parts = explode( '-', $name );
226
- if ( isset( $parts[1] ) )
227
  $parts[1]++;
228
- else
229
  $parts[1] = 2;
 
230
 
231
  return implode( '-', $parts );
232
  }
233
 
234
- // Adds necesary code for JS to work
235
- function _boxes_js_init() {
 
 
 
 
236
  echo $this->js_wrap( <<<EOT
237
  jQuery( document ).ready( function( $ ){
238
  // close postboxes that should be closed
@@ -256,5 +339,3 @@ EOT
256
  }
257
  }
258
 
259
-
260
-
1
  <?php
2
+ /**
3
+ * Admin screen with metaboxes base class.
4
+ */
5
  abstract class scbBoxesPage extends scbAdminPage {
6
  /*
7
  A box definition looks like this:
11
  */
12
  protected $boxes = array();
13
 
14
+ /**
15
+ * Constructor.
16
+ *
17
+ * @param string|bool $file (optional)
18
+ * @param object $options (optional) A scbOptions object.
19
+ *
20
+ * @return void
21
+ */
22
+ public function __construct( $file = false, $options = null ) {
23
  parent::__construct( $file, $options );
24
 
25
  scbUtil::add_uninstall_hook( $this->file, array( $this, 'uninstall' ) );
26
  }
27
 
28
+ /**
29
+ * Registers a page.
30
+ *
31
+ * @return void
32
+ */
33
+ public function page_init() {
34
+ if ( ! isset( $this->args['columns'] ) ) {
35
  $this->args['columns'] = 2;
36
+ }
37
 
38
  parent::page_init();
39
 
40
  add_action( 'load-' . $this->pagehook, array( $this, 'boxes_init' ) );
41
  }
42
 
43
+ /**
44
+ * Prints default CSS styles.
45
+ *
46
+ * @return void
47
+ */
48
+ protected function default_css() {
49
  ?>
50
  <style type="text/css">
51
  .postbox-container + .postbox-container {
85
  padding: 0 !important;
86
  margin-bottom: 0 !important;
87
  }
88
+ .meta-box-sortables {
89
+ min-height: 100px;
90
+ width: 100%;
91
+ }
92
  </style>
93
  <?php
94
  }
95
 
96
+ /**
97
+ * Displays page content.
98
+ *
99
+ * @return void
100
+ */
101
+ protected function page_content() {
102
  $this->default_css();
103
 
104
  global $screen_layout_columns;
107
  $hide2 = $hide3 = $hide4 = '';
108
  switch ( $screen_layout_columns ) {
109
  case 4:
110
+ if ( ! isset( $this->args['column_widths'] ) ) {
111
  $this->args['column_widths'] = array( 24.5, 24.5, 24.5, 24.5 );
112
+ }
113
  break;
114
  case 3:
115
+ if ( ! isset( $this->args['column_widths'] ) ) {
116
  $this->args['column_widths'] = array( 32.67, 32.67, 32.67 );
117
+ }
118
  $hide4 = 'display:none;';
119
  break;
120
  case 2:
121
+ if ( ! isset( $this->args['column_widths'] ) ) {
122
  $this->args['column_widths'] = array( 49, 49 );
123
+ }
124
  $hide3 = $hide4 = 'display:none;';
125
  break;
126
  default:
127
+ if ( ! isset( $this->args['column_widths'] ) ) {
128
  $this->args['column_widths'] = array( 98 );
129
+ }
130
  $hide2 = $hide3 = $hide4 = 'display:none;';
131
  }
132
 
133
  $this->args['column_widths'] = array_pad( $this->args['column_widths'], 4, 0 );
134
  }
135
  ?>
136
+ <div id='<?php echo $this->pagehook; ?>-widgets' class='metabox-holder'>
137
  <?php
138
  echo "\t<div class='postbox-container' style='width:{$this->args['column_widths'][0]}%'>\n";
139
  do_meta_boxes( $this->pagehook, 'normal', '' );
151
  <?php
152
  }
153
 
154
+ /**
155
+ * Displays page footer.
156
+ *
157
+ * @return void
158
+ */
159
+ protected function page_footer() {
160
  parent::page_footer();
161
  $this->_boxes_js_init();
162
  }
163
 
164
+ /**
165
+ * Handles option saving.
166
+ *
167
+ * @return void
168
+ */
169
+ protected function form_handler() {
170
+ if ( empty( $_POST ) ) {
171
  return;
172
+ }
173
 
174
  check_admin_referer( $this->nonce );
175
 
179
 
180
  $handler = $box[0] . '_handler';
181
 
182
+ if ( method_exists( $this, $handler ) ) {
183
  call_user_func_array( array( $this, $handler ), $args );
184
+ }
185
  }
186
  }
187
 
188
+ /**
189
+ * Uninstalls boxes.
190
+ *
191
+ * @return void
192
+ */
193
+ public function uninstall() {
194
  global $wpdb;
195
 
196
  $hook = str_replace( '-', '', $this->pagehook );
197
 
198
+ foreach ( array( 'metaboxhidden', 'closedpostboxes', 'wp_metaboxorder', 'screen_layout' ) as $option ) {
199
  $keys[] = "'{$option}_{$hook}'";
200
+ }
201
 
202
  $keys = '( ' . implode( ', ', $keys ) . ' )';
203
 
207
  " );
208
  }
209
 
210
+ /**
211
+ * Adds boxes.
212
+ *
213
+ * @return void
214
+ */
215
+ public function boxes_init() {
216
  wp_enqueue_script( 'postbox' );
217
 
218
  add_screen_option( 'layout_columns', array(
257
  }
258
  }
259
 
260
+ /**
261
+ * Transforms numeric array to associative.
262
+ *
263
+ * @param array $argv
264
+ * @param array $keys
265
+ *
266
+ * @return array
267
+ */
268
  private static function numeric_to_assoc( $argv, $keys ) {
269
  $args = array();
270
 
271
  foreach ( $keys as $i => $key ) {
272
+ if ( isset( $argv[ $i ] ) ) {
273
  $args[ $key ] = $argv[ $i ];
274
+ }
275
  }
276
 
277
  return $args;
278
  }
279
 
280
+ /**
281
+ * Since we don't pass an object to do_meta_boxes(),
282
+ * pass $box['args'] directly to each method.
283
+ *
284
+ * @param string $_
285
+ * @param array $box
286
+ *
287
+ * @return void
288
+ */
289
+ public function _intermediate_callback( $_, $box ) {
290
  list( $name ) = explode( '-', $box['id'] );
291
 
292
  call_user_func_array( array( $this, $name . '_box' ), $box['args'] );
293
  }
294
 
295
+ /**
296
+ * Adds/Increments ID in box name.
297
+ *
298
+ * @param string $name
299
+ *
300
+ * @return string
301
+ */
302
  private function _increment( $name ) {
303
  $parts = explode( '-', $name );
304
+ if ( isset( $parts[1] ) ) {
305
  $parts[1]++;
306
+ } else {
307
  $parts[1] = 2;
308
+ }
309
 
310
  return implode( '-', $parts );
311
  }
312
 
313
+ /**
314
+ * Adds necesary code for JS to work.
315
+ *
316
+ * @return void
317
+ */
318
+ protected function _boxes_js_init() {
319
  echo $this->js_wrap( <<<EOT
320
  jQuery( document ).ready( function( $ ){
321
  // close postboxes that should be closed
339
  }
340
  }
341
 
 
 
scb/Cron.php CHANGED
@@ -1,7 +1,6 @@
1
  <?php
2
-
3
  /**
4
- * wp-cron job container
5
  */
6
  class scbCron {
7
  protected $schedule;
@@ -12,19 +11,22 @@ class scbCron {
12
  protected $callback_args = array();
13
 
14
  /**
15
- * Create a new cron job
16
  *
17
- * @param string|bool $file Reference to main plugin file
18
  * @param array $args List of args:
19
  * string $action OR callback $callback
20
  * string $schedule OR number $interval
21
  * array $callback_args (optional)
 
 
22
  */
23
- function __construct( $file = false, $args ) {
24
 
25
  // Set time & schedule
26
- if ( isset( $args['time'] ) )
27
  $this->time = $args['time'];
 
28
 
29
  if ( isset( $args['interval'] ) ) {
30
  $this->schedule = $args['interval'] . 'secs';
@@ -36,18 +38,19 @@ class scbCron {
36
  // Set hook
37
  if ( isset( $args['action'] ) ) {
38
  $this->hook = $args['action'];
39
- } elseif ( isset( $args['callback'] ) ) {
40
  $this->hook = self::_callback_to_string( $args['callback'] );
41
  add_action( $this->hook, $args['callback'] );
42
- } elseif ( method_exists( $this, 'callback' ) ) {
43
  $this->hook = self::_callback_to_string( array( $this, 'callback' ) );
44
  add_action( $this->hook, $args['callback'] );
45
  } else {
46
  trigger_error( '$action OR $callback not set', E_USER_WARNING );
47
  }
48
 
49
- if ( isset( $args['callback_args'] ) )
50
  $this->callback_args = (array) $args['callback_args'];
 
51
 
52
  if ( $file && $this->schedule ) {
53
  scbUtil::add_activation_hook( $file, array( $this, 'reset' ) );
@@ -58,13 +61,15 @@ class scbCron {
58
  }
59
 
60
  /**
61
- * Change the interval of the cron job
62
  *
63
  * @param array $args List of args:
64
  * string $schedule OR number $interval
65
  * timestamp $time ( optional )
 
 
66
  */
67
- function reschedule( $args ) {
68
 
69
  if ( $args['schedule'] && $this->schedule != $args['schedule'] ) {
70
  $this->schedule = $args['schedule'];
@@ -79,40 +84,52 @@ class scbCron {
79
  }
80
 
81
  /**
82
- * Reset the schedule
 
 
83
  */
84
- function reset() {
85
  $this->unschedule();
86
  $this->schedule();
87
  }
88
 
89
  /**
90
- * Clear the cron job
 
 
91
  */
92
- function unschedule() {
93
  # wp_clear_scheduled_hook( $this->hook, $this->callback_args );
94
  self::really_clear_scheduled_hook( $this->hook );
95
  }
96
 
97
  /**
98
- * Execute the job now
99
- * @param array $args List of arguments to pass to the callback
 
 
 
100
  */
101
- function do_now( $args = null ) {
102
- if ( is_null( $args ) )
103
  $args = $this->callback_args;
 
104
 
105
  do_action_ref_array( $this->hook, $args );
106
  }
107
 
108
  /**
109
- * Execute the job with a given delay
110
- * @param int $delay in seconds
111
- * @param array $args List of arguments to pass to the callback
 
 
 
112
  */
113
- function do_once( $delay = 0, $args = null ) {
114
- if ( is_null( $args ) )
115
  $args = $this->callback_args;
 
116
 
117
  wp_clear_scheduled_hook( $this->hook, $args );
118
  wp_schedule_single_event( time() + $delay, $this->hook, $args );
@@ -122,15 +139,18 @@ class scbCron {
122
  //_____INTERNAL METHODS_____
123
 
124
  /**
 
 
125
  * @param array $schedules
126
  *
127
  * @return array
128
  */
129
- function _add_timing( $schedules ) {
130
- if ( isset( $schedules[$this->schedule] ) )
131
  return $schedules;
 
132
 
133
- $schedules[$this->schedule] = array(
134
  'interval' => $this->interval,
135
  'display' => $this->interval . ' seconds',
136
  );
@@ -138,43 +158,59 @@ class scbCron {
138
  return $schedules;
139
  }
140
 
 
 
 
 
 
141
  protected function schedule() {
142
- if ( ! $this->time )
143
  $this->time = time();
 
144
 
145
  wp_schedule_event( $this->time, $this->schedule, $this->hook, $this->callback_args );
146
  }
147
 
148
  /**
 
 
149
  * @param string $name
 
 
150
  */
151
  protected static function really_clear_scheduled_hook( $name ) {
152
  $crons = _get_cron_array();
153
 
154
  foreach ( $crons as $timestamp => $hooks ) {
155
- foreach ( $hooks as $hook => $args )
156
- if ( $hook == $name )
157
- unset( $crons[$timestamp][$hook] );
158
-
159
- if ( empty( $crons[$timestamp] ) )
160
- unset( $crons[$timestamp] );
 
 
 
161
  }
162
 
163
  _set_cron_array( $crons );
164
  }
165
 
166
  /**
 
 
167
  * @param callback $callback
168
  *
169
  * @return string
170
  */
171
  protected static function _callback_to_string( $callback ) {
172
- if ( ! is_array( $callback ) )
173
  $str = $callback;
174
- elseif ( ! is_string( $callback[0] ) )
175
  $str = get_class( $callback[0] ) . '_' . $callback[1];
176
- else
177
  $str = $callback[0] . '::' . $callback[1];
 
178
 
179
  $str .= '_hook';
180
 
1
  <?php
 
2
  /**
3
+ * WP Cron job container.
4
  */
5
  class scbCron {
6
  protected $schedule;
11
  protected $callback_args = array();
12
 
13
  /**
14
+ * Create a new cron job.
15
  *
16
+ * @param string|bool $file (optional) Reference to main plugin file
17
  * @param array $args List of args:
18
  * string $action OR callback $callback
19
  * string $schedule OR number $interval
20
  * array $callback_args (optional)
21
+ *
22
+ * @return void
23
  */
24
+ public function __construct( $file = false, $args ) {
25
 
26
  // Set time & schedule
27
+ if ( isset( $args['time'] ) ) {
28
  $this->time = $args['time'];
29
+ }
30
 
31
  if ( isset( $args['interval'] ) ) {
32
  $this->schedule = $args['interval'] . 'secs';
38
  // Set hook
39
  if ( isset( $args['action'] ) ) {
40
  $this->hook = $args['action'];
41
+ } else if ( isset( $args['callback'] ) ) {
42
  $this->hook = self::_callback_to_string( $args['callback'] );
43
  add_action( $this->hook, $args['callback'] );
44
+ } else if ( method_exists( $this, 'callback' ) ) {
45
  $this->hook = self::_callback_to_string( array( $this, 'callback' ) );
46
  add_action( $this->hook, $args['callback'] );
47
  } else {
48
  trigger_error( '$action OR $callback not set', E_USER_WARNING );
49
  }
50
 
51
+ if ( isset( $args['callback_args'] ) ) {
52
  $this->callback_args = (array) $args['callback_args'];
53
+ }
54
 
55
  if ( $file && $this->schedule ) {
56
  scbUtil::add_activation_hook( $file, array( $this, 'reset' ) );
61
  }
62
 
63
  /**
64
+ * Change the interval of the cron job.
65
  *
66
  * @param array $args List of args:
67
  * string $schedule OR number $interval
68
  * timestamp $time ( optional )
69
+ *
70
+ * @return void
71
  */
72
+ public function reschedule( $args ) {
73
 
74
  if ( $args['schedule'] && $this->schedule != $args['schedule'] ) {
75
  $this->schedule = $args['schedule'];
84
  }
85
 
86
  /**
87
+ * Reset the schedule.
88
+ *
89
+ * @return void
90
  */
91
+ public function reset() {
92
  $this->unschedule();
93
  $this->schedule();
94
  }
95
 
96
  /**
97
+ * Clear the cron job.
98
+ *
99
+ * @return void
100
  */
101
+ public function unschedule() {
102
  # wp_clear_scheduled_hook( $this->hook, $this->callback_args );
103
  self::really_clear_scheduled_hook( $this->hook );
104
  }
105
 
106
  /**
107
+ * Execute the job now.
108
+ *
109
+ * @param array $args (optional) List of arguments to pass to the callback.
110
+ *
111
+ * @return void
112
  */
113
+ public function do_now( $args = null ) {
114
+ if ( is_null( $args ) ) {
115
  $args = $this->callback_args;
116
+ }
117
 
118
  do_action_ref_array( $this->hook, $args );
119
  }
120
 
121
  /**
122
+ * Execute the job with a given delay.
123
+ *
124
+ * @param int $delay (optional) Delay in seconds.
125
+ * @param array $args (optional) List of arguments to pass to the callback.
126
+ *
127
+ * @return void
128
  */
129
+ public function do_once( $delay = 0, $args = null ) {
130
+ if ( is_null( $args ) ) {
131
  $args = $this->callback_args;
132
+ }
133
 
134
  wp_clear_scheduled_hook( $this->hook, $args );
135
  wp_schedule_single_event( time() + $delay, $this->hook, $args );
139
  //_____INTERNAL METHODS_____
140
 
141
  /**
142
+ * Adds custom schedule timing.
143
+ *
144
  * @param array $schedules
145
  *
146
  * @return array
147
  */
148
+ public function _add_timing( $schedules ) {
149
+ if ( isset( $schedules[ $this->schedule ] ) ) {
150
  return $schedules;
151
+ }
152
 
153
+ $schedules[ $this->schedule ] = array(
154
  'interval' => $this->interval,
155
  'display' => $this->interval . ' seconds',
156
  );
158
  return $schedules;
159
  }
160
 
161
+ /**
162
+ * Schedule the job.
163
+ *
164
+ * @return void
165
+ */
166
  protected function schedule() {
167
+ if ( ! $this->time ) {
168
  $this->time = time();
169
+ }
170
 
171
  wp_schedule_event( $this->time, $this->schedule, $this->hook, $this->callback_args );
172
  }
173
 
174
  /**
175
+ * Clears scheduled job.
176
+ *
177
  * @param string $name
178
+ *
179
+ * @return void
180
  */
181
  protected static function really_clear_scheduled_hook( $name ) {
182
  $crons = _get_cron_array();
183
 
184
  foreach ( $crons as $timestamp => $hooks ) {
185
+ foreach ( $hooks as $hook => $args ) {
186
+ if ( $hook == $name ) {
187
+ unset( $crons[ $timestamp ][ $hook ] );
188
+ }
189
+ }
190
+
191
+ if ( empty( $crons[ $timestamp ] ) ) {
192
+ unset( $crons[ $timestamp ] );
193
+ }
194
  }
195
 
196
  _set_cron_array( $crons );
197
  }
198
 
199
  /**
200
+ * Generates a hook name from given callback.
201
+ *
202
  * @param callback $callback
203
  *
204
  * @return string
205
  */
206
  protected static function _callback_to_string( $callback ) {
207
+ if ( ! is_array( $callback ) ) {
208
  $str = $callback;
209
+ } else if ( ! is_string( $callback[0] ) ) {
210
  $str = get_class( $callback[0] ) . '_' . $callback[1];
211
+ } else {
212
  $str = $callback[0] . '::' . $callback[1];
213
+ }
214
 
215
  $str .= '_hook';
216
 
scb/Forms.php CHANGED
@@ -1,48 +1,52 @@
1
  <?php
2
-
3
  /**
4
- * Data-aware form generator
5
  */
6
  class scbForms {
7
 
8
  const TOKEN = '%input%';
9
 
10
  /**
 
 
11
  * @param array|scbFormField_I $args
12
  * @param mixed $value
13
  *
14
  * @return string
15
  */
16
- static function input_with_value( $args, $value ) {
17
  $field = scbFormField::create( $args );
18
 
19
  return $field->render( $value );
20
  }
21
 
22
  /**
 
 
23
  * @param array|scbFormField_I $args
24
- * @param array $formdata
25
  *
26
  * @return string
27
  */
28
- static function input( $args, $formdata = null ) {
29
  $field = scbFormField::create( $args );
30
 
31
  return $field->render( scbForms::get_value( $args['name'], $formdata ) );
32
  }
33
 
34
  /**
35
- * Generates a table wrapped in a form
36
  *
37
  * @param array $rows
38
- * @param array $formdata
39
  *
40
  * @return string
41
  */
42
- static function form_table( $rows, $formdata = null ) {
43
  $output = '';
44
- foreach ( $rows as $row )
45
  $output .= self::table_row( $row, $formdata );
 
46
 
47
  $output = self::form_table_wrap( $output );
48
 
@@ -50,18 +54,19 @@ class scbForms {
50
  }
51
 
52
  /**
53
- * Generates a form
54
  *
55
  * @param array $inputs
56
- * @param array $formdata
57
  * @param string $nonce
58
  *
59
  * @return string
60
  */
61
- static function form( $inputs, $formdata = null, $nonce ) {
62
  $output = '';
63
- foreach ( $inputs as $input )
64
  $output .= self::input( $input, $formdata );
 
65
 
66
  $output = self::form_wrap( $output, $nonce );
67
 
@@ -69,17 +74,18 @@ class scbForms {
69
  }
70
 
71
  /**
72
- * Generates a table
73
  *
74
  * @param array $rows
75
- * @param array $formdata
76
  *
77
  * @return string
78
  */
79
- static function table( $rows, $formdata = null ) {
80
  $output = '';
81
- foreach ( $rows as $row )
82
  $output .= self::table_row( $row, $formdata );
 
83
 
84
  $output = self::table_wrap( $output );
85
 
@@ -87,14 +93,14 @@ class scbForms {
87
  }
88
 
89
  /**
90
- * Generates a table row
91
  *
92
  * @param array $args
93
- * @param array $formdata
94
  *
95
  * @return string
96
  */
97
- static function table_row( $args, $formdata = null ) {
98
  return self::row_wrap( $args['title'], self::input( $args, $formdata ) );
99
  }
100
 
@@ -102,22 +108,26 @@ class scbForms {
102
  // ____________WRAPPERS____________
103
 
104
  /**
 
 
105
  * @param string $content
106
- * @param string $nonce
107
  *
108
  * @return string
109
  */
110
- static function form_table_wrap( $content, $nonce = 'update_options' ) {
111
  return self::form_wrap( self::table_wrap( $content ), $nonce );
112
  }
113
 
114
  /**
 
 
115
  * @param string $content
116
- * @param string $nonce
117
  *
118
  * @return string
119
  */
120
- static function form_wrap( $content, $nonce = 'update_options' ) {
121
  return html( "form method='post' action=''",
122
  $content,
123
  wp_nonce_field( $nonce, '_wpnonce', $referer = true, $echo = false )
@@ -125,21 +135,25 @@ class scbForms {
125
  }
126
 
127
  /**
 
 
128
  * @param string $content
129
  *
130
  * @return string
131
  */
132
- static function table_wrap( $content ) {
133
  return html( "table class='form-table'", $content );
134
  }
135
 
136
  /**
 
 
137
  * @param string $title
138
  * @param string $content
139
  *
140
  * @return string
141
  */
142
- static function row_wrap( $title, $content ) {
143
  return html( 'tr',
144
  html( "th scope='row'", $title ),
145
  html( 'td', $content )
@@ -160,7 +174,7 @@ class scbForms {
160
  *
161
  * @return string
162
  */
163
- static function get_name( $name ) {
164
  $name = (array) $name;
165
 
166
  $name_str = array_shift( $name );
@@ -177,16 +191,17 @@ class scbForms {
177
  *
178
  * @param string $name The name of the value
179
  * @param array $value The data that will be traversed
180
- * @param mixed $fallback The value returned when the key is not found
181
  *
182
  * @return mixed
183
  */
184
- static function get_value( $name, $value, $fallback = null ) {
185
  foreach ( (array) $name as $key ) {
186
- if ( !isset( $value[ $key ] ) )
187
  return $fallback;
 
188
 
189
- $value = $value[$key];
190
  }
191
 
192
  return $value;
@@ -196,12 +211,12 @@ class scbForms {
196
  * Given a list of fields, validate some data.
197
  *
198
  * @param array $fields List of args that would be sent to scbForms::input()
199
- * @param array $data The data to validate. Defaults to $_POST
200
- * @param array $to_update Existing data to populate. Necessary for nested values
201
  *
202
  * @return array
203
  */
204
- static function validate_post_data( $fields, $data = null, $to_update = array() ) {
205
  if ( null === $data ) {
206
  $data = stripslashes_deep( $_POST );
207
  }
@@ -213,8 +228,9 @@ class scbForms {
213
 
214
  $value = $fieldObj->validate( $value );
215
 
216
- if ( null !== $value )
217
  self::set_value( $to_update, $field['name'], $value );
 
218
  }
219
 
220
  return $to_update;
@@ -227,11 +243,11 @@ class scbForms {
227
  *
228
  * @param array $args Field arguments.
229
  * @param int $object_id The object ID the metadata is attached to
230
- * @param string $meta_type
231
  *
232
  * @return string
233
  */
234
- static function input_from_meta( $args, $object_id, $meta_type = 'post' ) {
235
  $single = ( 'checkbox' != $args['type'] );
236
 
237
  $key = (array) $args['name'];
@@ -243,51 +259,63 @@ class scbForms {
243
  }
244
 
245
  /**
 
 
246
  * @param array $fields
247
  * @param array $data
248
- * @param int $object_id
249
- * @param string $meta_type
 
 
250
  */
251
- static function update_meta( $fields, $data, $object_id, $meta_type = 'post' ) {
252
  foreach ( $fields as $field_args ) {
253
  $key = $field_args['name'];
254
 
255
  if ( 'checkbox' == $field_args['type'] ) {
256
- $new_values = isset( $data[$key] ) ? $data[$key] : array();
257
 
258
  $old_values = get_metadata( $meta_type, $object_id, $key );
259
 
260
- foreach ( array_diff( $new_values, $old_values ) as $value )
261
  add_metadata( $meta_type, $object_id, $key, $value );
 
262
 
263
- foreach ( array_diff( $old_values, $new_values ) as $value )
264
  delete_metadata( $meta_type, $object_id, $key, $value );
 
265
  } else {
266
- $value = isset( $data[$key] ) ? $data[$key] : '';
267
 
268
- if ( '' === $value )
269
  delete_metadata( $meta_type, $object_id, $key );
270
- else
271
  update_metadata( $meta_type, $object_id, $key, $value );
 
272
  }
273
  }
274
  }
275
 
276
  /**
 
 
277
  * @param array $arr
278
  * @param string $name
279
  * @param mixed $value
 
 
280
  */
281
  private static function set_value( &$arr, $name, $value ) {
282
  $name = (array) $name;
283
 
284
  $final_key = array_pop( $name );
285
 
286
- while ( !empty( $name ) ) {
287
  $key = array_shift( $name );
288
 
289
- if ( !isset( $arr[ $key ] ) )
290
  $arr[ $key ] = array();
 
291
 
292
  $arr =& $arr[ $key ];
293
  }
@@ -298,30 +326,38 @@ class scbForms {
298
 
299
 
300
  /**
301
- * A wrapper for scbForms, containing the formdata
302
  */
303
  class scbForm {
304
  protected $data = array();
305
  protected $prefix = array();
306
 
307
  /**
 
 
308
  * @param array $data
309
- * @param string|boolean $prefix
 
 
310
  */
311
- function __construct( $data, $prefix = false ) {
312
- if ( is_array( $data ) )
313
  $this->data = $data;
 
314
 
315
- if ( $prefix )
316
  $this->prefix = (array) $prefix;
 
317
  }
318
 
319
  /**
 
 
320
  * @param string $path
321
  *
322
- * @return scbForm
323
  */
324
- function traverse_to( $path ) {
325
  $data = scbForms::get_value( $path, $this->data );
326
 
327
  $prefix = array_merge( $this->prefix, (array) $path );
@@ -330,14 +366,16 @@ class scbForm {
330
  }
331
 
332
  /**
 
 
333
  * @param array $args
334
  *
335
  * @return string
336
  */
337
- function input( $args ) {
338
  $value = scbForms::get_value( $args['name'], $this->data );
339
 
340
- if ( !empty( $this->prefix ) ) {
341
  $args['name'] = array_merge( $this->prefix, (array) $args['name'] );
342
  }
343
 
@@ -351,9 +389,9 @@ class scbForm {
351
  interface scbFormField_I {
352
 
353
  /**
354
- * Generate the corresponding HTML for a field
355
  *
356
- * @param mixed $value The value to use
357
  *
358
  * @return string
359
  */
@@ -362,7 +400,7 @@ interface scbFormField_I {
362
  /**
363
  * Validates a value against a field.
364
  *
365
- * @param mixed $value The value to check
366
  *
367
  * @return mixed null if the validation failed, sanitized value otherwise.
368
  */
@@ -377,13 +415,16 @@ abstract class scbFormField implements scbFormField_I {
377
  protected $args;
378
 
379
  /**
 
 
380
  * @param array|scbFormField_I $args
381
  *
382
  * @return mixed false on failure or instance of form class
383
  */
384
  public static function create( $args ) {
385
- if ( is_a( $args, 'scbFormField_I' ) )
386
  return $args;
 
387
 
388
  if ( empty( $args['name'] ) ) {
389
  return trigger_error( 'Empty name', E_USER_WARNING );
@@ -399,8 +440,9 @@ abstract class scbFormField implements scbFormField_I {
399
  unset( $args['values'] );
400
  }
401
 
402
- if ( isset( $args['extra'] ) && !is_array( $args['extra'] ) )
403
  $args['extra'] = shortcode_parse_atts( $args['extra'] );
 
404
 
405
  $args = wp_parse_args( $args, array(
406
  'desc' => '',
@@ -410,34 +452,42 @@ abstract class scbFormField implements scbFormField_I {
410
  ) );
411
 
412
  // depends on $args['desc']
413
- if ( isset( $args['choices'] ) )
414
  self::_expand_choices( $args );
 
415
 
416
  switch ( $args['type'] ) {
417
- case 'radio':
418
- return new scbRadiosField( $args );
419
- case 'select':
420
- return new scbSelectField( $args );
421
- case 'checkbox':
422
- if ( isset( $args['choices'] ) )
423
- return new scbMultipleChoiceField( $args );
424
- else
425
- return new scbSingleCheckboxField( $args );
426
- case 'custom':
427
- return new scbCustomField( $args );
428
- default:
429
- return new scbTextField( $args );
 
430
  }
431
  }
432
 
433
  /**
 
 
434
  * @param array $args
 
 
435
  */
436
  protected function __construct( $args ) {
437
  $this->args = $args;
438
  }
439
 
440
  /**
 
 
441
  * @param string $key
442
  *
443
  * @return mixed
@@ -447,6 +497,8 @@ abstract class scbFormField implements scbFormField_I {
447
  }
448
 
449
  /**
 
 
450
  * @param string $key
451
  *
452
  * @return bool
@@ -456,18 +508,22 @@ abstract class scbFormField implements scbFormField_I {
456
  }
457
 
458
  /**
459
- * @param mixed $value
 
 
460
  *
461
  * @return string
462
  */
463
  public function render( $value = null ) {
464
- if ( null === $value && isset( $this->default ) )
465
  $value = $this->default;
 
466
 
467
  $args = $this->args;
468
 
469
- if ( null !== $value )
470
  $this->_set_value( $args, $value );
 
471
 
472
  $args['name'] = scbForms::get_name( $args['name'] );
473
 
@@ -483,14 +539,14 @@ abstract class scbFormField implements scbFormField_I {
483
  abstract protected function _set_value( &$args, $value );
484
 
485
  /**
486
- * The actual rendering
487
  *
488
  * @param array $args
489
  */
490
  abstract protected function _render( $args );
491
 
492
  /**
493
- * Handle args for a single checkbox or radio input
494
  *
495
  * @param array $args
496
  *
@@ -506,14 +562,15 @@ abstract class scbFormField implements scbFormField_I {
506
 
507
  $args['extra']['checked'] = $args['checked'];
508
 
509
- if ( is_null( $args['desc'] ) && ! is_bool( $args['value'] ) )
510
  $args['desc'] = str_replace( '[]', '', $args['value'] );
 
511
 
512
  return self::_input_gen( $args );
513
  }
514
 
515
  /**
516
- * Generate html with the final args
517
  *
518
  * @param array $args
519
  *
@@ -540,6 +597,8 @@ abstract class scbFormField implements scbFormField_I {
540
  }
541
 
542
  /**
 
 
543
  * @param string $input
544
  * @param string $desc
545
  * @param string $desc_pos
@@ -551,6 +610,8 @@ abstract class scbFormField implements scbFormField_I {
551
  }
552
 
553
  /**
 
 
554
  * @param string $input
555
  * @param string $desc
556
  * @param string $desc_pos
@@ -558,13 +619,15 @@ abstract class scbFormField implements scbFormField_I {
558
  * @return string
559
  */
560
  protected static function add_desc( $input, $desc, $desc_pos ) {
561
- if ( empty( $desc ) )
562
  return $input;
 
563
 
564
- if ( 'before' == $desc_pos )
565
  return $desc . ' ' . $input;
566
- else
567
  return $input . ' ' . $desc;
 
568
  }
569
 
570
  /**
@@ -573,17 +636,19 @@ abstract class scbFormField implements scbFormField_I {
573
  private static function _expand_choices( &$args ) {
574
  $choices =& $args['choices'];
575
 
576
- if ( !empty( $choices ) && !self::is_associative( $choices ) ) {
577
  if ( is_array( $args['desc'] ) ) {
578
  $choices = array_combine( $choices, $args['desc'] ); // back-compat
579
  $args['desc'] = false;
580
- } elseif ( !isset( $args['numeric'] ) || !$args['numeric'] ) {
581
  $choices = array_combine( $choices, $choices );
582
  }
583
  }
584
  }
585
 
586
  /**
 
 
587
  * @param array $array
588
  *
589
  * @return bool
@@ -600,6 +665,8 @@ abstract class scbFormField implements scbFormField_I {
600
  class scbTextField extends scbFormField {
601
 
602
  /**
 
 
603
  * @param string $value
604
  *
605
  * @return string
@@ -611,6 +678,8 @@ class scbTextField extends scbFormField {
611
  }
612
 
613
  /**
 
 
614
  * @param array $args
615
  *
616
  * @return string
@@ -622,15 +691,20 @@ class scbTextField extends scbFormField {
622
  'extra' => array( 'class' => 'regular-text' ),
623
  ) );
624
 
625
- if ( ! isset( $args['extra']['id'] ) && ! is_array( $args['name'] ) && false === strpos( $args['name'], '[' ) )
626
  $args['extra']['id'] = $args['name'];
 
627
 
628
  return scbFormField::_input_gen( $args );
629
  }
630
 
631
  /**
 
 
632
  * @param array $args
633
  * @param string $value
 
 
634
  */
635
  protected function _set_value( &$args, $value ) {
636
  $args['value'] = $value;
@@ -643,18 +717,23 @@ class scbTextField extends scbFormField {
643
  abstract class scbSingleChoiceField extends scbFormField {
644
 
645
  /**
 
 
646
  * @param mixed $value
647
  *
648
  * @return mixed|null
649
  */
650
  public function validate( $value ) {
651
- if ( isset( $this->choices[ $value ] ) )
652
  return $value;
 
653
 
654
  return null;
655
  }
656
 
657
  /**
 
 
658
  * @param array $args
659
  *
660
  * @return string
@@ -667,21 +746,27 @@ abstract class scbSingleChoiceField extends scbFormField {
667
  if ( isset( $args['selected'] ) ) {
668
  $args['selected'] = (string) $args['selected'];
669
  } else {
670
- $args['selected'] = array('foo'); // hack to make default blank
671
  }
672
 
673
  return $this->_render_specific( $args );
674
  }
675
 
676
  /**
677
- * @param array $args
678
- * @param mixed $value
 
 
 
 
679
  */
680
  protected function _set_value( &$args, $value ) {
681
  $args['selected'] = $value;
682
  }
683
 
684
  /**
 
 
685
  * @param array $args
686
  *
687
  * @return string
@@ -695,6 +780,8 @@ abstract class scbSingleChoiceField extends scbFormField {
695
  class scbSelectField extends scbSingleChoiceField {
696
 
697
  /**
 
 
698
  * @param array $args
699
  *
700
  * @return string
@@ -744,6 +831,8 @@ class scbSelectField extends scbSingleChoiceField {
744
  class scbRadiosField extends scbSelectField {
745
 
746
  /**
 
 
747
  * @param array $args
748
  *
749
  * @return string
@@ -781,6 +870,8 @@ class scbRadiosField extends scbSelectField {
781
  class scbMultipleChoiceField extends scbFormField {
782
 
783
  /**
 
 
784
  * @param mixed $value
785
  *
786
  * @return array
@@ -790,6 +881,8 @@ class scbMultipleChoiceField extends scbFormField {
790
  }
791
 
792
  /**
 
 
793
  * @param array $args
794
  *
795
  * @return string
@@ -800,8 +893,9 @@ class scbMultipleChoiceField extends scbFormField {
800
  'checked' => null,
801
  ) );
802
 
803
- if ( ! is_array( $args['checked'] ) )
804
  $args['checked'] = array();
 
805
 
806
  $opts = '';
807
  foreach ( $args['choices'] as $value => $title ) {
@@ -821,8 +915,12 @@ class scbMultipleChoiceField extends scbFormField {
821
  }
822
 
823
  /**
824
- * @param array $args
825
- * @param mixed $value
 
 
 
 
826
  */
827
  protected function _set_value( &$args, $value ) {
828
  $args['checked'] = (array) $value;
@@ -835,6 +933,8 @@ class scbMultipleChoiceField extends scbFormField {
835
  class scbSingleCheckboxField extends scbFormField {
836
 
837
  /**
 
 
838
  * @param mixed $value
839
  *
840
  * @return boolean
@@ -844,6 +944,8 @@ class scbSingleCheckboxField extends scbFormField {
844
  }
845
 
846
  /**
 
 
847
  * @param array $args
848
  *
849
  * @return string
@@ -858,15 +960,20 @@ class scbSingleCheckboxField extends scbFormField {
858
 
859
  $args['extra']['checked'] = $args['checked'];
860
 
861
- if ( is_null( $args['desc'] ) && ! is_bool( $args['value'] ) )
862
  $args['desc'] = str_replace( '[]', '', $args['value'] );
 
863
 
864
  return scbFormField::_input_gen( $args );
865
  }
866
 
867
  /**
868
- * @param array $args
869
- * @param mixed $value
 
 
 
 
870
  */
871
  protected function _set_value( &$args, $value ) {
872
  $args['checked'] = ( $value || ( isset( $args['value'] ) && $value == $args['value'] ) );
@@ -881,7 +988,11 @@ class scbCustomField implements scbFormField_I {
881
  protected $args;
882
 
883
  /**
 
 
884
  * @param array $args
 
 
885
  */
886
  function __construct( $args ) {
887
  $this->args = wp_parse_args( $args, array(
@@ -891,6 +1002,8 @@ class scbCustomField implements scbFormField_I {
891
  }
892
 
893
  /**
 
 
894
  * @param string $key
895
  *
896
  * @return mixed
@@ -900,6 +1013,8 @@ class scbCustomField implements scbFormField_I {
900
  }
901
 
902
  /**
 
 
903
  * @param string $key
904
  *
905
  * @return boolean
@@ -909,7 +1024,9 @@ class scbCustomField implements scbFormField_I {
909
  }
910
 
911
  /**
912
- * @param mixed $value
 
 
913
  *
914
  * @return string
915
  */
@@ -918,6 +1035,8 @@ class scbCustomField implements scbFormField_I {
918
  }
919
 
920
  /**
 
 
921
  * @param mixed $value
922
  *
923
  * @return mixed
1
  <?php
 
2
  /**
3
+ * Data-aware form generator.
4
  */
5
  class scbForms {
6
 
7
  const TOKEN = '%input%';
8
 
9
  /**
10
+ * Generates form field.
11
+ *
12
  * @param array|scbFormField_I $args
13
  * @param mixed $value
14
  *
15
  * @return string
16
  */
17
+ public static function input_with_value( $args, $value ) {
18
  $field = scbFormField::create( $args );
19
 
20
  return $field->render( $value );
21
  }
22
 
23
  /**
24
+ * Generates form field.
25
+ *
26
  * @param array|scbFormField_I $args
27
+ * @param array $formdata (optional)
28
  *
29
  * @return string
30
  */
31
+ public static function input( $args, $formdata = null ) {
32
  $field = scbFormField::create( $args );
33
 
34
  return $field->render( scbForms::get_value( $args['name'], $formdata ) );
35
  }
36
 
37
  /**
38
+ * Generates a table wrapped in a form.
39
  *
40
  * @param array $rows
41
+ * @param array $formdata (optional)
42
  *
43
  * @return string
44
  */
45
+ public static function form_table( $rows, $formdata = null ) {
46
  $output = '';
47
+ foreach ( $rows as $row ) {
48
  $output .= self::table_row( $row, $formdata );
49
+ }
50
 
51
  $output = self::form_table_wrap( $output );
52
 
54
  }
55
 
56
  /**
57
+ * Generates a form.
58
  *
59
  * @param array $inputs
60
+ * @param array $formdata (optional)
61
  * @param string $nonce
62
  *
63
  * @return string
64
  */
65
+ public static function form( $inputs, $formdata = null, $nonce ) {
66
  $output = '';
67
+ foreach ( $inputs as $input ) {
68
  $output .= self::input( $input, $formdata );
69
+ }
70
 
71
  $output = self::form_wrap( $output, $nonce );
72
 
74
  }
75
 
76
  /**
77
+ * Generates a table.
78
  *
79
  * @param array $rows
80
+ * @param array $formdata (optional)
81
  *
82
  * @return string
83
  */
84
+ public static function table( $rows, $formdata = null ) {
85
  $output = '';
86
+ foreach ( $rows as $row ) {
87
  $output .= self::table_row( $row, $formdata );
88
+ }
89
 
90
  $output = self::table_wrap( $output );
91
 
93
  }
94
 
95
  /**
96
+ * Generates a table row.
97
  *
98
  * @param array $args
99
+ * @param array $formdata (optional)
100
  *
101
  * @return string
102
  */
103
+ public static function table_row( $args, $formdata = null ) {
104
  return self::row_wrap( $args['title'], self::input( $args, $formdata ) );
105
  }
106
 
108
  // ____________WRAPPERS____________
109
 
110
  /**
111
+ * Wraps a table in a form.
112
+ *
113
  * @param string $content
114
+ * @param string $nonce (optional)
115
  *
116
  * @return string
117
  */
118
+ public static function form_table_wrap( $content, $nonce = 'update_options' ) {
119
  return self::form_wrap( self::table_wrap( $content ), $nonce );
120
  }
121
 
122
  /**
123
+ * Wraps a content in a form.
124
+ *
125
  * @param string $content
126
+ * @param string $nonce (optional)
127
  *
128
  * @return string
129
  */
130
+ public static function form_wrap( $content, $nonce = 'update_options' ) {
131
  return html( "form method='post' action=''",
132
  $content,
133
  wp_nonce_field( $nonce, '_wpnonce', $referer = true, $echo = false )
135
  }
136
 
137
  /**
138
+ * Wraps a content in a table.
139
+ *
140
  * @param string $content
141
  *
142
  * @return string
143
  */
144
+ public static function table_wrap( $content ) {
145
  return html( "table class='form-table'", $content );
146
  }
147
 
148
  /**
149
+ * Wraps a content in a table row.
150
+ *
151
  * @param string $title
152
  * @param string $content
153
  *
154
  * @return string
155
  */
156
+ public static function row_wrap( $title, $content ) {
157
  return html( 'tr',
158
  html( "th scope='row'", $title ),
159
  html( 'td', $content )
174
  *
175
  * @return string
176
  */
177
+ public static function get_name( $name ) {
178