1<?php
2/**
3 * Widget API: WP_Widget_Factory class
4 *
5 * @package WordPress
6 * @subpackage Widgets
7 * @since 4.4.0
8 */
9
10/**
11 * Singleton that registers and instantiates WP_Widget classes.
12 *
13 * @since 2.8.0
14 * @since 4.4.0 Moved to its own file from wp-includes/widgets.php
15 */
16#[AllowDynamicProperties]
17class WP_Widget_Factory {
18
19 /**
20 * Widgets array.
21 *
22 * @since 2.8.0
23 * @var array
24 */
25 public $widgets = array();
26
27 /**
28 * PHP5 constructor.
29 *
30 * @since 4.3.0
31 */
32 public function __construct() {
33 add_action( 'widgets_init', array( $this, '_register_widgets' ), 100 );
34 }
35
36 /**
37 * PHP4 constructor.
38 *
39 * @since 2.8.0
40 * @deprecated 4.3.0 Use __construct() instead.
41 *
42 * @see WP_Widget_Factory::__construct()
43 */
44 public function WP_Widget_Factory() {
45 _deprecated_constructor( 'WP_Widget_Factory', '4.3.0' );
46 self::__construct();
47 }
48
49 /**
50 * Registers a widget subclass.
51 *
52 * @since 2.8.0
53 * @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object
54 * instead of simply a `WP_Widget` subclass name.
55 *
56 * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass.
57 */
58 public function register( $widget ) {
59 if ( $widget instanceof WP_Widget ) {
60 $this->widgets[ spl_object_hash( $widget ) ] = $widget;
61 } else {
62 $this->widgets[ $widget ] = new $widget();
63 }
64 }
65
66 /**
67 * Un-registers a widget subclass.
68 *
69 * @since 2.8.0
70 * @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object
71 * instead of simply a `WP_Widget` subclass name.
72 *
73 * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass.
74 */
75 public function unregister( $widget ) {
76 if ( $widget instanceof WP_Widget ) {
77 unset( $this->widgets[ spl_object_hash( $widget ) ] );
78 } else {
79 unset( $this->widgets[ $widget ] );
80 }
81 }
82
83 /**
84 * Serves as a utility method for adding widgets to the registered widgets global.
85 *
86 * @since 2.8.0
87 *
88 * @global array $wp_registered_widgets
89 */
90 public function _register_widgets() {
91 global $wp_registered_widgets;
92 $keys = array_keys( $this->widgets );
93 $registered = array_keys( $wp_registered_widgets );
94 $registered = array_map( '_get_widget_id_base', $registered );
95
96 foreach ( $keys as $key ) {
97 // Don't register new widget if old widget with the same id is already registered.
98 if ( in_array( $this->widgets[ $key ]->id_base, $registered, true ) ) {
99 unset( $this->widgets[ $key ] );
100 continue;
101 }
102
103 $this->widgets[ $key ]->_register();
104 }
105 }
106
107 /**
108 * Returns the registered WP_Widget object for the given widget type.
109 *
110 * @since 5.8.0
111 *
112 * @param string $id_base Widget type ID.
113 * @return WP_Widget|null
114 */
115 public function get_widget_object( $id_base ) {
116 $key = $this->get_widget_key( $id_base );
117 if ( '' === $key ) {
118 return null;
119 }
120
121 return $this->widgets[ $key ];
122 }
123
124 /**
125 * Returns the registered key for the given widget type.
126 *
127 * @since 5.8.0
128 *
129 * @param string $id_base Widget type ID.
130 * @return string
131 */
132 public function get_widget_key( $id_base ) {
133 foreach ( $this->widgets as $key => $widget_object ) {
134 if ( $widget_object->id_base === $id_base ) {
135 return $key;
136 }
137 }
138
139 return '';
140 }
141}
142