Unyson - Version 2.4.17

Version Description

  • Fixed #1197
  • Added 'oembed' option type (docs)
  • fixed: fw_get_db_customizer_option() infinite recursion when called with default value inside customizer.php
Download this release

Release Info

Developer Unyson
Plugin Icon 128x128 Unyson
Version 2.4.17
Comparing to
See all releases

Code changes from version 2.4.16 to 2.4.17

framework/helpers/class-fw-cache.php CHANGED
@@ -22,12 +22,11 @@
22
  */
23
  class FW_Cache
24
  {
25
- protected static $cache = array();
26
-
27
  /**
28
- * @var bool
 
29
  */
30
- protected static $is_enabled;
31
 
32
  /**
33
  * If the PHP will have less that this memory, the cache will try to delete parts from its array to free memory
@@ -41,8 +40,33 @@ class FW_Cache
41
  */
42
  protected static $memory_limit = null;
43
 
 
 
 
 
44
  protected static $not_found_value;
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  protected static function get_memory_limit()
47
  {
48
  if (self::$memory_limit === null) {
@@ -74,16 +98,86 @@ class FW_Cache
74
  */
75
  public static function _init()
76
  {
77
- self::$is_enabled = function_exists('register_tick_function');
78
  self::$not_found_value = new FW_Cache_Not_Found_Exception();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  }
80
 
 
 
 
 
 
81
  public static function is_enabled()
82
  {
83
- return self::$is_enabled;
84
  }
85
 
86
- public static function free_memory()
87
  {
88
  while (self::memory_exceeded() && !empty(self::$cache)) {
89
  reset(self::$cache);
@@ -92,6 +186,13 @@ class FW_Cache
92
 
93
  unset(self::$cache[$key]);
94
  }
 
 
 
 
 
 
 
95
  }
96
 
97
  /**
@@ -101,7 +202,7 @@ class FW_Cache
101
  */
102
  public static function set($keys, $value, $keys_delimiter = '/')
103
  {
104
- if (!self::$is_enabled) {
105
  return;
106
  }
107
 
@@ -149,10 +250,14 @@ class FW_Cache
149
  self::free_memory();
150
 
151
  if ($value === self::$not_found_value) {
 
 
152
  throw new FW_Cache_Not_Found_Exception();
153
- }
 
154
 
155
- return $value;
 
156
  }
157
 
158
  /**
@@ -162,15 +267,29 @@ class FW_Cache
162
  {
163
  self::$cache = array();
164
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  }
166
 
167
  class FW_Cache_Not_Found_Exception extends Exception {}
168
 
169
- FW_Cache::_init();
170
-
171
- // auto free_memory() every X ticks
172
- if (FW_Cache::is_enabled()) {
173
- declare(ticks=3000);
174
-
175
- register_tick_function(array('FW_Cache', 'free_memory'));
176
- }
22
  */
23
  class FW_Cache
24
  {
 
 
25
  /**
26
+ * The actual cache
27
+ * @var array
28
  */
29
+ protected static $cache = array();
30
 
31
  /**
32
  * If the PHP will have less that this memory, the cache will try to delete parts from its array to free memory
40
  */
41
  protected static $memory_limit = null;
42
 
43
+ /**
44
+ * A special value that is used to detect if value was found in cache
45
+ * We can't use null|false because these can be values set by user and we can't treat them as not existing values
46
+ */
47
  protected static $not_found_value;
48
 
49
+ /**
50
+ * The amount of times the data was already stored in the cache.
51
+ * @var int
52
+ * @since 2.4.17
53
+ */
54
+ protected static $hits = 0;
55
+
56
+ /**
57
+ * Amount of times the cache did not have the value in cache.
58
+ * @var int
59
+ * @since 2.4.17
60
+ */
61
+ protected static $misses = 0;
62
+
63
+ /**
64
+ * Amount of times the cache free was called.
65
+ * @var int
66
+ * @since 2.4.17
67
+ */
68
+ protected static $freed = 0;
69
+
70
  protected static function get_memory_limit()
71
  {
72
  if (self::$memory_limit === null) {
98
  */
99
  public static function _init()
100
  {
 
101
  self::$not_found_value = new FW_Cache_Not_Found_Exception();
102
+
103
+ /**
104
+ * Listen often triggered hooks to clear the memory
105
+ * instead of tick function https://github.com/ThemeFuse/Unyson/issues/1197
106
+ * @since 2.4.17
107
+ */
108
+ foreach (array(
109
+ 'query' => true,
110
+ 'plugins_loaded' => true,
111
+ 'wp_get_object_terms' => true,
112
+ 'created_term' => true,
113
+ 'wp_upgrade' => true,
114
+ 'added_option' => true,
115
+ 'updated_option' => true,
116
+ 'deleted_option' => true,
117
+ 'wp_after_admin_bar_render' => true,
118
+ 'http_response' => true,
119
+ 'oembed_result' => true,
120
+ 'customize_post_value_set' => true,
121
+ 'customize_save_after' => true,
122
+ 'customize_render_panel' => true,
123
+ 'customize_render_control' => true,
124
+ 'customize_render_section' => true,
125
+ 'role_has_cap' => true,
126
+ 'user_has_cap' => true,
127
+ 'theme_page_templates' => true,
128
+ 'pre_get_users' => true,
129
+ 'request' => true,
130
+ 'send_headers' => true,
131
+ 'updated_usermeta' => true,
132
+ 'added_usermeta' => true,
133
+ 'image_memory_limit' => true,
134
+ 'upload_dir' => true,
135
+ 'wp_head' => true,
136
+ 'wp_footer' => true,
137
+ 'wp' => true,
138
+ 'wp_init' => true,
139
+ 'fw_init' => true,
140
+ 'init' => true,
141
+ 'updated_postmeta' => true,
142
+ 'deleted_postmeta' => true,
143
+ 'setted_transient' => true,
144
+ 'registered_post_type' => true,
145
+ 'wp_count_posts' => true,
146
+ 'wp_count_attachments' => true,
147
+ 'after_delete_post' => true,
148
+ 'post_updated' => true,
149
+ 'wp_insert_post' => true,
150
+ 'deleted_post' => true,
151
+ 'clean_post_cache' => true,
152
+ 'wp_restore_post_revision' => true,
153
+ 'wp_delete_post_revision' => true,
154
+ 'get_term' => true,
155
+ 'edited_term_taxonomies' => true,
156
+ 'deleted_term_taxonomy' => true,
157
+ 'edited_terms' => true,
158
+ 'created_term' => true,
159
+ 'clean_term_cache' => true,
160
+ 'edited_term_taxonomy' => true,
161
+ 'switch_theme' => true,
162
+ 'wp_get_update_data' => true,
163
+ 'clean_user_cache' => true,
164
+ 'process_text_diff_html' => true,
165
+ ) as $hook => $tmp) {
166
+ add_filter($hook, array(__CLASS__, 'free_memory'), 9999);
167
+ }
168
  }
169
 
170
+ /**
171
+ * This method does nothing @since 2.4.17
172
+ * but we can't delete it because it's public and maybe somebody is calling it
173
+ * @return bool
174
+ */
175
  public static function is_enabled()
176
  {
177
+ return true;
178
  }
179
 
180
+ public static function free_memory($dummy = null)
181
  {
182
  while (self::memory_exceeded() && !empty(self::$cache)) {
183
  reset(self::$cache);
186
 
187
  unset(self::$cache[$key]);
188
  }
189
+
190
+ ++self::$freed;
191
+
192
+ /**
193
+ * This method is used add_filter() so to not break anything return filter value
194
+ */
195
+ return $dummy;
196
  }
197
 
198
  /**
202
  */
203
  public static function set($keys, $value, $keys_delimiter = '/')
204
  {
205
+ if (!self::is_enabled()) {
206
  return;
207
  }
208
 
250
  self::free_memory();
251
 
252
  if ($value === self::$not_found_value) {
253
+ ++self::$misses;
254
+
255
  throw new FW_Cache_Not_Found_Exception();
256
+ } else {
257
+ ++self::$hits;
258
 
259
+ return $value;
260
+ }
261
  }
262
 
263
  /**
267
  {
268
  self::$cache = array();
269
  }
270
+
271
+ /**
272
+ * Debug information
273
+ * <?php add_action('admin_footer', function(){ FW_Cache::stats(); });
274
+ * @since 2.4.17
275
+ */
276
+ public static function stats() {
277
+ echo '<div style="z-index: 10000; position: relative; background: #fff; padding: 15px;">';
278
+ echo '<p>';
279
+ echo '<strong>Cache Hits:</strong> '. self::$hits .'<br />';
280
+ echo '<strong>Cache Misses:</strong> '. self::$misses .'<br />';
281
+ echo '<strong>Cache Freed:</strong> '. self::$freed .'<br />';
282
+ echo '<strong>PHP Memory Peak Usage:</strong> '. fw_human_bytes(memory_get_peak_usage(false)) .'<br />';
283
+ echo '</p>';
284
+ echo '<ul>';
285
+ foreach (self::$cache as $group => $cache) {
286
+ echo "<li><strong>Group:</strong> $group - ( " . number_format( strlen( serialize( $cache ) ) / KB_IN_BYTES, 2 ) . 'k )</li>';
287
+ }
288
+ echo '</ul>';
289
+ echo '</div>';
290
+ }
291
  }
292
 
293
  class FW_Cache_Not_Found_Exception extends Exception {}
294
 
295
+ FW_Cache::_init();
 
 
 
 
 
 
 
framework/helpers/database.php CHANGED
@@ -422,12 +422,12 @@
422
  */
423
  function fw_get_db_customizer_option( $option_id = null, $default_value = null ) {
424
  // note: this contains only changed controls/options
425
- $all_db_values = get_theme_mod(FW_Option_Type::get_default_name_prefix(), null);
426
 
427
  if (
428
  !is_null($default_value)
429
  &&
430
- is_null($option_id ? fw_akg($option_id, $all_db_values) : $all_db_values)
431
  ) {
432
  /**
433
  * Default value was provided in case db value is empty.
@@ -439,46 +439,44 @@
439
  return $default_value;
440
  }
441
 
442
- // extract options default values
443
- {
444
- $cache_key = 'fw_default_options_values/customizer';
445
-
446
- try {
447
- $all_default_values = FW_Cache::get( $cache_key );
448
- } catch ( FW_Cache_Not_Found_Exception $e ) {
449
- // extract the default values from options array
450
- $all_default_values = fw_get_options_values_from_input(
451
- fw()->theme->get_customizer_options(),
452
- array()
453
- );
454
 
455
- FW_Cache::set( $cache_key, $all_default_values );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456
  }
457
- }
458
 
459
- if (is_null($all_db_values)) {
460
- $all_db_values = array();
461
  }
462
 
463
- if (is_null($option_id)) {
464
- return array_merge(
465
- $all_default_values,
466
- $all_db_values
467
- );
468
- } else {
469
- $base_key = explode('/', $option_id); // note: option_id can be a multi-key 'a/b/c'
470
- $base_key = array_shift($base_key);
471
-
472
- $all_db_values = array_key_exists($base_key, $all_db_values)
473
- ? $all_db_values
474
- : $all_default_values;
475
-
476
- return fw_akg(
477
- $option_id,
478
- $all_db_values,
479
- $default_value
480
- );
481
- }
482
  }
483
 
484
  /**
422
  */
423
  function fw_get_db_customizer_option( $option_id = null, $default_value = null ) {
424
  // note: this contains only changed controls/options
425
+ $db_values = get_theme_mod(FW_Option_Type::get_default_name_prefix(), null);
426
 
427
  if (
428
  !is_null($default_value)
429
  &&
430
+ is_null($option_id ? fw_akg($option_id, $db_values) : $db_values)
431
  ) {
432
  /**
433
  * Default value was provided in case db value is empty.
439
  return $default_value;
440
  }
441
 
442
+ if (is_null($db_values)) {
443
+ $db_values = array();
444
+ }
 
 
 
 
 
 
 
 
 
445
 
446
+ if (
447
+ is_null($option_id)
448
+ ||
449
+ (
450
+ ($base_key = explode('/', $option_id)) // note: option_id can be a multi-key 'a/b/c'
451
+ &&
452
+ ($base_key = array_shift($base_key))
453
+ &&
454
+ !array_key_exists($base_key, $db_values)
455
+ )
456
+ ) {
457
+ // extract options default values
458
+ {
459
+ $cache_key = 'fw_default_options_values/customizer';
460
+
461
+ try {
462
+ $default_values = FW_Cache::get( $cache_key );
463
+ } catch ( FW_Cache_Not_Found_Exception $e ) {
464
+ // extract the default values from options array
465
+ $default_values = fw_get_options_values_from_input(
466
+ fw()->theme->get_customizer_options(),
467
+ array()
468
+ );
469
+
470
+ FW_Cache::set( $cache_key, $default_values );
471
+ }
472
  }
 
473
 
474
+ $db_values = array_merge($default_values, $db_values);
 
475
  }
476
 
477
+ return is_null($option_id)
478
+ ? $db_values
479
+ : fw_akg($option_id, $db_values, $default_value);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480
  }
481
 
482
  /**
framework/helpers/general.php CHANGED
@@ -1143,8 +1143,7 @@ function fw_current_user_can($capabilities, $default_value = null)
1143
  * @param int $seconds
1144
  * @return string
1145
  */
1146
- function fw_human_time($seconds)
1147
- {
1148
  static $translations = null;
1149
  if ($translations === null) {
1150
  $translations = array(
@@ -1191,6 +1190,39 @@ function fw_human_time($seconds)
1191
  }
1192
  }
1193
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1194
  function fw_strlen($string) {
1195
  if (function_exists('mb_strlen')) {
1196
  return mb_strlen($string, 'UTF-8');
@@ -1265,7 +1297,7 @@ function fw_oembed_get($url, $args = array()) {
1265
 
1266
  if (!empty($args['width']) and !empty($args['height']) and class_exists('DOMDocument') and !empty($html)) {
1267
  $dom_element = new DOMDocument();
1268
- $dom_element->loadHTML($html);
1269
  $obj = $dom_element->getElementsByTagName('iframe')->item(0);
1270
  $obj->setAttribute('width', $args['width']);
1271
  $obj->setAttribute('height', $args['height']);
1143
  * @param int $seconds
1144
  * @return string
1145
  */
1146
+ function fw_human_time($seconds) {
 
1147
  static $translations = null;
1148
  if ($translations === null) {
1149
  $translations = array(
1190
  }
1191
  }
1192
 
1193
+ /**
1194
+ * Convert bytes to human readable format
1195
+ *
1196
+ * @param integer $bytes Size in bytes to convert
1197
+ * @param integer $precision
1198
+ * @return string
1199
+ * @since 2.4.17
1200
+ */
1201
+ function fw_human_bytes($bytes, $precision = 2) {
1202
+ $kilobyte = 1024;
1203
+ $megabyte = $kilobyte * 1024;
1204
+ $gigabyte = $megabyte * 1024;
1205
+ $terabyte = $gigabyte * 1024;
1206
+
1207
+ if (($bytes >= 0) && ($bytes < $kilobyte)) {
1208
+ return $bytes . ' B';
1209
+
1210
+ } elseif (($bytes >= $kilobyte) && ($bytes < $megabyte)) {
1211
+ return round($bytes / $kilobyte, $precision) . ' KB';
1212
+
1213
+ } elseif (($bytes >= $megabyte) && ($bytes < $gigabyte)) {
1214
+ return round($bytes / $megabyte, $precision) . ' MB';
1215
+
1216
+ } elseif (($bytes >= $gigabyte) && ($bytes < $terabyte)) {
1217
+ return round($bytes / $gigabyte, $precision) . ' GB';
1218
+
1219
+ } elseif ($bytes >= $terabyte) {
1220
+ return round($bytes / $terabyte, $precision) . ' TB';
1221
+ } else {
1222
+ return $bytes . ' B';
1223
+ }
1224
+ }
1225
+
1226
  function fw_strlen($string) {
1227
  if (function_exists('mb_strlen')) {
1228
  return mb_strlen($string, 'UTF-8');
1297
 
1298
  if (!empty($args['width']) and !empty($args['height']) and class_exists('DOMDocument') and !empty($html)) {
1299
  $dom_element = new DOMDocument();
1300
+ @$dom_element->loadHTML($html);
1301
  $obj = $dom_element->getElementsByTagName('iframe')->item(0);
1302
  $obj->setAttribute('width', $args['width']);
1303
  $obj->setAttribute('height', $args['height']);
framework/includes/option-types/init.php CHANGED
@@ -30,6 +30,7 @@ require $dir . '/slider/class-fw-option-type-short-slider.php';
30
  require $dir . '/range-slider/class-fw-option-type-range-slider.php';
31
  require $dir . '/rgba-color-picker/class-fw-option-type-rgba-color-picker.php';
32
  require $dir . '/typography-v2/class-fw-option-type-typography-v2.php';
 
33
  if (!class_exists('FW_Option_Type_Multi_Select')) {
34
  require $dir . '/multi-select/class-fw-option-type-multi-select.php';
35
  }
30
  require $dir . '/range-slider/class-fw-option-type-range-slider.php';
31
  require $dir . '/rgba-color-picker/class-fw-option-type-rgba-color-picker.php';
32
  require $dir . '/typography-v2/class-fw-option-type-typography-v2.php';
33
+ require $dir . '/oembed/class-fw-option-type-oembed.php';
34
  if (!class_exists('FW_Option_Type_Multi_Select')) {
35
  require $dir . '/multi-select/class-fw-option-type-multi-select.php';
36
  }
framework/includes/option-types/oembed/class-fw-option-type-oembed.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'FW' ) ) {
2
+ die( 'Forbidden' );
3
+ }
4
+
5
+ class FW_Option_Type_Oembed extends FW_Option_Type {
6
+
7
+ /**
8
+ * Option's unique type, used in option array in 'type' key
9
+ * @return string
10
+ */
11
+ public function get_type() {
12
+ return 'oembed';
13
+ }
14
+
15
+ /**
16
+ * Generate html
17
+ *
18
+ * @param string $id
19
+ * @param array $option Option array merged with _get_defaults()
20
+ * @param array $data {value => _get_value_from_input(), id_prefix => ..., name_prefix => ...}
21
+ *
22
+ * @return string HTML
23
+ * @internal
24
+ */
25
+ protected function _render( $id, $option, $data ) {
26
+
27
+ $defaults = $this->_get_defaults();
28
+ $option['preview'] = array_merge( $defaults['preview'], $option['preview'] );
29
+ $option['attr'] =array_merge($defaults['attr'], $option['attr']);
30
+
31
+ return fw_render_view(
32
+ fw_get_framework_directory( '/includes/option-types/' . $this->get_type() . '/view.php' ),
33
+ compact( 'id', 'option', 'data' )
34
+ );
35
+ }
36
+
37
+ /**
38
+ * Extract correct value for $option['value'] from input array
39
+ * If input value is empty, will be returned $option['value']
40
+ *
41
+ * @param array $option Option array merged with _get_defaults()
42
+ * @param array|string|null $input_value
43
+ *
44
+ * @return string|array|int|bool Correct value
45
+ * @internal
46
+ */
47
+ protected function _get_value_from_input( $option, $input_value ) {
48
+ return (string) ( is_null( $input_value ) ? $option['value'] : $input_value );
49
+ }
50
+
51
+ /**
52
+ * Default option array
53
+ *
54
+ * This makes possible an option array to have required only one parameter: array('type' => '...')
55
+ * Other parameters are merged with the array returned by this method.
56
+ *
57
+ * @return array
58
+ *
59
+ * array(
60
+ * 'value' => '',
61
+ * ...
62
+ * )
63
+ * @internal
64
+ */
65
+ protected function _get_defaults() {
66
+ return array(
67
+ 'value' => '',
68
+ 'attr' => array(
69
+ 'placeholder' => 'https://www.youtube.com'
70
+ ),
71
+ 'preview' => array(
72
+ 'width' => 428,
73
+ 'height' => 320,
74
+ /**
75
+ * by default wp_get_embed maintain ratio and return changed width and height values of the iframe,
76
+ * if you set it to false , the dimensions will be forced to change as in preview.width and preview.height
77
+ */
78
+ 'keep_ratio' => true
79
+ )
80
+ );
81
+ }
82
+
83
+ protected function _enqueue_static( $id, $option, $data ) {
84
+ wp_enqueue_style(
85
+ 'fw-option-' . $this->get_type(),
86
+ fw_get_framework_directory_uri( '/includes/option-types/' . $this->get_type() . '/static/css/styles.css' ),
87
+ array( 'fw' )
88
+ );
89
+
90
+ wp_enqueue_script(
91
+ 'fw-option-' . $this->get_type(),
92
+ fw_get_framework_directory_uri( '/includes/option-types/' . $this->get_type() . '/static/js/' . $this->get_type() . '.js' ),
93
+ array( 'underscore', 'fw-events', 'fw', 'wp-util' ),
94
+ false,
95
+ true
96
+ );
97
+ }
98
+
99
+ public static function _action_get_oembed_response() {
100
+
101
+ if ( wp_verify_nonce( FW_Request::POST( '_nonce' ), '_action_get_oembed_response' ) ) {
102
+
103
+ $url = FW_Request::POST( 'url' );
104
+ $width = FW_Request::POST( 'preview/width' );
105
+ $height = FW_Request::POST( 'preview/height' );
106
+ $keep_ratio = ( FW_Request::POST( 'preview/keep_ratio' ) === 'true' );
107
+
108
+ $iframe = empty( $keep_ratio ) ?
109
+ fw_oembed_get( $url, compact( 'width', 'height' ) ) :
110
+ wp_oembed_get( $url, compact( 'width', 'height' ) );
111
+
112
+ wp_send_json_success( array( 'response' => $iframe ) );
113
+ }
114
+
115
+ wp_send_json_error( array( 'message' => 'Invalid nonce' ) );
116
+ }
117
+ }
118
+
119
+ FW_Option_Type::register( 'FW_Option_Type_Oembed' );
120
+
121
+ add_action(
122
+ 'wp_ajax_get_oembed_response',
123
+ array( "FW_Option_Type_Oembed", '_action_get_oembed_response' )
124
+ );
framework/includes/option-types/oembed/static/css/styles.css ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .fw-oembed-preview img,
2
+ .fw-oembed-preview iframe,
3
+ .fw-oembed-preview embed
4
+ {
5
+ max-width: 100%;
6
+ vertical-align: middle;
7
+ }
8
+
9
+ .fw-oembed-preview a {
10
+ display: inline-block;
11
+ }
12
+
13
+ .fw-oembed-preview img {
14
+ display: block;
15
+ height: auto;
16
+ }
17
+ .fw-oembed-preview {
18
+ padding-top: 7px;
19
+ }
framework/includes/option-types/oembed/static/js/oembed.js ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($, _, fwEvents) {
2
+ var oembed = function () {
3
+ var $wrapper = $(this);
4
+ var $input = $wrapper.find('input[type=text]');
5
+ var $iframeWrapper = $wrapper.find('.fw-oembed-preview');
6
+
7
+ $input.on('input',
8
+ _.debounce(function () {
9
+ wp.ajax.post(
10
+ 'get_oembed_response',
11
+ {
12
+ '_nonce': $wrapper.data('nonce'),
13
+ 'preview': $wrapper.data('preview'),
14
+ 'url': $input.val()
15
+ }).done(function (data) {
16
+ $iframeWrapper.html(data.response);
17
+ }).fail(function () {
18
+ })
19
+
20
+ }, 300)
21
+ );
22
+ };
23
+
24
+ fwEvents.on('fw:options:init', function (data) {
25
+ data.$elements
26
+ .find('.fw-option-type-oembed:not(.fw-option-initialized)').each(oembed)
27
+ .addClass('fw-option-initialized');
28
+ });
29
+ })(jQuery, _, fwEvents);
framework/includes/option-types/oembed/view.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'FW' ) ) {
2
+ die( 'Forbidden' );
3
+ }
4
+
5
+ $wrapper_attr = $option['attr'];
6
+ $wrapper_attr['data-nonce'] = wp_create_nonce( '_action_get_oembed_response' );
7
+ $wrapper_attr['data-preview'] = json_encode( $option['preview'] );
8
+
9
+ unset(
10
+ $wrapper_attr['value'],
11
+ $wrapper_attr['name'],
12
+ $wrapper_attr['placeholder']
13
+ );
14
+
15
+ $input_attr['value'] = $data['value'];
16
+ $input_attr['name'] = $option['attr']['name'];
17
+ $input_attr['placeholder'] = $option['attr']['placeholder'];
18
+ ?>
19
+ <div <?php echo fw_attr_to_html( $wrapper_attr ) ?>>
20
+
21
+ <div class="fw-oembed-input">
22
+ <input type="text" <?php echo fw_attr_to_html( $input_attr ); ?>/>
23
+ </div>
24
+ <div class="fw-oembed-preview">
25
+ <?php
26
+ $iframe = empty( $option['preview']['keep_ratio'] ) ? fw_oembed_get( $data['value'], array(
27
+ 'height' => $option['preview']['height'],
28
+ 'width' => $option['preview']['width']
29
+ ) ) :
30
+ wp_oembed_get( $data['value'], array(
31
+ 'height' => $option['preview']['height'],
32
+ 'width' => $option['preview']['width']
33
+ ) );
34
+
35
+ echo $iframe;
36
+ ?>
37
+ </div>
38
+ </div>
framework/manifest.php CHANGED
@@ -4,4 +4,4 @@ $manifest = array();
4
 
5
  $manifest['name'] = __('Unyson', 'fw');
6
 
7
- $manifest['version'] = '2.4.16';
4
 
5
  $manifest['name'] = __('Unyson', 'fw');
6
 
7
+ $manifest['version'] = '2.4.17';
framework/static/css/fw.css CHANGED
@@ -2923,6 +2923,10 @@ body.wp-customizer > div:not(.fw-modal) > .media-modal-backdrop {
2923
  transition-duration: .6s;
2924
  }
2925
 
 
 
 
 
2926
  /* end: open animation */
2927
 
2928
  /* close animation */
2923
  transition-duration: .6s;
2924
  }
2925
 
2926
+ .fw-modal.fw-modal-open > .media-modal > .media-modal-close:focus {
2927
+ outline: 0;
2928
+ }
2929
+
2930
  /* end: open animation */
2931
 
2932
  /* close animation */
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: unyson
3
  Tags: page builder, cms, grid, layout, responsive, back up, backup, db backup, dump, migrate, schedule, search engine optimization, seo, media, slideshow, shortcode, slide, slideshare, slideshow, google sitemaps, sitemaps, analytics, google analytics, calendar, event, events, google maps, learning, lessons, sidebars, breadcrumbs, review, portfolio, framework
4
  Requires at least: 4.0.0
5
  Tested up to: 4.4
6
- Stable tag: 2.4.16
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -83,6 +83,11 @@ Yes; Unyson will work with any theme.
83
 
84
  == Changelog ==
85
 
 
 
 
 
 
86
  = 2.4.16 =
87
  * Fixed [#1178](https://github.com/ThemeFuse/Unyson/issues/1178), [#1179](https://github.com/ThemeFuse/Unyson/issues/1179), [#1169](https://github.com/ThemeFuse/Unyson/issues/1169), [#1085](https://github.com/ThemeFuse/Unyson/issues/1085)
88
 
3
  Tags: page builder, cms, grid, layout, responsive, back up, backup, db backup, dump, migrate, schedule, search engine optimization, seo, media, slideshow, shortcode, slide, slideshare, slideshow, google sitemaps, sitemaps, analytics, google analytics, calendar, event, events, google maps, learning, lessons, sidebars, breadcrumbs, review, portfolio, framework
4
  Requires at least: 4.0.0
5
  Tested up to: 4.4
6
+ Stable tag: 2.4.17
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
83
 
84
  == Changelog ==
85
 
86
+ = 2.4.17 =
87
+ * Fixed [#1197](https://github.com/ThemeFuse/Unyson/issues/1197)
88
+ * Added `'oembed'` option type ([docs](http://manual.unyson.io/en/latest/options/built-in-option-types.html#oembed))
89
+ * fixed: `fw_get_db_customizer_option()` infinite recursion when called with default value inside `customizer.php`
90
+
91
  = 2.4.16 =
92
  * Fixed [#1178](https://github.com/ThemeFuse/Unyson/issues/1178), [#1179](https://github.com/ThemeFuse/Unyson/issues/1179), [#1169](https://github.com/ThemeFuse/Unyson/issues/1169), [#1085](https://github.com/ThemeFuse/Unyson/issues/1085)
93
 
unyson.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Unyson
4
  * Plugin URI: http://unyson.io/
5
  * Description: A free drag & drop framework that comes with a bunch of built in extensions that will help you develop premium themes fast & easy.
6
- * Version: 2.4.16
7
  * Author: ThemeFuse
8
  * Author URI: http://themefuse.com
9
  * License: GPL2+
3
  * Plugin Name: Unyson
4
  * Plugin URI: http://unyson.io/
5
  * Description: A free drag & drop framework that comes with a bunch of built in extensions that will help you develop premium themes fast & easy.
6
+ * Version: 2.4.17
7
  * Author: ThemeFuse
8
  * Author URI: http://themefuse.com
9
  * License: GPL2+