PluginProbe
Themify Builder / 7.7.4
Themify Builder v7.7.4
7.8.1 7.8.0 7.7.9 7.7.8 7.7.7 7.7.6 7.7.5 7.7.4 7.7.3 7.7.2 trunk 7.6.0 7.6.1 7.6.2 7.6.3 7.6.4 7.6.5 7.6.6 7.6.7 7.6.8 7.6.9 7.7.0 7.7.1
themify-builder / modules / module-widget.php

module-widget.php in Themify Builder 7.7.4, at modules/module-widget.php

344 lines 12.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 defined('ABSPATH') || exit;
4
5 /**
6 * Module Name: Widget
7 * Description: Display any available widgets
8 */
9 class TB_Widget_Module extends Themify_Builder_Component_Module {
10
11 public static function init():void {
12 add_action('wp_ajax_tb_get_widget_items', array(__CLASS__, 'get_items'));
13 add_action('wp_ajax_module_widget_get_form', array(__CLASS__, 'widget_get_form'), 10);
14 add_action('tb_data_before_save', array(__CLASS__, 'before_builder_save'), 10, 2);
15 }
16
17 public static function get_module_name():string {
18 return __('Widget', 'themify');
19 }
20
21 public static function get_items() {
22 check_ajax_referer( 'tf_nonce', 'nonce' );
23 $result = array();
24 global $wp_widget_factory;
25 if (!empty($wp_widget_factory->widgets)) {
26 foreach ($wp_widget_factory->widgets as $widget) {
27 $class = get_class($widget);
28 $result[$class] = array('n' => $widget->name, 'b' => $widget->id_base);
29 if (!empty($widget->widget_options['description'])) {
30 $result[$class]['d'] = $widget->widget_options['description'];
31 }
32 }
33 }
34
35 $columns = array_column($result, 'n');
36 array_multisort($columns, SORT_ASC, $result);
37
38 die(json_encode($result));
39 }
40
41 /**
42 * Get a widget's registered key in $wp_widget_factory from its classname.
43 * register_widget() works with WP_Widget instances too, in such cases the
44 * widget's key is a hashed string.
45 *
46 * @return string|null
47 */
48 public static function get_widget_factory_name($classname) {
49 if (empty($classname) || !class_exists($classname,false)) {
50 return;
51 }
52 global $wp_widget_factory;
53 if (isset($wp_widget_factory->widgets[$classname])) {
54 return $classname;
55 }
56 foreach ($wp_widget_factory->widgets as $key => $widget) {
57 if ($widget instanceof WP_Widget && get_class($widget) === $classname) {
58 return $key;
59 }
60 }
61 }
62
63 public static function widget_get_form() {
64 check_ajax_referer('tf_nonce', 'nonce');
65
66 global $wp_widget_factory;
67 require_once ABSPATH . 'wp-admin/includes/widgets.php';
68 $widget_class = $_POST['load_class'];
69 if ($widget_class == '') {
70 die(-1);
71 }
72 $widget_class = str_replace('\\\\', '\\', $widget_class);
73
74 try {
75 $instance = !empty($_POST['widget_instance']) && $_POST['widget_instance'] !== 'null' ? $_POST['widget_instance'] : array();
76 if ( is_string( $instance ) ) {
77 $instance = json_decode( stripslashes( $instance ), true );
78 }
79 } catch( Exception $e ) {
80 $instance = [];
81 }
82 $instance = TB_Widget_Module::sanitize_widget_instance($instance);
83
84 $widget_key = self::get_widget_factory_name($widget_class);
85 if (!$widget_key) {
86 die(-1);
87 }
88 $widget = $wp_widget_factory->widgets[$widget_key];
89
90 $widget->number = next_widget_id_number($_POST['id_base']);
91 ob_start();
92 $instance = stripslashes_deep($instance);
93 $template = '';
94 $src = array();
95
96 if (empty($_POST['tpl_loaded']) && method_exists($widget, 'render_control_template_scripts')) {
97 require_once ABSPATH . WPINC . '/media-template.php';
98 ob_start();
99 $widget->render_control_template_scripts();
100 if ($widget->id_base !== 'text') {
101 wp_print_media_templates();
102 }
103
104 $template = ob_get_contents();
105 ob_end_clean();
106 $widget->enqueue_admin_scripts();
107 $type = str_replace('_', '-', $widget->id_base) . '-widget';
108 if ($widget->id_base === 'text') {
109 $type .= 's';
110 }
111 wp_enqueue_script($type);
112 global $wp_scripts;
113 if (isset($wp_scripts->registered[$type])) {
114 $script = $wp_scripts->registered[$type];
115 if ($widget->id_base !== 'text' && !empty($wp_scripts->registered[$type]->deps)) {
116 foreach ($wp_scripts->registered[$type]->deps as $deps) {
117 $src[] = array('src' => self::resolve_script_path($wp_scripts->registered[$deps]->src));
118 }
119 }
120
121 $src[] = array('src' => self::resolve_script_path($script->src), 'extra' => !empty($script->extra) ? $script->extra : '');
122 }
123 }
124
125 /* prevent errors */
126 set_error_handler(function($errno, $errstr, $errfile, $errline) {
127 return false;
128 });
129 try{
130 @$widget->form($instance);
131 }
132 catch(Throwable $e){
133 }
134 restore_error_handler();
135
136 do_action('in_widget_form', $widget, null, $instance);
137 $form = ob_get_clean();
138 $base_name = 'widget-' . $widget->id_base . '\[' . $widget->number . '\]';
139 $form = preg_replace("/{$base_name}/", '', $form); // remove extra names
140 $form = str_replace(array(
141 '[',
142 ']'
143 ), '', $form); // remove extra [ & ] characters
144 $widget->form = $form;
145
146 /**
147 * The widget-id is not used to save widget data, it is however needed for compatibility
148 * with how core renders the module forms.
149 */
150 $form = '<div class="widget open">
151 <div class="widget-inside">
152 <div class="form">
153 <div class="widget-content">'
154 . $form .
155 '</div>
156 <input type="hidden" class="id_base" name="id_base" value="' . esc_attr($widget->id_base) . '" />
157 <input type="hidden" class="widget-id" name="widget-id" value="w_' . time() . '" />
158 <input type="hidden" class="widget-class" name="widget-class" value="' . $widget_class . '" />
159 </div>
160 </div>
161 <br/>
162 </div>';
163
164 global $wp_version;
165 wp_send_json(array(
166 'form' => $form,
167 'template' => $template,
168 'v' => $wp_version,
169 'src' => $src
170 ));
171 wp_die();
172 }
173
174 private static function resolve_script_path($src) {
175
176 $content_url = defined('WP_CONTENT_URL') ? WP_CONTENT_URL : '';
177
178 if (!preg_match('|^(https?:)?//|', $src) && !( $content_url && 0 === strpos($src, $content_url) )) {
179 if (!($guessurl = site_url() )) {
180 $guessurl = wp_guess_url();
181 }
182 $src = $guessurl . $src;
183 }
184
185 return $src;
186 }
187
188 /*
189 * Sanitize keys for widget fields
190 * This is required to provide backward compatibility with how widget data was saved.
191 *
192 * @return array
193 * @since 3.2.0
194 */
195
196 public static function sanitize_widget_instance($instance) {
197 if (is_array($instance)) {
198 foreach ($instance as $key => $val) {
199 preg_match('/.*\[\d\]\[(.*)\]/', $key, $matches);
200 if (isset($matches[1])) {
201 unset($instance[$key]);
202 $instance[$matches[1]] = $val;
203 }
204 }
205 }
206
207 return $instance;
208 }
209
210 /**
211 * Render plain content for static content.
212 *
213 * @param array $module
214 * @return string
215 */
216 public static function get_static_content(array $module):string {
217 if (!isset($module['mod_settings'])) {
218 return '';
219 }
220 return isset($module['mod_settings']['class_widget']) && 'Themify_Social_Links' === $module['mod_settings']['class_widget']?self::social_links_plain_content():parent::get_static_content($module);
221 }
222
223 private static function social_links_plain_content():string {
224 $out = '';
225 if (function_exists('themify_get_data')){
226 $data = themify_get_data();
227 $pre = 'setting-link_';
228
229 $field_ids = isset($data[$pre . 'field_ids']) ? json_decode($data[$pre . 'field_ids']) : false;
230
231 if (is_array($field_ids) || is_object($field_ids)) {
232 $out .= '<ul>';
233 $is_exist = function_exists('icl_t');
234 foreach ($field_ids as $fid) {
235
236 $title_name = $pre . 'title_' . $fid;
237
238 if ($is_exist) {
239 $title_val = icl_t('Themify', $title_name, $data[$title_name]);
240 } else {
241 $title_val = isset($data[$title_name]) ? $data[$title_name] : '';
242 }
243
244 $link_name = $pre . 'link_' . $fid;
245 $link_val = isset($data[$link_name]) ? trim($data[$link_name]) : '';
246 if ('' === $link_val) {
247 continue;
248 }
249 $out .= sprintf('<li><a href="%s">%s</a></li>', esc_url($link_val), $title_val);
250 }
251 $out .= '</ul>';
252 }
253 }
254 return $out;
255 }
256
257 /**
258 * Before Builder saves data, find all Widget modules and call
259 * WP_Widget::update() method on widget instance data.
260 *
261 * @return array
262 */
263 public static function before_builder_save(array $builder_data, $post_id) {
264 if (!empty($builder_data)) {
265 if (strpos(json_encode($builder_data), 'class_widget') !== false) {
266 foreach ($builder_data as $row_index => $row) {
267 if (!empty($row['cols'])) {
268 foreach ($row['cols'] as $col_index => $column) {
269 if (!empty($column['modules'])) {
270 foreach ($column['modules'] as $module_index => $module) {
271 if (!empty($module['cols'])) {
272 foreach ($module['cols'] as $sub_column_index => $sub_column) {
273 if (!empty($sub_column['modules'])) {
274 foreach ($sub_column['modules'] as $sub_module_index => $sub_module) {
275 if (isset($sub_module['mod_name']) && $sub_module['mod_name'] === 'widget') {
276 $builder_data[$row_index]['cols'][$col_index]['modules'][$module_index]['cols'][$sub_column_index]['modules'][$sub_module_index] = self::call_widget_update($sub_module);
277 }
278 }
279 }
280 }
281 }
282 if (isset($module['mod_name']) && $module['mod_name'] === 'widget') {
283 $builder_data[$row_index]['cols'][$col_index]['modules'][$module_index] = self::call_widget_update($module);
284 }
285 }
286 }
287 }
288 }
289 }
290 }
291 }
292 return $builder_data;
293 }
294
295 /**
296 * Takes a $module array, for "widget" modules will call WP_Widget::update() method
297 * on the widget instance data
298 *
299 * @return array
300 */
301 private static function call_widget_update($module) {
302 if (!empty($module['mod_settings']['instance_widget'])) {
303 global $wp_widget_factory;
304 $widget_class = $module['mod_settings']['class_widget'];
305 if (isset($wp_widget_factory->widgets[$widget_class])) {
306 set_error_handler(function($errno, $errstr, $errfile, $errline) {
307 return false;
308 });
309 try{
310 @$instance = $wp_widget_factory->widgets[$widget_class]->update($module['mod_settings']['instance_widget'], array());
311 /** documented in wp-includes/class-wp-widget.php */
312 @$instance = apply_filters( 'widget_update_callback', $instance, $module['mod_settings']['instance_widget'], $module['mod_settings']['instance_widget'], $wp_widget_factory->widgets[$widget_class] );
313 }
314 catch(Throwable $e){
315 }
316 restore_error_handler();
317
318 if (!isset($instance['widget-id']) && isset($module['mod_settings']['instance_widget']['widget-id'])) {
319 $instance['widget-id'] = $module['mod_settings']['instance_widget']['widget-id'];
320 }
321 $module['mod_settings']['instance_widget'] = $instance;
322 }
323 }
324 return $module;
325 }
326
327 public static function widget_gallery_lightbox($markup) {
328 return str_replace('<a', '<a class="themify_lightbox"', $markup);
329 }
330
331 public static function get_styling_image_fields() : array {
332 return [
333 'background_image' => '',
334 'b_i_w_t' => '.module .widgettitle'
335 ];
336 }
337
338 public static function get_translatable_text_fields( $module ) : array {
339 return [ 'mod_title_widget' ];
340 }
341 }
342
343 TB_Widget_Module::init();
344