Unyson - Version 2.2.3

Version Description

  • Fixed #397, #394, #389, 384, #355
  • Added option type runnable code
Download this release

Release Info

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

Code changes from version 2.2.2 to 2.2.3

framework/core/components/backend.php CHANGED
@@ -544,6 +544,7 @@ final class _FW_Component_Backend {
544
 
545
  unset( $box[ $id ] ); // free memory
546
  }
 
547
  }
548
 
549
  /**
@@ -1098,6 +1099,7 @@ final class _FW_Component_Backend {
1098
  )
1099
  );
1100
  }
 
1101
 
1102
  $html .= '</div>';
1103
  break;
@@ -1120,6 +1122,7 @@ final class _FW_Component_Backend {
1120
  $html .= $this->render_options( $group['options'], $values, $options_data );
1121
  $html .= '</div>';
1122
  }
 
1123
  break;
1124
  case 'option':
1125
  foreach ( $collected_type_options as $id => &$_option ) {
@@ -1134,6 +1137,7 @@ final class _FW_Component_Backend {
1134
  $design
1135
  );
1136
  }
 
1137
  break;
1138
  default:
1139
  $html .= '<p><em>' . __( 'Unknown collected type', 'fw' ) . ': ' . $collected_type . '</em></p>';
544
 
545
  unset( $box[ $id ] ); // free memory
546
  }
547
+ unset($box);
548
  }
549
 
550
  /**
1099
  )
1100
  );
1101
  }
1102
+ unset($box);
1103
 
1104
  $html .= '</div>';
1105
  break;
1122
  $html .= $this->render_options( $group['options'], $values, $options_data );
1123
  $html .= '</div>';
1124
  }
1125
+ unset($group);
1126
  break;
1127
  case 'option':
1128
  foreach ( $collected_type_options as $id => &$_option ) {
1137
  $design
1138
  );
1139
  }
1140
+ unset($_option);
1141
  break;
1142
  default:
1143
  $html .= '<p><em>' . __( 'Unknown collected type', 'fw' ) . ': ' . $collected_type . '</em></p>';
framework/core/components/extensions.php CHANGED
@@ -302,55 +302,98 @@ final class _FW_Component_Extensions
302
  }
303
  }
304
 
305
- private function load_all_extensions()
306
  {
307
- /**
308
- * { '/hello/world/extensions' => 'https://hello.com/world/extensions' }
309
- */
310
- $custom_locations = apply_filters('fw_extensions_locations', array());
311
 
312
- {
313
- $customizations_locations = array();
 
 
 
 
 
314
 
315
- if (is_child_theme()) {
316
- $customizations_locations[fw_get_stylesheet_customizations_directory('/extensions')]
317
- = fw_get_stylesheet_customizations_directory_uri('/extensions');
318
- }
319
 
320
- $customizations_locations[fw_get_template_customizations_directory('/extensions')]
321
- = fw_get_template_customizations_directory_uri('/extensions');
 
 
322
 
323
- $customizations_locations += $custom_locations;
324
- }
 
 
 
325
 
326
- self::load_extensions(array(
327
- 'path' => fw_get_framework_directory('/extensions'),
328
- 'uri' => fw_get_framework_directory_uri('/extensions'),
329
- 'customizations_locations' => $customizations_locations,
330
- ));
331
 
332
- foreach ($custom_locations as $path => $uri) {
333
- unset($customizations_locations[$path]);
334
- self::load_extensions(array(
335
- 'path' => $path,
336
- 'uri' => $uri,
337
  'customizations_locations' => $customizations_locations,
338
- ));
339
- }
 
 
 
 
340
 
341
- array_pop($customizations_locations);
342
- self::load_extensions(array(
343
- 'path' => fw_get_template_customizations_directory('/extensions'),
344
- 'uri' => fw_get_template_customizations_directory_uri('/extensions'),
345
- 'customizations_locations' => $customizations_locations,
346
- ));
 
 
 
 
 
 
 
347
 
348
- if (is_child_theme()) {
349
  array_pop($customizations_locations);
350
- self::load_extensions(array(
351
- 'path' => fw_get_stylesheet_customizations_directory('/extensions'),
352
- 'uri' => fw_get_stylesheet_customizations_directory_uri('/extensions'),
353
  'customizations_locations' => $customizations_locations,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  ));
355
  }
356
  }
@@ -409,6 +452,7 @@ final class _FW_Component_Extensions
409
  }
410
  }
411
  }
 
412
  }
413
 
414
  /**
302
  }
303
  }
304
 
305
+ public function get_locations()
306
  {
307
+ $cache_key = 'fw_extensions_locations';
 
 
 
308
 
309
+ try {
310
+ return FW_Cache::get($cache_key);
311
+ } catch (FW_Cache_Not_Found_Exception $e) {
312
+ /**
313
+ * { '/hello/world/extensions' => 'https://hello.com/world/extensions' }
314
+ */
315
+ $custom_locations = apply_filters('fw_extensions_locations', array());
316
 
317
+ {
318
+ $customizations_locations = array();
 
 
319
 
320
+ if (is_child_theme()) {
321
+ $customizations_locations[fw_get_stylesheet_customizations_directory('/extensions')]
322
+ = fw_get_stylesheet_customizations_directory_uri('/extensions');
323
+ }
324
 
325
+ $customizations_locations[fw_get_template_customizations_directory('/extensions')]
326
+ = fw_get_template_customizations_directory_uri('/extensions');
327
+
328
+ $customizations_locations += $custom_locations;
329
+ }
330
 
331
+ $locations = array();
 
 
 
 
332
 
333
+ $locations[ fw_get_framework_directory('/extensions') ] = array(
334
+ 'path' => fw_get_framework_directory('/extensions'),
335
+ 'uri' => fw_get_framework_directory_uri('/extensions'),
 
 
336
  'customizations_locations' => $customizations_locations,
337
+ 'is' => array(
338
+ 'framework' => true,
339
+ 'custom' => false,
340
+ 'theme' => false,
341
+ ),
342
+ );
343
 
344
+ foreach ($custom_locations as $path => $uri) {
345
+ unset($customizations_locations[$path]);
346
+ $locations[ $path ] = array(
347
+ 'path' => $path,
348
+ 'uri' => $uri,
349
+ 'customizations_locations' => $customizations_locations,
350
+ 'is' => array(
351
+ 'framework' => false,
352
+ 'custom' => true,
353
+ 'theme' => false,
354
+ ),
355
+ );
356
+ }
357
 
 
358
  array_pop($customizations_locations);
359
+ $locations[ fw_get_template_customizations_directory('/extensions') ] = array(
360
+ 'path' => fw_get_template_customizations_directory('/extensions'),
361
+ 'uri' => fw_get_template_customizations_directory_uri('/extensions'),
362
  'customizations_locations' => $customizations_locations,
363
+ 'is' => array(
364
+ 'framework' => false,
365
+ 'custom' => false,
366
+ 'theme' => true,
367
+ ),
368
+ );
369
+
370
+ if (is_child_theme()) {
371
+ array_pop($customizations_locations);
372
+ $locations[ fw_get_stylesheet_customizations_directory('/extensions') ] = array(
373
+ 'path' => fw_get_stylesheet_customizations_directory('/extensions'),
374
+ 'uri' => fw_get_stylesheet_customizations_directory_uri('/extensions'),
375
+ 'customizations_locations' => $customizations_locations,
376
+ 'is' => array(
377
+ 'framework' => false,
378
+ 'custom' => false,
379
+ 'theme' => true,
380
+ ),
381
+ );
382
+ }
383
+
384
+ FW_Cache::set($cache_key, $locations);
385
+
386
+ return $locations;
387
+ }
388
+ }
389
+
390
+ private function load_all_extensions()
391
+ {
392
+ foreach ($this->get_locations() as $location) {
393
+ self::load_extensions(array(
394
+ 'path' => $location['path'],
395
+ 'uri' => $location['uri'],
396
+ 'customizations_locations' => $location['customizations_locations'],
397
  ));
398
  }
399
  }
452
  }
453
  }
454
  }
455
+ unset($sub_extensions);
456
  }
457
 
458
  /**
framework/core/components/extensions/manager/class--fw-extensions-manager.php CHANGED
@@ -347,7 +347,6 @@ final class _FW_Extensions_Manager
347
  * Scan all directories for extensions
348
  *
349
  * @param bool $reset_cache
350
- *
351
  * @return array
352
  */
353
  private function get_installed_extensions($reset_cache = false)
@@ -361,21 +360,16 @@ final class _FW_Extensions_Manager
361
  try {
362
  return FW_Cache::get($cache_key);
363
  } catch (FW_Cache_Not_Found_Exception $e) {
364
- {
365
- $search_paths = array(
366
- 'framework' => fw_get_framework_directory('/extensions'),
367
- 'parent' => fw_get_template_customizations_directory('/extensions'),
368
- );
369
-
370
- if (is_child_theme()) {
371
- $search_paths['child'] = fw_get_stylesheet_customizations_directory('/extensions');
372
- }
373
- }
374
-
375
  $extensions = array();
376
 
377
- foreach ($search_paths as $source => $path) {
378
- $this->read_extensions($source, $path, $extensions);
 
 
 
 
 
 
379
  }
380
 
381
  FW_Cache::set($cache_key, $extensions);
@@ -386,36 +380,35 @@ final class _FW_Extensions_Manager
386
 
387
  /**
388
  * used by $this->get_installed_extensions()
389
- * @param string $source
390
- * @param string $path
391
  * @param array $list
392
  * @param null|string $parent_extension_name
393
  */
394
- private function read_extensions($source, $path, &$list, $parent_extension_name = null)
395
  {
396
- $paths = glob($path .'/*', GLOB_ONLYDIR | GLOB_NOSORT);
397
 
398
  if (empty($paths)) {
399
  return;
400
  }
401
 
402
- foreach ($paths as $i => $extension_path) {
403
  $extension_name = basename($extension_path);
404
 
405
  if (isset($list[$extension_name])) {
406
- // extension already
407
  } elseif (file_exists($extension_path .'/manifest.php')) {
408
  $vars = fw_get_variables_from_file($extension_path .'/manifest.php', array(
409
  'manifest' => array(),
410
  ));
411
 
412
  $list[$extension_name] = array(
413
- 'source' => $source,
414
  'path' => $extension_path,
415
  'manifest' => $vars['manifest'],
416
  'children' => array(),
417
  'active' => (bool)fw()->extensions->get($extension_name),
418
  'parent' => $parent_extension_name,
 
419
  );
420
 
421
  if ($parent_extension_name) {
@@ -426,9 +419,11 @@ final class _FW_Extensions_Manager
426
  continue;
427
  }
428
 
 
 
 
429
  $this->read_extensions(
430
- $source,
431
- $extension_path .'/extensions',
432
  $list,
433
  $extension_name
434
  );
@@ -1696,7 +1691,7 @@ final class _FW_Extensions_Manager
1696
  'is_supported' =>
1697
  fw()->theme->manifest->get('supported_extensions/'. $extension_name, false) !== false
1698
  ||
1699
- $installed_extensions[$extension_name]['source'] !== 'framework'
1700
  ), false);
1701
 
1702
  unset($installed_extensions);
@@ -2806,6 +2801,7 @@ final class _FW_Extensions_Manager
2806
  }
2807
  }
2808
  }
 
2809
 
2810
  // remove all skipped extensions and sub-extension from used extensions
2811
  foreach (array_keys($skip_extensions) as $skip_extension_name) {
@@ -2866,7 +2862,7 @@ final class _FW_Extensions_Manager
2866
  $db_active_extensions = fw()->extensions->_get_db_active_extensions();
2867
 
2868
  foreach ($this->get_installed_extensions() as $extension_name => $extension) {
2869
- if ($extension['source'] !== 'framework') {
2870
  $db_active_extensions[ $extension_name ] = array();
2871
  }
2872
  }
347
  * Scan all directories for extensions
348
  *
349
  * @param bool $reset_cache
 
350
  * @return array
351
  */
352
  private function get_installed_extensions($reset_cache = false)
360
  try {
361
  return FW_Cache::get($cache_key);
362
  } catch (FW_Cache_Not_Found_Exception $e) {
 
 
 
 
 
 
 
 
 
 
 
363
  $extensions = array();
364
 
365
+ foreach (fw()->extensions->get_locations() as $location) {
366
+ // leave only used keys
367
+ $location = array(
368
+ 'path' => $location['path'],
369
+ 'is' => $location['is'],
370
+ );
371
+
372
+ $this->read_extensions($location, $extensions);
373
  }
374
 
375
  FW_Cache::set($cache_key, $extensions);
380
 
381
  /**
382
  * used by $this->get_installed_extensions()
383
+ * @param string $location
 
384
  * @param array $list
385
  * @param null|string $parent_extension_name
386
  */
387
+ private function read_extensions($location, &$list, $parent_extension_name = null)
388
  {
389
+ $paths = glob($location['path'] .'/*', GLOB_ONLYDIR | GLOB_NOSORT);
390
 
391
  if (empty($paths)) {
392
  return;
393
  }
394
 
395
+ foreach ($paths as $extension_path) {
396
  $extension_name = basename($extension_path);
397
 
398
  if (isset($list[$extension_name])) {
399
+ // extension already found
400
  } elseif (file_exists($extension_path .'/manifest.php')) {
401
  $vars = fw_get_variables_from_file($extension_path .'/manifest.php', array(
402
  'manifest' => array(),
403
  ));
404
 
405
  $list[$extension_name] = array(
 
406
  'path' => $extension_path,
407
  'manifest' => $vars['manifest'],
408
  'children' => array(),
409
  'active' => (bool)fw()->extensions->get($extension_name),
410
  'parent' => $parent_extension_name,
411
+ 'is' => $location['is'],
412
  );
413
 
414
  if ($parent_extension_name) {
419
  continue;
420
  }
421
 
422
+ $sub_extension_location = $location;
423
+ $sub_extension_location['path'] .= '/'. $extension_name .'/extensions';
424
+
425
  $this->read_extensions(
426
+ $sub_extension_location,
 
427
  $list,
428
  $extension_name
429
  );
1691
  'is_supported' =>
1692
  fw()->theme->manifest->get('supported_extensions/'. $extension_name, false) !== false
1693
  ||
1694
+ $installed_extensions[$extension_name]['is']['theme']
1695
  ), false);
1696
 
1697
  unset($installed_extensions);
2801
  }
2802
  }
2803
  }
2804
+ unset($inst_ext_data);
2805
 
2806
  // remove all skipped extensions and sub-extension from used extensions
2807
  foreach (array_keys($skip_extensions) as $skip_extension_name) {
2862
  $db_active_extensions = fw()->extensions->_get_db_active_extensions();
2863
 
2864
  foreach ($this->get_installed_extensions() as $extension_name => $extension) {
2865
+ if ($extension['is']['theme']) {
2866
  $db_active_extensions[ $extension_name ] = array();
2867
  }
2868
  }
framework/core/components/extensions/manager/views/extension.php CHANGED
@@ -85,7 +85,7 @@ if (isset($lists['available'][$name])) {
85
  if (
86
  isset($lists['supported'][$name]) // is listed in the supported extensions list in theme manifest
87
  ||
88
- ($installed_data && $installed_data['source'] !== 'framework') // is located in the theme
89
  ): ?>
90
  <p><em><strong><span class="dashicons dashicons-yes"></span> <?php _e('Compatible', 'fw') ?></strong> <?php _e('with your current theme', 'fw') ?></em></p>
91
  <?php endif; ?>
85
  if (
86
  isset($lists['supported'][$name]) // is listed in the supported extensions list in theme manifest
87
  ||
88
+ ($installed_data && $installed_data['is']['theme']) // is located in the theme
89
  ): ?>
90
  <p><em><strong><span class="dashicons dashicons-yes"></span> <?php _e('Compatible', 'fw') ?></strong> <?php _e('with your current theme', 'fw') ?></em></p>
91
  <?php endif; ?>
framework/core/components/extensions/manager/views/extensions-page.php CHANGED
@@ -25,6 +25,7 @@ foreach ($lists['active'] as $name => &$data) {
25
 
26
  $display_active_extensions[$name] = &$data;
27
  }
 
28
  ?>
29
  <?php if (empty($display_active_extensions)): ?>
30
  <div class="fw-extensions-no-active">
@@ -48,6 +49,7 @@ foreach ($lists['active'] as $name => &$data) {
48
 
49
  $displayed[$name] = true;
50
  }
 
51
  ?>
52
  </div>
53
  <?php endif; ?>
@@ -62,7 +64,7 @@ foreach ($lists['active'] as $name => &$data) {
62
  $theme_extensions = array();
63
 
64
  foreach ($lists['disabled'] as $name => &$data) {
65
- if ($data['source'] == 'framework') {
66
  continue;
67
  }
68
 
@@ -71,8 +73,9 @@ foreach ($lists['active'] as $name => &$data) {
71
  'description' => fw_akg('description', $data['manifest'], '')
72
  );
73
  }
 
74
 
75
- foreach (($theme_extensions + $lists['supported']) as $name => $data) {
76
  if (isset($displayed[$name])) {
77
  continue;
78
  } elseif (isset($lists['installed'][$name])) {
@@ -127,6 +130,7 @@ foreach ($lists['active'] as $name => &$data) {
127
 
128
  $displayed[$name] = $something_displayed = true;
129
  }
 
130
 
131
  if ($can_install) {
132
  foreach ( $lists['available'] as $name => &$data ) {
@@ -161,6 +165,7 @@ foreach ($lists['active'] as $name => &$data) {
161
 
162
  $something_displayed = true;
163
  }
 
164
  }
165
  ?>
166
  </div>
25
 
26
  $display_active_extensions[$name] = &$data;
27
  }
28
+ unset($data);
29
  ?>
30
  <?php if (empty($display_active_extensions)): ?>
31
  <div class="fw-extensions-no-active">
49
 
50
  $displayed[$name] = true;
51
  }
52
+ unset($data);
53
  ?>
54
  </div>
55
  <?php endif; ?>
64
  $theme_extensions = array();
65
 
66
  foreach ($lists['disabled'] as $name => &$data) {
67
+ if (!$data['is']['theme']) {
68
  continue;
69
  }
70
 
73
  'description' => fw_akg('description', $data['manifest'], '')
74
  );
75
  }
76
+ unset($data);
77
 
78
+ foreach ($theme_extensions + $lists['supported'] as $name => $data) {
79
  if (isset($displayed[$name])) {
80
  continue;
81
  } elseif (isset($lists['installed'][$name])) {
130
 
131
  $displayed[$name] = $something_displayed = true;
132
  }
133
+ unset($data);
134
 
135
  if ($can_install) {
136
  foreach ( $lists['available'] as $name => &$data ) {
165
 
166
  $something_displayed = true;
167
  }
168
+ unset($data);
169
  }
170
  ?>
171
  </div>
framework/core/extends/class-fw-extension.php CHANGED
@@ -274,6 +274,7 @@ abstract class FW_Extension
274
  foreach ($active_tree as $extension_name => &$sub_extensions) {
275
  $result[$extension_name] = fw()->extensions->get($extension_name);
276
  }
 
277
 
278
  return $result;
279
  }
274
  foreach ($active_tree as $extension_name => &$sub_extensions) {
275
  $result[$extension_name] = fw()->extensions->get($extension_name);
276
  }
277
+ unset($sub_extensions);
278
 
279
  return $result;
280
  }
framework/helpers/class-fw-form.php CHANGED
@@ -358,6 +358,63 @@ class FW_Form {
358
  unset( $data );
359
  }
360
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  echo '<form '. fw_attr_to_html( $render_data['attr'] ) .' >';
362
 
363
  echo fw_html_tag('input', array(
@@ -498,7 +555,7 @@ if ( is_admin() ) {
498
  * Display form errors in admin side
499
  * @internal
500
  */
501
- function _action_show_fw_form_errors_in_admin() {
502
  $form = FW_Form::get_submitted();
503
 
504
  if ( ! $form || $form->is_valid() ) {
@@ -509,39 +566,20 @@ if ( is_admin() ) {
509
  FW_Flash_Messages::add( 'fw-form-admin-' . $input_name, $error_message, 'error' );
510
  }
511
  }
512
- add_action( 'wp_loaded', '_action_show_fw_form_errors_in_admin', 111 );
513
  } else {
514
  /**
515
- * Detect if form errors was not displayed in frontend then display them with default design
516
- * Do nothing if the theme already displayed the errors
517
  * @internal
518
  */
519
- function _action_show_fw_form_errors_in_frontend() {
520
  $form = FW_Form::get_submitted();
521
 
522
  if ( ! $form || $form->is_valid() ) {
523
  return;
524
  }
525
 
526
- if ( $form->errors_accessed() ) {
527
- // already displayed
528
- return;
529
- }
530
-
531
- foreach ($form->get_errors() as $input_name => $error_message) {
532
- FW_Flash_Messages::add(
533
- 'fw-form-error-'. $input_name,
534
- $error_message,
535
- 'error'
536
- );
537
- }
538
  }
539
- add_action( 'wp_footer', '_action_show_fw_form_errors_in_frontend',
540
- /**
541
- * Use priority later than the default 10.
542
- * In docs (to customize the error messages) will be easier to explain
543
- * to use just add_action('wp_footer', ...) and not bother about priority
544
- */
545
- 11
546
- );
547
  }
358
  unset( $data );
359
  }
360
 
361
+ // display form errors in frontend
362
+ do {
363
+ if (is_admin()) {
364
+ // errors in admin side are displayed by a script at the end of this file
365
+ break;
366
+ }
367
+
368
+ $submitted_form = FW_Form::get_submitted();
369
+
370
+ if ( ! $submitted_form ) {
371
+ break;
372
+ }
373
+
374
+ if ( $submitted_form->get_id() !== $this->get_id() ) {
375
+ // the submitted form is not current form
376
+ break;
377
+ }
378
+
379
+ unset($submitted_form); // not needed anymore, below will be used only with $this (because it's the same form)
380
+
381
+ if ( $this->is_valid() ) {
382
+ break;
383
+ }
384
+
385
+ /**
386
+ * Use this action to customize errors display in your theme
387
+ */
388
+ do_action('fw_form_display_errors_frontend', $this);
389
+
390
+ if ( $this->errors_accessed() ) {
391
+ // already displayed, prevent/cancel default display
392
+ break;
393
+ }
394
+
395
+ $errors = $this->get_errors();
396
+
397
+ if (empty($errors)) {
398
+ break;
399
+ }
400
+
401
+ echo '<ul class="fw-form-errors">';
402
+
403
+ foreach ($errors as $input_name => $error_message) {
404
+ echo fw_html_tag(
405
+ 'li',
406
+ array(
407
+ 'data-input-name' => $input_name,
408
+ ),
409
+ $error_message
410
+ );
411
+ }
412
+
413
+ echo '</ul>';
414
+
415
+ unset($errors);
416
+ } while(false);
417
+
418
  echo '<form '. fw_attr_to_html( $render_data['attr'] ) .' >';
419
 
420
  echo fw_html_tag('input', array(
555
  * Display form errors in admin side
556
  * @internal
557
  */
558
+ function _action_fw_form_show_errors_in_admin() {
559
  $form = FW_Form::get_submitted();
560
 
561
  if ( ! $form || $form->is_valid() ) {
566
  FW_Flash_Messages::add( 'fw-form-admin-' . $input_name, $error_message, 'error' );
567
  }
568
  }
569
+ add_action( 'wp_loaded', '_action_fw_form_show_errors_in_admin', 111 );
570
  } else {
571
  /**
572
+ * to disable this use remove_action('wp_print_styles', '_action_fw_form_frontend_default_styles');
 
573
  * @internal
574
  */
575
+ function _action_fw_form_frontend_default_styles() {
576
  $form = FW_Form::get_submitted();
577
 
578
  if ( ! $form || $form->is_valid() ) {
579
  return;
580
  }
581
 
582
+ echo '<style type="text/css">.fw-form-errors { color: #bf0000; }</style>';
 
 
 
 
 
 
 
 
 
 
 
583
  }
584
+ add_action( 'wp_print_styles', '_action_fw_form_frontend_default_styles' );
 
 
 
 
 
 
 
585
  }
framework/helpers/general.php CHANGED
@@ -611,6 +611,7 @@ function fw_extract_only_options(array $options, &$_recursion_options = array())
611
  $recursion['level']--;
612
  }
613
  }
 
614
 
615
  if ($recursion['level'] == 0) {
616
  $result =& $recursion['result'];
@@ -715,6 +716,7 @@ function fw_collect_first_level_options(&$collected, &$options) {
715
  trigger_error('Invalid option: '. $option_id, E_USER_WARNING);
716
  }
717
  }
 
718
  }
719
 
720
  /**
611
  $recursion['level']--;
612
  }
613
  }
614
+ unset($option);
615
 
616
  if ($recursion['level'] == 0) {
617
  $result =& $recursion['result'];
716
  trigger_error('Invalid option: '. $option_id, E_USER_WARNING);
717
  }
718
  }
719
+ unset($option);
720
  }
721
 
722
  /**
framework/includes/option-types.php CHANGED
@@ -893,3 +893,4 @@ require $dir .'/option-types/popup/class-fw-option-type-popup.php';
893
  require $dir .'/option-types/slider/class-fw-option-type-slider.php';
894
  require $dir .'/option-types/range-slider/class-fw-option-type-range-slider.php';
895
  require $dir .'/option-types/rgba-color-picker/class-fw-option-type-rgba-color-picker.php';
 
893
  require $dir .'/option-types/slider/class-fw-option-type-slider.php';
894
  require $dir .'/option-types/range-slider/class-fw-option-type-range-slider.php';
895
  require $dir .'/option-types/rgba-color-picker/class-fw-option-type-rgba-color-picker.php';
896
+ require $dir .'/option-types/runnable/class-fw-option-type-runnable.php';
framework/includes/option-types/addable-box/view.php CHANGED
@@ -51,7 +51,7 @@ unset($attr['value']);
51
  );
52
  ?>
53
  </div>
54
- <?php endforeach; ?>
55
  </div>
56
  <br class="default-box-template fw-hidden" data-template="<?php
57
  /**
@@ -59,13 +59,6 @@ unset($attr['value']);
59
  * when this option will be used inside another option template
60
  */
61
 
62
- /**
63
- * This is a reference.
64
- * Unset before replacing with new value
65
- * to prevent changing value to what it refers
66
- */
67
- unset($values);
68
-
69
  $values = array();
70
 
71
  // must contain characters that will remain the same after htmlspecialchars()
51
  );
52
  ?>
53
  </div>
54
+ <?php endforeach; unset($values); ?>
55
  </div>
56
  <br class="default-box-template fw-hidden" data-template="<?php
57
  /**
59
  * when this option will be used inside another option template
60
  */
61
 
 
 
 
 
 
 
 
62
  $values = array();
63
 
64
  // must contain characters that will remain the same after htmlspecialchars()
framework/includes/option-types/icon/class-fw-option-type-icon.php CHANGED
@@ -63,6 +63,8 @@ class FW_Option_Type_Icon extends FW_Option_Type
63
  $this->enqueued_font_styles[ $style_hash ] = true;
64
  }
65
  }
 
 
66
  }
67
 
68
  /**
63
  $this->enqueued_font_styles[ $style_hash ] = true;
64
  }
65
  }
66
+
67
+ return true;
68
  }
69
 
70
  /**
framework/includes/option-types/multi-select/class-fw-option-type-multi-select.php CHANGED
@@ -137,9 +137,9 @@ class FW_Option_Type_Multi_Select extends FW_Option_Type
137
  if ( empty( $names ) ) {
138
  $items = $wpdb->get_results(
139
  $wpdb->prepare(
140
- "SELECT users.id val, users.display_name title " .
141
  "FROM $wpdb->users as users " .
142
- "WHERE users.display_name LIKE %s " .
143
  "LIMIT 100",
144
  '%'. $wpdb->esc_like($title) .'%'
145
  )
@@ -155,9 +155,9 @@ class FW_Option_Type_Multi_Select extends FW_Option_Type
155
  array($wpdb, 'prepare'),
156
  array_merge(
157
  array(
158
- "SELECT users.id val, users.display_name title " .
159
  "FROM $wpdb->users as users, $wpdb->usermeta as usermeta " .
160
- "WHERE users.display_name LIKE %s AND usermeta.meta_key = 'wp_capabilities' " .
161
  "AND ( ".
162
  implode(' OR ', array_fill(1, count($like_user_meta), 'usermeta.meta_value LIKE %s')) .
163
  " ) " .
@@ -334,7 +334,7 @@ class FW_Option_Type_Multi_Select extends FW_Option_Type
334
  $ids = implode( ', ', array_unique( $ids ) );
335
 
336
  $query = $wpdb->get_results(
337
- "SELECT users.id, users.display_name title " .
338
  "FROM $wpdb->users as users " .
339
  "WHERE users.ID IN ($ids)"
340
  );
137
  if ( empty( $names ) ) {
138
  $items = $wpdb->get_results(
139
  $wpdb->prepare(
140
+ "SELECT users.id val, users.user_nicename title " .
141
  "FROM $wpdb->users as users " .
142
+ "WHERE users.user_nicename LIKE %s " .
143
  "LIMIT 100",
144
  '%'. $wpdb->esc_like($title) .'%'
145
  )
155
  array($wpdb, 'prepare'),
156
  array_merge(
157
  array(
158
+ "SELECT users.id val, users.user_nicename title " .
159
  "FROM $wpdb->users as users, $wpdb->usermeta as usermeta " .
160
+ "WHERE users.user_nicename LIKE %s AND usermeta.meta_key = 'wp_capabilities' " .
161
  "AND ( ".
162
  implode(' OR ', array_fill(1, count($like_user_meta), 'usermeta.meta_value LIKE %s')) .
163
  " ) " .
334
  $ids = implode( ', ', array_unique( $ids ) );
335
 
336
  $query = $wpdb->get_results(
337
+ "SELECT users.id, users.user_nicename title " .
338
  "FROM $wpdb->users as users " .
339
  "WHERE users.ID IN ($ids)"
340
  );
framework/includes/option-types/runnable/class-fw-option-type-runnable.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'FW' ) ) {
2
+ die( 'Forbidden' );
3
+ }
4
+ /**
5
+ * This option type let you run a callback by click on Run button.
6
+ * example of $option array
7
+ * array(
8
+ * 'type' => 'runnable',
9
+ * 'value' => 'This script have no runs',
10
+ * 'label' => __('Convert data', 'fw'),
11
+ * 'desc' => __('There are posts, pages, categories or tags without language set. Do you want to set them all to default language.', 'fw'),
12
+ * 'help' => __('Help tip', 'fw'),
13
+ * 'content'=>__('Run this script'),
14
+ * 'callback'=> array('translation' , 'convert_data_to_default_language')
15
+ * )
16
+ */
17
+ /**
18
+ * Class FW_Option_Type_Runnable
19
+ */
20
+ class FW_Option_Type_Runnable extends FW_Option_Type {
21
+
22
+ /**
23
+ * Option's unique type, used in option array in 'type' key
24
+ * @return string
25
+ */
26
+ public function get_type() {
27
+ return 'runnable';
28
+
29
+
30
+ }
31
+
32
+ /**
33
+ * Run callback.
34
+ */
35
+ public function run_callback() {
36
+
37
+ $callback = explode( '.', FW_Request::POST( 'callback' ) );
38
+ $length = count( $callback );
39
+
40
+ if ( $length === 1 && is_callable( $callback[0] ) ) {
41
+ $handler = $callback[0];
42
+ } elseif ( $length === 2 && is_callable( $callback ) ) {
43
+ $handler = $callback;
44
+ } elseif ( $length === 2 && is_callable( $fw_ext_callback = array( fw_ext( $callback[0] ), $callback[1] ) ) ) {
45
+ $handler = $fw_ext_callback;
46
+ } else {
47
+ wp_send_json_error( 'Your callback is not callable' );
48
+ }
49
+
50
+ call_user_func( $handler );
51
+ }
52
+
53
+ /**
54
+ * Generate option's html from option array.
55
+ *
56
+ * @param string $id
57
+ * @param array $option
58
+ * @param array $data
59
+ *
60
+ * @return string HTML
61
+ * @internal
62
+ */
63
+ protected function _render( $id, $option, $data ) {
64
+
65
+ $callback = implode( '.', (array) $option['callback'] );
66
+ $option['attr']['value'] = (string) $data['value'];
67
+
68
+ return '<div class="runnable-wrapper">
69
+ <button data-callback="' . $callback . '" type="button" class="runnable-button button-primary">' . $option['content'] . '</button>
70
+ <div class="runnable-last-run">' . $option['attr']['value'] . '</div>
71
+ <input type="hidden" ' . fw_attr_to_html( $option['attr'] ) . '/>
72
+ </div>';
73
+ }
74
+
75
+ /**
76
+ * Enqueue static.
77
+ * @param string $id
78
+ * @param array $option
79
+ * @param array $data
80
+ */
81
+ protected function _enqueue_static( $id, $option, $data ) {
82
+ $js_path = fw_get_framework_directory_uri( '/includes/option-types/runnable/static/js/runnable.js' );
83
+ $css_path = fw_get_framework_directory_uri( '/includes/option-types/runnable/static/css/runnable.css' );
84
+
85
+ wp_enqueue_script(
86
+ 'fw-option-' . $this->get_type() . '-js',
87
+ $js_path,
88
+ array( 'jquery', 'fw-moment' ),
89
+ fw()->manifest->get_version()
90
+ );
91
+
92
+ wp_enqueue_style(
93
+ 'fw-option-' . $this->get_type() . '-css',
94
+ $css_path,
95
+ array(),
96
+ fw()->manifest->get_version()
97
+ );
98
+ }
99
+
100
+ /**
101
+ * Extract correct value for $option['value'] from input array
102
+ * If input value is empty, will be returned $option['value']
103
+ *
104
+ * @param array $option
105
+ * @param array|string|null $input_value
106
+ *
107
+ * @return string|array|int|bool Correct value
108
+ * @internal
109
+ */
110
+ protected function _get_value_from_input( $option, $input_value ) {
111
+ return (string) ( is_null( $input_value ) ? $option['value'] : $input_value );
112
+ }
113
+
114
+ /**
115
+ * Default option array
116
+ *
117
+ * This makes possible an option array to have required only one parameter: array('type' => '...')
118
+ * Other parameters are merged with array returned from this method
119
+ *
120
+ * @return array
121
+ *
122
+ * array(
123
+ * 'value' => '',
124
+ * ...
125
+ * )
126
+ * @internal
127
+ */
128
+ protected function _get_defaults() {
129
+ return array(
130
+ 'value' => '',
131
+ 'content' => 'Run'
132
+ );
133
+ }
134
+
135
+ }
136
+
137
+ FW_Option_Type::register( 'FW_Option_Type_Runnable' );
138
+
139
+ add_action( 'wp_ajax_fw_runnable', array( 'FW_Option_Type_Runnable', 'run_callback' ) );
framework/includes/option-types/runnable/static/css/runnable.css ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ .fw-backend-option-type-runnable .runnable-wrapper .runnable-button {
2
+ float: left;
3
+ }
4
+
5
+ .fw-backend-option-type-runnable .runnable-wrapper .runnable-last-run {
6
+ float: left;
7
+ padding-left: 20px;
8
+ line-height: 28px
9
+ }
framework/includes/option-types/runnable/static/js/runnable.js ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($, fwe) {
2
+ var init = function () {
3
+ var $hidden = $(this),
4
+ $button = $hidden.parent().find('.runnable-button'),
5
+ $textDiv = $hidden.parent().find('.runnable-last-run');
6
+
7
+ var showDate = function ($timestamp) {
8
+ $textDiv.text('Last run was ' + moment($timestamp, 'X').fromNow());
9
+ }
10
+
11
+ if (moment($hidden.val(), 'X', true).isValid()) {
12
+ showDate($hidden.val());
13
+ }
14
+
15
+ $button.on('click', function (e) {
16
+ e.preventDefault();
17
+
18
+ $.ajax({
19
+ type: "post",
20
+ dataType: "json",
21
+ url: ajaxurl,
22
+ data: {action: 'fw_runnable', callback: $(this).data('callback')}
23
+ }).done(function (data) {
24
+ if (data.success) {
25
+ var $timestamp = moment().format('X');
26
+ $hidden.val($timestamp);
27
+ showDate($timestamp);
28
+ }
29
+
30
+ fwe.trigger('fw:option-type:runnable:change', {
31
+ $element: $hidden,
32
+ response: data
33
+ });
34
+ });
35
+ });
36
+ };
37
+
38
+ fwe.on('fw:options:init', function (data) {
39
+ data.$elements
40
+ .find('.fw-option-type-runnable:not(.fw-option-initialized)').each(init)
41
+ .addClass('fw-option-initialized');
42
+ });
43
+ })(jQuery, fwEvents);
framework/includes/option-types/typography/view.php CHANGED
@@ -58,11 +58,11 @@
58
  '700italic' => 'Bold/Italic',
59
  )
60
  as $key => $style): ?>
61
- <option value="<?php echo esc_attr($key) ?>" <?php if ($data['value']['style'] == $key): ?>selected="selected"<?php endif; ?>><?php echo fw_htmlspecialchars($style) ?></option>
62
  <?php endforeach; ?>
63
  <?php else: ?>
64
  <?php foreach ($fonts['google'][$data['value']['family']]['variants'] as $variant): ?>
65
- <option value="<?php echo esc_attr($variant) ?>" <?php if ($data['value']['style'] == $variant): ?>selected="selected"<?php endif; ?>><?php echo fw_htmlspecialchars(ucfirst($variant)) ?></option>
66
  <?php endforeach; ?>
67
  <?php endif; ?>
68
  </select>
58
  '700italic' => 'Bold/Italic',
59
  )
60
  as $key => $style): ?>
61
+ <option value="<?php echo esc_attr($key) ?>" <?php if ($data['value']['style'] === $key): ?>selected="selected"<?php endif; ?>><?php echo fw_htmlspecialchars($style) ?></option>
62
  <?php endforeach; ?>
63
  <?php else: ?>
64
  <?php foreach ($fonts['google'][$data['value']['family']]['variants'] as $variant): ?>
65
+ <option value="<?php echo esc_attr($variant) ?>" <?php if ($data['value']['style'] === $variant): ?>selected="selected"<?php endif; ?>><?php echo fw_htmlspecialchars(ucfirst($variant)) ?></option>
66
  <?php endforeach; ?>
67
  <?php endif; ?>
68
  </select>
framework/manifest.php CHANGED
@@ -4,4 +4,4 @@ $manifest = array();
4
 
5
  $manifest['name'] = __('Unyson', 'fw');
6
 
7
- $manifest['version'] = '2.2.2';
4
 
5
  $manifest['name'] = __('Unyson', 'fw');
6
 
7
+ $manifest['version'] = '2.2.3';
framework/static/css/fw.css CHANGED
@@ -2985,7 +2985,7 @@ body.rtl .fw-options-modal .media-frame-content > form .fw-options-tabs-contents
2985
  /* SoleModal */
2986
 
2987
  .fw-sole-modal > .media-modal {
2988
- z-index: 100001;
2989
  margin: auto;
2990
  }
2991
 
2985
  /* SoleModal */
2986
 
2987
  .fw-sole-modal > .media-modal {
2988
+ z-index: 500000;
2989
  margin: auto;
2990
  }
2991
 
framework/views/backend-tabs.php CHANGED
@@ -10,7 +10,7 @@
10
  <ul>
11
  <?php foreach ($tabs as $tab_id => &$tab): ?>
12
  <li><a href="#fw-options-tab-<?php echo esc_attr($tab_id) ?>" class="nav-tab fw-wp-link" ><?php echo htmlspecialchars($tab['title'], ENT_COMPAT, 'UTF-8') ?></a></li>
13
- <?php endforeach; ?>
14
  </ul>
15
  <div class="fw-clear"></div>
16
  </div>
@@ -33,6 +33,7 @@
33
  ?><div <?php echo fw_attr_to_html($attr) ?>><?php echo fw()->backend->render_options($tab['options'], $values, $options_data) ?></div><?php
34
  unset($tabs[$tab_id]); // free memory after printed and not needed anymore
35
  endforeach;
 
36
  ?>
37
  </div>
38
  </div>
10
  <ul>
11
  <?php foreach ($tabs as $tab_id => &$tab): ?>
12
  <li><a href="#fw-options-tab-<?php echo esc_attr($tab_id) ?>" class="nav-tab fw-wp-link" ><?php echo htmlspecialchars($tab['title'], ENT_COMPAT, 'UTF-8') ?></a></li>
13
+ <?php endforeach; unset($tab); ?>
14
  </ul>
15
  <div class="fw-clear"></div>
16
  </div>
33
  ?><div <?php echo fw_attr_to_html($attr) ?>><?php echo fw()->backend->render_options($tab['options'], $values, $options_data) ?></div><?php
34
  unset($tabs[$tab_id]); // free memory after printed and not needed anymore
35
  endforeach;
36
+ unset($tab);
37
  ?>
38
  </div>
39
  </div>
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: unyson, themefusecom
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.1
6
- Stable tag: 2.2.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -86,6 +86,10 @@ Yes; Unyson will work with any theme.
86
 
87
  == Changelog ==
88
 
 
 
 
 
89
  = 2.2.2 =
90
  * Added experimental `$option['option_handler']` [636ed56](https://github.com/ThemeFuse/Unyson/commit/636ed56fe499a4e855b5f49198747460833539a3)
91
  * `<input required ... />` works in `fw.OptionsModal` [#274](https://github.com/ThemeFuse/Unyson/issues/274)
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.1
6
+ Stable tag: 2.2.3
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
86
 
87
  == Changelog ==
88
 
89
+ = 2.2.3 =
90
+ * Fixed [#397](https://github.com/ThemeFuse/Unyson/issues/397), [#394](https://github.com/ThemeFuse/Unyson/issues/394), [#389](https://github.com/ThemeFuse/Unyson/issues/389), [384](https://github.com/ThemeFuse/Unyson/issues/384), [#355](https://github.com/ThemeFuse/Unyson/issues/355)
91
+ * Added option type `runnable` [code](https://github.com/ThemeFuse/Unyson/blob/master/framework/includes/option-types/runnable/class-fw-option-type-runnable.php)
92
+
93
  = 2.2.2 =
94
  * Added experimental `$option['option_handler']` [636ed56](https://github.com/ThemeFuse/Unyson/commit/636ed56fe499a4e855b5f49198747460833539a3)
95
  * `<input required ... />` works in `fw.OptionsModal` [#274](https://github.com/ThemeFuse/Unyson/issues/274)
unyson.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Unyson
4
  * Plugin URI: http://unyson.themefuse.com/
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.2.2
7
  * Author: ThemeFuse
8
  * Author URI: http://themefuse.com
9
  * License: GPL2+
3
  * Plugin Name: Unyson
4
  * Plugin URI: http://unyson.themefuse.com/
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.2.3
7
  * Author: ThemeFuse
8
  * Author URI: http://themefuse.com
9
  * License: GPL2+