PluginProbe ʕ •ᴥ•ʔ
Custom Sidebars – Dynamic Sidebar Classic Widget Area Manager / 3.0.7.1
Custom Sidebars – Dynamic Sidebar Classic Widget Area Manager v3.0.7.1
trunk 2.1.2.0 3.0.0.0 3.0.0.1 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.7.1 3.0.8 3.0.8.1 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.3 3.31 3.32 3.35 3.36 3.37 3.38
custom-sidebars / inc / class-custom-sidebars-export.php
custom-sidebars / inc Last commit date
external 9 years ago class-custom-sidebars-checkup-notification.php 9 years ago class-custom-sidebars-cloning.php 9 years ago class-custom-sidebars-editor.php 9 years ago class-custom-sidebars-explain.php 9 years ago class-custom-sidebars-export.php 9 years ago class-custom-sidebars-replacer.php 9 years ago class-custom-sidebars-visibility.php 9 years ago class-custom-sidebars-widgets.php 9 years ago class-custom-sidebars.php 9 years ago
class-custom-sidebars-export.php
811 lines
1 <?php
2
3 add_action( 'cs_init', array( 'CustomSidebarsExport', 'instance' ) );
4
5 /**
6 * Provides functionality to export and import sidebar settings.
7 *
8 * @since 2.0
9 */
10 class CustomSidebarsExport extends CustomSidebars {
11
12 // Holds the contents of the import-file during preview/import.
13 static private $import_data = null;
14
15 // Used after preview. This holds only the items that were selected for import.
16 private $selected_data = null;
17
18
19 /**
20 * Returns the singleton object.
21 *
22 * @since 2.0
23 */
24 public static function instance() {
25 static $Inst = null;
26
27 if ( null === $Inst ) {
28 $Inst = new CustomSidebarsExport();
29 }
30
31 return $Inst;
32 }
33
34 /**
35 * Constructor is private -> singleton.
36 *
37 * @since 2.0
38 */
39 private function __construct() {
40 if ( is_admin() ) {
41 add_action(
42 'cs_widget_header',
43 array( $this, 'widget_header' )
44 );
45
46 add_action(
47 'cs_ajax_request',
48 array( $this, 'handle_ajax' )
49 );
50 }
51 }
52
53 /**
54 * Called by action 'cs_widget_header'. Output the export/import button in
55 * the widget header.
56 *
57 * @since 2.0
58 */
59 public function widget_header() {
60 ?>
61 <a href="#" class="cs-action btn-export"><?php _e( 'Import / Export Sidebars', 'custom-sidebars' ); ?></a>
62 <?php
63 }
64
65 /**
66 * When the custom sidebars section is visible we see if export-action
67 * needs to be processed.
68 *
69 * @since 2.0
70 */
71 public function handle_ajax( $ajax_action ) {
72 $req = (object) array(
73 'status' => 'ERR',
74 );
75 $is_json = true;
76 $handle_it = false;
77 $view_file = '';
78
79 switch ( $ajax_action ) {
80 case 'export':
81 case 'import':
82 case 'preview-import':
83 $handle_it = true;
84 $req->status = 'OK';
85 $req->action = $ajax_action;
86 break;
87 }
88
89 // The ajax request was not meant for us...
90 if ( ! $handle_it ) {
91 return false;
92 }
93
94 if ( ! current_user_can( self::$cap_required ) ) {
95 $req = self::req_err(
96 $req,
97 __( 'You do not have permission for this', 'custom-sidebars' )
98 );
99 } else {
100 switch ( $ajax_action ) {
101 case 'export':
102 $this->download_export_file();
103 break;
104
105 case 'preview-import':
106 $req = $this->read_import_file( $req );
107 if ( 'OK' == $req->status ) {
108 ob_start();
109 include CSB_VIEWS_DIR . 'import.php';
110 $req->html = ob_get_clean();
111 }
112 break;
113
114 case 'import':
115 $req = $this->prepare_import_data( $req );
116 break;
117 }
118 }
119
120 // Make the ajax response either as JSON or plain text.
121 if ( $is_json ) {
122 self::json_response( $req );
123 } else {
124 ob_start();
125 include CSB_VIEWS_DIR . $view_file;
126 $resp = ob_get_clean();
127
128 self::plain_response( $resp );
129 }
130 }
131
132
133 /*============================*\
134 ================================
135 == ==
136 == EXPORT ==
137 == ==
138 ================================
139 \*============================*/
140
141
142 /**
143 * Collects the plugin details for export.
144 *
145 * @since 2.0
146 */
147 private function get_export_data() {
148 global $wp_registered_widgets, $wp_version;
149
150 $theme = wp_get_theme();
151
152 $csb_info = get_plugin_data( CSB_PLUGIN );
153
154 $data = array();
155 // Add some meta-details to the export file.
156 $data['meta'] = array(
157 'created' => time(),
158 'wp_version' => $wp_version,
159 'csb_version' => @$csb_info['Version'],
160 'theme_name' => $theme->get( 'Name' ),
161 'theme_version' => $theme->get( 'Version' ),
162 'description' => htmlspecialchars( @$_POST['export-description'] ),
163 );
164
165 // Export the custom sidebars.
166 $data['sidebars'] = self::get_custom_sidebars();
167
168 // Export the sidebar options (e.g. default replacement).
169 $data['options'] = self::get_options();
170
171 // Export category-information.
172 $data['categories'] = get_categories( array( 'hide_empty' => 0 ) );
173
174 /*
175 * Export all widget options.
176 *
177 * $wp_registered_widgets contains all widget-instances that were placed
178 * inside a sidebar. So we loop this array and fetch each widgets
179 * options individually:
180 *
181 * Widget options are saved inside options table with option_name
182 * "widget_<widget-slug>"; the options can be an array, e.g.
183 * "widget_search" contains options for all widget instances in any
184 * sidebar. When we place 2 search widgets in different sidebars there
185 * will be a list with two option-arrays.
186 */
187 $data['widgets'] = array();
188 foreach ( self::get_sidebar_widgets() as $sidebar => $widgets ) {
189 if ( 'wp_inactive_widgets' === $sidebar ) {
190 continue;
191 }
192 if ( is_array( $widgets ) ) {
193 $data['widgets'][ $sidebar ] = array();
194 foreach ( $widgets as $widget_id ) {
195 if ( isset( $wp_registered_widgets[ $widget_id ] ) ) {
196 $item = $wp_registered_widgets[ $widget_id ];
197 $cb = $item['callback'];
198 $widget = is_array( $cb ) ? reset( $cb ) : false;
199 $id = $widget_id;
200 if ( ! isset( $data['widgets'][ $sidebar ][ $id ] ) ) {
201 if ( preg_match( '/(\d+)$/', $widget_id, $matches ) ) {
202 $id = $matches[1];
203 }
204 }
205 if ( isset( $data['widgets'][ $sidebar ][ $id ] ) ) {
206 continue;
207 }
208 if ( is_object( $widget ) && method_exists( $widget, 'get_settings' ) ) {
209 /**
210 * set correct widget data
211 */
212 $widget->id = $widget_id;
213 $widget->number = $id;
214 /**
215 * get settings
216 */
217 $settings = $widget->get_settings();
218 $data['widgets'][ $sidebar ][ $id ] = array(
219 'name' => @$widget->name,
220 'classname' => get_class( $widget ),
221 'id_base' => @$widget->id_base,
222 'description' => @$widget->description,
223 'settings' => $settings[ @$widget->number ],
224 'version' => 3,
225 );
226 } else {
227 /**
228 * Widgets that are registered with the old widget API
229 * have a different structure:
230 *
231 * - Not an object but a callback function.
232 * - No standard options-form.
233 * -> No widget settings to export.
234 * -> No clone/visibility options to export.
235 * - Only one instance
236 * -> "id_base" is same as $widget_id
237 */
238 $data['widgets'][ $sidebar ][ $widget_id ] = array(
239 'name' => @$item['name'],
240 'classname' => @$item['classname'],
241 'id_base' => @$item['id'],
242 'description' => @$item['description'],
243 'settings' => @$item['params'],
244 'version' => 2,
245 );
246 }
247 /**
248 * remove empty settings
249 */
250 if ( isset( $data['widgets'][ $sidebar ][ $id ]['settings']['csb_visibility']['conditions'] ) ) {
251 foreach ( $data['widgets'][ $sidebar ][ $id ]['settings']['csb_visibility']['conditions'] as $condition_id => $condition_value ) {
252 if ( empty( $condition_value ) ) {
253
254 unset( $data['widgets'][ $sidebar ][ $id ]['settings']['csb_visibility']['conditions'][ $condition_id ] );
255
256 }
257 }
258 }
259 }
260 }
261 } else {
262 $data['widgets'][ $sidebar ] = $widgets;
263 }
264 }
265 return $data;
266 }
267
268 /**
269 * Generates the export file and sends it as a download to the browser.
270 *
271 * @since 2.0
272 */
273 private function download_export_file() {
274 $data = $this->get_export_data();
275 $filename = 'sidebars.' . date( 'Y-m-d.H-i-s' ) . '.json';
276 $option = defined( 'JSON_PRETTY_PRINT' )? JSON_PRETTY_PRINT : null;
277 $content = json_encode( (object) $data, $option );
278 // Send the download headers.
279 header( 'Pragma: public' );
280 header( 'Expires: 0' );
281 header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
282 header( 'Cache-Control: private', false ); // required for certain browsers
283 header( 'Content-type: application/json' );
284 header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
285 header( 'Content-Transfer-Encoding: binary' );
286 header( 'Content-Length: ' . strlen( $content ) );
287 // Finally send the export-file content.
288 echo '' . $content;
289 die();
290 }
291
292 /*=============================*\
293 =================================
294 == ==
295 == PREVIEW ==
296 == ==
297 =================================
298 \*=============================*/
299
300
301 /**
302 * Checks if a valid export-file was uploaded and stores the file contents
303 * inside self::$import_data. The data is de-serialized.
304 * In error case the response object will be set to error status.
305 *
306 * @since 2.0
307 * @param object $req Initial response object for JSON response.
308 * @return object Updated response object.
309 */
310 private function read_import_file( $req ) {
311 if ( is_array( $_FILES['data'] ) ) {
312 switch ( $_FILES['data']['error'] ) {
313 case UPLOAD_ERR_OK:
314 // This is the expeted status!
315 break;
316
317 case UPLOAD_ERR_NO_FILE:
318 return self::req_err(
319 $req,
320 __( 'No file was uploaded', 'custom-sidebars' )
321 );
322
323 case UPLOAD_ERR_INI_SIZE:
324 case UPLOAD_ERR_FORM_SIZE:
325 return self::req_err(
326 $req,
327 __( 'Import file is too big', 'custom-sidebars' )
328 );
329
330 default:
331 return self::req_err(
332 $req,
333 __( 'Something went wrong', 'custom-sidebars' )
334 );
335 }
336
337 $content = file_get_contents( $_FILES['data']['tmp_name'] );
338 $data = json_decode( $content, true );
339
340 if (
341 is_array( $data['meta'] ) &&
342 is_array( $data['sidebars'] ) &&
343 is_array( $data['options'] ) &&
344 is_array( $data['widgets'] ) &&
345 is_array( $data['categories'] )
346 ) {
347 $data['meta']['filename'] = $_FILES['data']['name'];
348 $data['ignore'] = array();
349 self::$import_data = $data;
350
351 // Remove details that does not exist on current blog.
352 $this->prepare_data();
353 } else {
354 return self::req_err(
355 $req,
356 __( 'Unexpected import format', 'custom-sidebars' )
357 );
358 }
359 } else {
360 return self::req_err(
361 $req,
362 __( 'No file was uploaded', 'custom-sidebars' )
363 );
364 }
365
366 return $req;
367 }
368
369 /**
370 * Loads the import-data into the self::$import_data property.
371 * The data was prepared by the import-preview screen.
372 * Populates the response object.
373 *
374 * @since 2.0
375 * @param object $req Initial response object for JSON response.
376 * @return object Updated response object.
377 */
378 private function prepare_import_data( $req ) {
379 $data = json_decode( base64_decode( @$_POST['import_data'] ), true );
380
381 if (
382 is_array( $data['meta'] ) &&
383 is_array( $data['sidebars'] ) &&
384 is_array( $data['options'] ) &&
385 is_array( $data['widgets'] ) &&
386 is_array( $data['categories'] )
387 ) {
388 $data['ignore'] = array();
389 self::$import_data = $data;
390
391 // Remove details that does not exist on current blog.
392 $this->prepare_data();
393
394 // "selected_data" only contains the items that were selected for import.
395 $this->selected_data = self::$import_data;
396 unset( $this->selected_data['meta'] );
397 unset( $this->selected_data['categories'] );
398 unset( $this->selected_data['ignore'] );
399
400 if ( ! isset( $_POST['import_plugin_config'] ) ) {
401 unset( $this->selected_data['options'] );
402 }
403 if ( ! isset( $_POST['import_widgets'] ) ) {
404 unset( $this->selected_data['widgets'] );
405 } else {
406 foreach ( $this->selected_data['widgets'] as $id => $widgets ) {
407 $key = 'import_sb_' . $id;
408 if ( ! isset( $_POST[ $key ] ) ) {
409 unset( $this->selected_data['widgets'][ $id ] );
410 }
411 }
412 }
413 foreach ( $this->selected_data['sidebars'] as $id => $sidebar ) {
414 $key = 'import_sb_' . $sidebar['id'];
415 if ( ! isset( $_POST[ $key ] ) ) {
416 unset( $this->selected_data['sidebars'][ $id ] );
417 }
418 }
419
420 // Finally: Import the config!
421 $req = $this->do_import( $req );
422 } else {
423 return self::req_err(
424 $req,
425 __(
426 'Something unexpected happened and we could not finish ' .
427 'the import. Please try again.', 'custom-sidebars'
428 )
429 );
430 }
431
432 return $req;
433 }
434
435 /**
436 * Loops through the import data array and removes configuration which is
437 * not relevant for the current blog. I.e. posttypes that are not registered
438 * or categories that do not match the current blog.
439 *
440 * @since 2.0
441 */
442 private function prepare_data() {
443 global $wp_registered_widgets;
444 $theme_sidebars = self::get_sidebars();
445 $valid_categories = array();
446 $valid_sidebars = array();
447 $valid_widgets = array();
448
449 // =====
450 // Normalize the sidebar list (change numeric index to sidebar-id).
451 $sidebars_remapped = array();
452 foreach ( self::$import_data['sidebars'] as $sidebar ) {
453 $sidebars_remapped[ $sidebar['id'] ] = $sidebar;
454 }
455 self::$import_data['sidebars'] = $sidebars_remapped;
456
457 // =====
458 // Get a list of existing/valid sidebar-IDs.
459 $valid_sidebars = array_merge(
460 array_keys( $theme_sidebars ),
461 array_keys( self::$import_data['sidebars'] )
462 );
463
464 // =====
465 // Check for theme-sidebars that do not exist.
466 foreach ( self::$import_data['options']['modifiable'] as $id => $sb_id ) {
467 if ( ! isset( $theme_sidebars[ $sb_id ] ) ) {
468 if ( ! isset( self::$import_data['ignore']['sidebars'] ) ) {
469 self::$import_data['ignore']['sidebars'] = array();
470 }
471 self::$import_data['ignore']['sidebars'][] = $sb_id;
472 unset( self::$import_data['options']['modifiable'][ $id ] );
473 }
474 }
475
476 // =====
477 // Remove invalid sidebars from the default replacement options.
478 foreach ( array( 'post_type_single', 'post_type_archive', 'category_single', 'category_archive' ) as $key ) {
479 foreach ( self::$import_data['options'][ $key ] as $id => $list ) {
480 $list = $this->_remove_sidebar_from_list( $list, $valid_sidebars );
481 self::$import_data['options'][ $key ][ $id ] = $list;
482 }
483 }
484 foreach ( array( 'blog', 'tags', 'authors', 'search', 'date' ) as $key ) {
485 $list = self::$import_data['options'][ $key ];
486 $list = $this->_remove_sidebar_from_list( $list, $valid_sidebars );
487 self::$import_data['options'][ $key ] = $list;
488 }
489
490 // =====
491 // Check for missing/different categories.
492 foreach ( get_categories( array( 'hide_empty' => 0 ) ) as $cat ) {
493 $valid_categories[ $cat->term_id ] = $cat;
494 }
495 foreach ( self::$import_data['categories'] as $infos ) {
496 $id = $infos['term_id'];
497 if (
498 empty( $valid_categories[ $id ] ) ||
499 $valid_categories[ $id ]->slug != $infos['slug']
500 ) {
501 if ( ! isset( self::$import_data['ignore']['categories'] ) ) {
502 self::$import_data['ignore']['categories'] = array();
503 }
504 self::$import_data['ignore']['categories'][] = $infos['name'];
505 unset( self::$import_data['categories'][ $id ] );
506
507 // Remove the categories from the config array.
508 unset( self::$import_data['options']['category_posts'][ $id ] );
509 unset( self::$import_data['options']['category_pages'][ $id ] );
510 }
511 }
512
513 // =====
514 // Remove missing widgets from import data.
515 foreach ( $wp_registered_widgets as $widget ) {
516 if ( is_array( $widget['callback'] ) ) {
517 $classname = get_class( $widget['callback'][0] );
518 } else {
519 $classname = $widget['classname'];
520 }
521 $valid_widgets[ $classname ] = true;
522 }
523 foreach ( self::$import_data['widgets'] as $sb_id => $sidebar ) {
524 if ( ! is_array( $sidebar ) ) { continue; }
525 foreach ( $sidebar as $id => $widget_instance ) {
526 $version = $widget_instance['version'];
527 $instance_class = $widget_instance['classname'];
528 $exists = (true === @$valid_widgets[ $instance_class ]);
529 if ( ! $exists ) {
530 if ( ! isset( self::$import_data['ignore']['widgets'] ) ) {
531 self::$import_data['ignore']['widgets'] = array();
532 }
533 self::$import_data['ignore']['widgets'][] = $widget_instance['name'];
534 unset( $sidebar[ $id ] );
535 }
536 }
537 self::$import_data['widgets'][ $sb_id ] = $sidebar;
538 }
539 }
540
541 /**
542 * Helper function that is used by prepare_data.
543 *
544 * @since 2.0
545 */
546 private function _remove_sidebar_from_list( $list, $valid_list ) {
547 /**
548 * do not process if $list is not an array or is an empty array
549 */
550 if ( ! is_array( $list ) || empty( $list ) ) {
551 return $list;
552 }
553 foreach ( $list as $id => $value ) {
554 if ( ! in_array( $value, $valid_list ) ) {
555 unset( $list[ $id ] );
556 } else if ( ! in_array( $id, $valid_list ) ) {
557 unset( $list[ $id ] );
558 }
559 }
560 return $list;
561 }
562
563 /**
564 * Returns the contents of the uploaded import file for preview or import.
565 *
566 * @since 2.0
567 */
568 static public function get_import_data() {
569 return self::$import_data;
570 }
571
572
573 /*============================*\
574 ================================
575 == ==
576 == IMPORT ==
577 == ==
578 ================================
579 \*============================*/
580
581 /**
582 * Process the import data provided in self::$import_data.
583 * Save the configuration to database.
584 * Populates the response object.
585 *
586 * @since 2.0
587 * @param object $req Initial response object for JSON response.
588 * @return object Updated response object.
589 */
590 private function do_import( $req ) {
591 $data = $this->selected_data;
592 $msg = array();
593
594 // =====================================================================
595 // Import custom sidebars
596
597 $sidebars = self::get_custom_sidebars();
598 $sidebar_count = 0;
599 // First replace existing sidebars.
600 foreach ( $sidebars as $idx => $sidebar ) {
601 $sb_id = $sidebar['id'];
602 if ( isset( $data['sidebars'][ $sb_id ] ) ) {
603 $new_sidebar = $data['sidebars'][ $sb_id ];
604 $sidebars[ $idx ] = array(
605 'name' => @$new_sidebar['name'],
606 'id' => $sb_id,
607 'description' => @$new_sidebar['description'],
608 'before_widget' => @$new_sidebar['before_widget'],
609 'after_widget' => @$new_sidebar['after_widget'],
610 'before_title' => @$new_sidebar['before_title'],
611 'after_title' => @$new_sidebar['after_title'],
612 );
613 $sidebar_count += 1;
614 unset( $data['sidebars'][ $sb_id ] );
615 }
616 }
617 // Second add new sidebars.
618 foreach ( $data['sidebars'] as $sb_id => $new_sidebar ) {
619 $sidebars[] = array(
620 'name' => @$new_sidebar['name'],
621 'id' => $sb_id,
622 'description' => @$new_sidebar['description'],
623 'before_widget' => @$new_sidebar['before_widget'],
624 'after_widget' => @$new_sidebar['after_widget'],
625 'before_title' => @$new_sidebar['before_title'],
626 'after_title' => @$new_sidebar['after_title'],
627 );
628 $sidebar_count += 1;
629 }
630 if ( $sidebar_count > 0 ) {
631 self::set_custom_sidebars( $sidebars );
632 $msg[] = sprintf(
633 __( 'Imported %d custom sidebar(s)!', 'custom-sidebars' ),
634 $sidebar_count
635 );
636 }
637
638 // =====================================================================
639 // Import plugin settings
640 if ( ! empty( $data['options'] ) ) {
641 self::set_options( $data['options'] );
642 $msg[] = __( 'Plugin options were imported!', 'custom-sidebars' );
643 }
644
645 // =====================================================================
646 // Import widgets
647 $widget_count = 0;
648 $def_sidebars = wp_get_sidebars_widgets();
649 $widget_list = array();
650 $orig_POST = $_POST;
651 // First replace existing sidebars.
652 foreach ( $data['widgets'] as $sb_id => $sidebar ) {
653 // --- 1. Remove all widgets from the sidebar
654
655 // @see wp-admin/includes/ajax-actions.php : function wp_ajax_save_widget()
656 // Empty the sidebar, in case it contains widgets.
657 $old_widgets = @$def_sidebars[ $sb_id ];
658 $def_sidebars[ $sb_id ] = array();
659 wp_set_sidebars_widgets( $def_sidebars );
660
661 // Also remove the widget-instances from wp-option table.
662 if ( ! is_array( $old_widgets ) ) {
663 $old_widgets = array();
664 }
665 foreach ( $old_widgets as $widget_id ) {
666 $id_base = preg_replace( '/-[0-9]+$/', '', $widget_id );
667 $_POST = array(
668 'sidebar' => $sb_id,
669 'widget-' . $id_base => array(),
670 'the-widget-id' => $widget_id,
671 'delete_widget' => '1',
672 );
673 $this->_refresh_widget_settings( $id_base );
674 }
675
676 // --- 2. Import the new widgets to the sidebar
677
678 foreach ( $sidebar as $class => $widget ) {
679 $widget_base = $widget['id_base'];
680 $widget_name = $this->_add_new_widget( $widget_base, $widget['settings'] );
681
682 if ( ! empty( $widget_name ) ) {
683 $def_sidebars[ $sb_id ][] = $widget_name;
684 $widget_count += 1;
685 }
686 }
687 }
688 $_POST = $orig_POST;
689 if ( $widget_count > 0 ) {
690 wp_set_sidebars_widgets( $def_sidebars );
691 $msg[] = sprintf(
692 __( 'Imported %d widget(s)!', 'custom-sidebars' ),
693 $widget_count
694 );
695 }
696
697 $req->message = base64_encode( implode( '<br />', $msg ) );
698
699 // We return a HTTP header to refresh the widgets page.
700 header( 'HTTP/1.1 302 Found' );
701 header( 'Location: ' . admin_url( 'widgets.php?cs-msg=' . $req->message ) );
702 die();
703 }
704
705 /**
706 * Helper function used by the "do_import()" handler.
707 * Updates the widget-data in DB.
708 *
709 * @since 2.0
710 */
711 private function _refresh_widget_settings( $id_base ) {
712 global $wp_registered_widget_updates;
713
714 foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
715
716 if ( $name == $id_base ) {
717 if ( ! is_callable( $control['callback'] ) ) {
718 continue;
719 }
720
721 ob_start();
722 if ( is_object( $control['callback'] ) ) {
723 $control['callback']->updated = false;
724 }
725 call_user_func_array( $control['callback'], $control['params'] );
726 ob_end_clean();
727
728 break;
729 }
730 }
731 }
732
733 /**
734 * Helper function used by the "do_import()" handler.
735 * Updates the widget-data in DB.
736 *
737 * @since 2.0
738 */
739 private function _add_new_widget( $id_base, $instance ) {
740 global $wp_registered_widget_updates;
741 $widget_name = false;
742
743 foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
744
745 if ( $name == $id_base ) {
746 if ( ! is_callable( $control['callback'] ) ) {
747 continue;
748 }
749
750 if ( is_array( $control['callback'] ) ) {
751 $obj = $control['callback'][0];
752 } else {
753 // We cannot import data from old widgets API.
754 break;
755 }
756 $obj->updated = false;
757
758 $all_instances = $obj->get_settings();
759
760 // Find out what the next free number is.
761 $new_number = 0;
762 foreach ( $all_instances as $number => $data ) {
763 $new_number = $number > $new_number ? $number : $new_number;
764 }
765 $new_number += 1;
766 $widget_name = $id_base . '-' . $new_number;
767 /**
768 * reset previous data
769 */
770 $keys = array( 'title', 'text', 'filter', 'csb_visibility', 'csb_clone' );
771 foreach ( $keys as $key ) {
772 if ( isset( $_POST[ $key ] ) ) {
773 unset( $_POST[ $key ] );
774 }
775 }
776 /**
777 * set current values
778 */
779 foreach ( $instance as $key => $value ) {
780 $_POST[ $key ] = $value;
781 }
782
783 /**
784 * Filter a widget's settings before saving.
785 *
786 * Returning false will effectively short-circuit the widget's ability
787 * to update settings.
788 *
789 * @see wp-includes/widgets.php : function "update_callback()"
790 * @since WordPress 2.8.0
791 *
792 * @param array $instance The current widget instance's settings.
793 * @param array $new_instance Array of new widget settings.
794 * @param array $old_instance Array of old widget settings.
795 * @param WP_Widget $this The current widget instance.
796 */
797 $instance = apply_filters( 'widget_update_callback', $instance, $instance, array(), $obj );
798 if ( false !== $instance ) {
799 $all_instances[ $new_number ] = $instance;
800 }
801
802 $obj->save_settings( $all_instances );
803
804 break;
805 }
806 }
807
808 return $widget_name;
809 }
810 };
811