Unyson - Version 2.1.2

Version Description

  • Minor fixes and improvements in the extensions installation process
Download this release

Release Info

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

Code changes from version 2.1.1 to 2.1.2

CONTRIBUTING.md ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # How to contribute
2
+
3
+ ## Getting Started
4
+
5
+ * Make sure you have a [GitHub account](https://github.com/signup/free)
6
+ * Submit a ticket for your issue, assuming one does not already exist.
7
+ * Clearly describe the issue including steps to reproduce when it is a bug.
8
+ * Make sure you fill in the earliest version that you know has the issue.
9
+
10
+ ## Making Changes
11
+
12
+ * Fork the repository on GitHub.
13
+ * Make the changes to your forked repository.
14
+ * **Ensure you stick to the [WordPress Coding Standards](http://make.wordpress.org/core/handbook/coding-standards/php/).**
15
+ * Ensure you use LF line endings - no crazy windows line endings. :)
16
+ * When committing, reference your issue (#1234) and include a note about the fix.
17
+ * Push the changes to your fork and submit a pull request on the master branch of the Unyson repository. Existing maintenance branches will be maintained of by Unyson developers.
18
+
19
+ At this point you're waiting on us to merge your pull request. We'll review all pull requests, and make suggestions and changes if necessary.
20
+
21
+ # Additional Resources
22
+
23
+ * [General GitHub documentation](http://help.github.com/)
24
+ * [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
25
+ * [Unyson Docs](http://unyson-docs.themefuse.com/)
framework/core/components/extensions/manager/class--fw-extensions-manager.php CHANGED
@@ -152,7 +152,7 @@ final class _FW_Extensions_Manager
152
  wp_send_json_error();
153
  }
154
 
155
- if (FW_WP_Filesystem::has_direct_access()) {
156
  wp_send_json_success();
157
  } else {
158
  wp_send_json_error();
@@ -205,6 +205,7 @@ final class _FW_Extensions_Manager
205
  return;
206
  }
207
 
 
208
  $tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
209
  fw_fix_path(WP_CONTENT_DIR) .'/tmp/fw-plugin-update-extensions-backup'
210
  );
@@ -253,8 +254,9 @@ final class _FW_Extensions_Manager
253
  return;
254
  }
255
 
 
256
  $tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
257
- fw_fix_path( WP_CONTENT_DIR ) . '/tmp/fw-plugin-update-extensions-backup'
258
  );
259
  $extensions_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
260
  fw_get_framework_directory( '/extensions' )
@@ -328,8 +330,8 @@ final class _FW_Extensions_Manager
328
 
329
  $extensions = array();
330
 
331
- foreach ($search_paths as $path) {
332
- $this->read_extensions($path, $extensions);
333
  }
334
 
335
  FW_Cache::set($cache_key, $extensions);
@@ -340,11 +342,12 @@ final class _FW_Extensions_Manager
340
 
341
  /**
342
  * used by $this->get_installed_extensions()
 
343
  * @param string $path
344
  * @param array $list
345
  * @param null|string $parent_extension_name
346
  */
347
- private function read_extensions($path, &$list, $parent_extension_name = null)
348
  {
349
  $paths = glob($path .'/*', GLOB_ONLYDIR | GLOB_NOSORT);
350
 
@@ -363,6 +366,7 @@ final class _FW_Extensions_Manager
363
  ));
364
 
365
  $list[$extension_name] = array(
 
366
  'path' => $extension_path,
367
  'manifest' => $vars['manifest'],
368
  'children' => array(),
@@ -379,6 +383,7 @@ final class _FW_Extensions_Manager
379
  }
380
 
381
  $this->read_extensions(
 
382
  $extension_path .'/extensions',
383
  $list,
384
  $extension_name
@@ -386,11 +391,9 @@ final class _FW_Extensions_Manager
386
  }
387
  }
388
 
389
- private function get_tmp_dir()
390
  {
391
- return FW_WP_Filesystem::real_path_to_filesystem_path(
392
- fw_fix_path(WP_CONTENT_DIR) .'/tmp/fw-extension-download'
393
- );
394
  }
395
 
396
  /**
@@ -733,10 +736,9 @@ final class _FW_Extensions_Manager
733
  foreach ($parent_extensions as $parent_extension_name) {
734
  $current_extension_path .= '/extensions/'. $parent_extension_name;
735
 
736
- $activate_extensions[$parent_extension_name] = array();
737
-
738
  if (isset($installed_extensions[$parent_extension_name])) {
739
  // skip already installed extensions
 
740
  continue;
741
  }
742
 
@@ -778,6 +780,8 @@ final class _FW_Extensions_Manager
778
  )
779
  );
780
 
 
 
781
  /**
782
  * Read again all extensions
783
  * The downloaded extension may contain more sub extensions
@@ -880,10 +884,12 @@ final class _FW_Extensions_Manager
880
  /** @var WP_Filesystem_Base $wp_filesystem */
881
  global $wp_filesystem;
882
 
883
- if ($wp_filesystem->exists($this->get_tmp_dir())) {
884
- if ( ! $wp_filesystem->rmdir( $this->get_tmp_dir(), true ) ) {
 
 
885
  $skin->error(
886
- sprintf( __( 'Cannot remove temporary directory: %s', 'fw' ), $this->get_tmp_dir() )
887
  );
888
  break;
889
  }
@@ -900,6 +906,7 @@ final class _FW_Extensions_Manager
900
  fw_render_view(dirname(__FILE__) .'/views/install-form.php', array(
901
  'extension_titles' => $install_data['all'],
902
  'list_page_link' => $this->get_link(),
 
903
  ), false);
904
 
905
  echo '</form>';
@@ -1587,7 +1594,7 @@ final class _FW_Extensions_Manager
1587
 
1588
  // create temporary directory
1589
  {
1590
- $wp_fs_tmp_dir = $this->get_tmp_dir();
1591
 
1592
  if ($wp_filesystem->exists($wp_fs_tmp_dir)) {
1593
  // just in case it already exists, clear everything, it may contain old files
152
  wp_send_json_error();
153
  }
154
 
155
+ if (FW_WP_Filesystem::has_direct_access(fw_get_framework_directory('/extensions'))) {
156
  wp_send_json_success();
157
  } else {
158
  wp_send_json_error();
205
  return;
206
  }
207
 
208
+ // a directory outside the plugin
209
  $tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
210
  fw_fix_path(WP_CONTENT_DIR) .'/tmp/fw-plugin-update-extensions-backup'
211
  );
254
  return;
255
  }
256
 
257
+ // a directory outside the plugin
258
  $tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
259
+ fw_fix_path( WP_CONTENT_DIR ) .'/tmp/fw-plugin-update-extensions-backup'
260
  );
261
  $extensions_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
262
  fw_get_framework_directory( '/extensions' )
330
 
331
  $extensions = array();
332
 
333
+ foreach ($search_paths as $source => $path) {
334
+ $this->read_extensions($source, $path, $extensions);
335
  }
336
 
337
  FW_Cache::set($cache_key, $extensions);
342
 
343
  /**
344
  * used by $this->get_installed_extensions()
345
+ * @param string $source
346
  * @param string $path
347
  * @param array $list
348
  * @param null|string $parent_extension_name
349
  */
350
+ private function read_extensions($source, $path, &$list, $parent_extension_name = null)
351
  {
352
  $paths = glob($path .'/*', GLOB_ONLYDIR | GLOB_NOSORT);
353
 
366
  ));
367
 
368
  $list[$extension_name] = array(
369
+ 'source' => $source,
370
  'path' => $extension_path,
371
  'manifest' => $vars['manifest'],
372
  'children' => array(),
383
  }
384
 
385
  $this->read_extensions(
386
+ $source,
387
  $extension_path .'/extensions',
388
  $list,
389
  $extension_name
391
  }
392
  }
393
 
394
+ private function get_tmp_dir($append = '')
395
  {
396
+ return apply_filters('fw_tmp_dir', fw_fix_path(WP_CONTENT_DIR) .'/tmp') . $append;
 
 
397
  }
398
 
399
  /**
736
  foreach ($parent_extensions as $parent_extension_name) {
737
  $current_extension_path .= '/extensions/'. $parent_extension_name;
738
 
 
 
739
  if (isset($installed_extensions[$parent_extension_name])) {
740
  // skip already installed extensions
741
+ $activate_extensions[$parent_extension_name] = array();
742
  continue;
743
  }
744
 
780
  )
781
  );
782
 
783
+ $activate_extensions[$parent_extension_name] = array();
784
+
785
  /**
786
  * Read again all extensions
787
  * The downloaded extension may contain more sub extensions
884
  /** @var WP_Filesystem_Base $wp_filesystem */
885
  global $wp_filesystem;
886
 
887
+ $wp_fs_tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path($this->get_tmp_dir());
888
+
889
+ if ($wp_filesystem->exists($wp_fs_tmp_dir)) {
890
+ if ( ! $wp_filesystem->rmdir( $wp_fs_tmp_dir, true ) ) {
891
  $skin->error(
892
+ sprintf( __( 'Cannot remove temporary directory: %s', 'fw' ), $wp_fs_tmp_dir )
893
  );
894
  break;
895
  }
906
  fw_render_view(dirname(__FILE__) .'/views/install-form.php', array(
907
  'extension_titles' => $install_data['all'],
908
  'list_page_link' => $this->get_link(),
909
+ 'supported' => $supported
910
  ), false);
911
 
912
  echo '</form>';
1594
 
1595
  // create temporary directory
1596
  {
1597
+ $wp_fs_tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path($this->get_tmp_dir());
1598
 
1599
  if ($wp_filesystem->exists($wp_fs_tmp_dir)) {
1600
  // just in case it already exists, clear everything, it may contain old files
framework/core/components/extensions/manager/static/extensions-page.js CHANGED
@@ -93,7 +93,7 @@ jQuery(function($){
93
  window.location.reload();
94
  } else {
95
  if (true) {
96
- var $lastMessage = $content.find('p:last-child');
97
 
98
  if ($lastMessage.find('a').length) {
99
  // this is not message, these are link printed by WP_Upgrader_Skin::after()
93
  window.location.reload();
94
  } else {
95
  if (true) {
96
+ var $lastMessage = $content.find('> p').last();
97
 
98
  if ($lastMessage.find('a').length) {
99
  // this is not message, these are link printed by WP_Upgrader_Skin::after()
framework/core/components/extensions/manager/views/extension.php CHANGED
@@ -77,7 +77,16 @@ if (isset($lists['available'][$name])) {
77
  unset( $_links );
78
  }
79
  ?>
80
- <?php if ( isset($lists['supported'][$name]) && (($installed_data && !$is_active) || $available_data) ): ?>
 
 
 
 
 
 
 
 
 
81
  <p><em><strong><span class="dashicons dashicons-yes"></span> <?php _e('Compatible', 'fw') ?></strong> <?php _e('with your current theme', 'fw') ?></em></p>
82
  <?php endif; ?>
83
  </td>
@@ -93,6 +102,14 @@ if (isset($lists['available'][$name])) {
93
  <?php wp_nonce_field($nonces['activate']['action'], $nonces['activate']['name']); ?>
94
  <input class="button" type="submit" value="<?php esc_attr_e('Activate', 'fw'); ?>"/>
95
  </form>
 
 
 
 
 
 
 
 
96
  <form action="<?php echo esc_attr($link) ?>&sub-page=delete&extension=<?php echo esc_attr($name) ?>"
97
  method="post"
98
  class="fw-extension-ajax-form"
@@ -102,6 +119,7 @@ if (isset($lists['available'][$name])) {
102
  <a href="#" onclick="jQuery(this).closest('form').submit(); return false;" data-remove-extension="<?php echo esc_attr($name) ?>" ><?php _e('Remove', 'fw'); ?></a>
103
  </p>
104
  </form>
 
105
  </div>
106
  <?php elseif ($available_data): ?>
107
  <form action="<?php echo esc_attr($link) ?>&sub-page=install&extension=<?php echo esc_attr($name) ?>" method="post" class="fw-extension-ajax-form">
77
  unset( $_links );
78
  }
79
  ?>
80
+ <?php
81
+ if (
82
+ !$is_active // do not show the "Compatible" text is extension is already active
83
+ &&
84
+ (
85
+ isset($lists['supported'][$name]) // is listed in the supported extensions list in theme manifest
86
+ ||
87
+ ($installed_data && $installed_data['source'] !== 'framework') // is located in the theme
88
+ )
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; ?>
92
  </td>
102
  <?php wp_nonce_field($nonces['activate']['action'], $nonces['activate']['name']); ?>
103
  <input class="button" type="submit" value="<?php esc_attr_e('Activate', 'fw'); ?>"/>
104
  </form>
105
+ <?php
106
+ /**
107
+ * Do not show the "Delete extension" button if the extension is not in the available list.
108
+ * If you delete such extension you will not be able to install it back.
109
+ * Most often these will be extensions located in the theme.
110
+ */
111
+ if ($available_data):
112
+ ?>
113
  <form action="<?php echo esc_attr($link) ?>&sub-page=delete&extension=<?php echo esc_attr($name) ?>"
114
  method="post"
115
  class="fw-extension-ajax-form"
119
  <a href="#" onclick="jQuery(this).closest('form').submit(); return false;" data-remove-extension="<?php echo esc_attr($name) ?>" ><?php _e('Remove', 'fw'); ?></a>
120
  </p>
121
  </form>
122
+ <?php endif; ?>
123
  </div>
124
  <?php elseif ($available_data): ?>
125
  <form action="<?php echo esc_attr($link) ?>&sub-page=install&extension=<?php echo esc_attr($name) ?>" method="post" class="fw-extension-ajax-form">
framework/core/components/extensions/manager/views/extensions-page.php CHANGED
@@ -56,31 +56,48 @@ foreach ($lists['active'] as $name => &$data) {
56
  <div class="fw-row fw-extensions-list">
57
  <?php $something_displayed = false; ?>
58
  <?php
59
- foreach ($lists['supported'] as $name => &$data) {
60
- if (isset($displayed[$name])) {
61
- continue;
62
- } elseif (isset($lists['installed'][$name])) {
63
- if (true !== fw_akg('display', $lists['installed'][$name]['manifest'], $display_default_value)) {
64
  continue;
65
  }
66
- } elseif (!isset($lists['available'][$name])) {
67
- /*trigger_error(
68
- sprintf(__('Supported extension "%s" is not available.', 'fw'), $name)
69
- );*/
70
- continue;
71
  }
72
 
73
- fw_render_view($extension_view_path, array(
74
- 'name' => $name,
75
- 'title' => $data['name'],
76
- 'description' => $data['description'],
77
- 'link' => $link,
78
- 'lists' => &$lists,
79
- 'nonces' => $nonces,
80
- 'default_thumbnail' => $default_thumbnail,
81
- ), false);
 
 
 
 
82
 
83
- $displayed[$name] = $something_displayed = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  }
85
 
86
  foreach ($lists['disabled'] as $name => &$data) {
56
  <div class="fw-row fw-extensions-list">
57
  <?php $something_displayed = false; ?>
58
  <?php
59
+ {
60
+ $theme_extensions = array();
61
+
62
+ foreach ($lists['disabled'] as $name => &$data) {
63
+ if ($data['source'] == 'framework') {
64
  continue;
65
  }
66
+
67
+ $theme_extensions[$name] = array(
68
+ 'name' => fw_akg('name', $data['manifest'], fw_id_to_title($name)),
69
+ 'description' => fw_akg('description', $data['manifest'], '')
70
+ );
71
  }
72
 
73
+ foreach (($theme_extensions + $lists['supported']) as $name => $data) {
74
+ if (isset($displayed[$name])) {
75
+ continue;
76
+ } elseif (isset($lists['installed'][$name])) {
77
+ if (true !== fw_akg('display', $lists['installed'][$name]['manifest'], $display_default_value)) {
78
+ continue;
79
+ }
80
+ } elseif (!isset($lists['available'][$name])) {
81
+ /*trigger_error(
82
+ sprintf(__('Supported extension "%s" is not available.', 'fw'), $name)
83
+ );*/
84
+ continue;
85
+ }
86
 
87
+ fw_render_view($extension_view_path, array(
88
+ 'name' => $name,
89
+ 'title' => $data['name'],
90
+ 'description' => $data['description'],
91
+ 'link' => $link,
92
+ 'lists' => &$lists,
93
+ 'nonces' => $nonces,
94
+ 'default_thumbnail' => $default_thumbnail,
95
+ ), false);
96
+
97
+ $displayed[$name] = $something_displayed = true;
98
+ }
99
+
100
+ unset($theme_extensions);
101
  }
102
 
103
  foreach ($lists['disabled'] as $name => &$data) {
framework/core/components/extensions/manager/views/install-form.php CHANGED
@@ -2,17 +2,27 @@
2
  /**
3
  * @var array $extension_titles
4
  * @var array $list_page_link
 
5
  */
6
 
7
  $count = count($extension_titles);
8
  ?>
9
 
 
 
 
 
 
 
 
 
10
  <p><?php echo _n(
11
  'You are about to install the following extension:',
12
  'You are about to install the following extensions:',
13
  $count,
14
  'fw'
15
  ) ?></p>
 
16
 
17
  <ul class="ul-disc">
18
  <?php foreach ($extension_titles as $extension_title): ?>
2
  /**
3
  * @var array $extension_titles
4
  * @var array $list_page_link
5
+ * @var bool $supported
6
  */
7
 
8
  $count = count($extension_titles);
9
  ?>
10
 
11
+ <?php if ($supported): ?>
12
+ <p><?php echo _n(
13
+ 'We\'ve detected that your current theme is compatible with the following extension and it is recommended that you install it to fully benefit from your theme.',
14
+ 'We\'ve detected that your current theme is compatible with the following extensions and it is recommended that you install them to fully benefit from your theme.',
15
+ $count,
16
+ 'fw'
17
+ ) ?></p>
18
+ <?php else: ?>
19
  <p><?php echo _n(
20
  'You are about to install the following extension:',
21
  'You are about to install the following extensions:',
22
  $count,
23
  'fw'
24
  ) ?></p>
25
+ <?php endif; ?>
26
 
27
  <ul class="ul-disc">
28
  <?php foreach ($extension_titles as $extension_title): ?>
framework/extensions/update/class-fw-extension-update.php CHANGED
@@ -62,7 +62,7 @@ class FW_Extension_Update extends FW_Extension
62
  private function get_wp_fs_tmp_dir()
63
  {
64
  return FW_WP_Filesystem::real_path_to_filesystem_path(
65
- fw_fix_path(WP_CONTENT_DIR) .'/tmp/fw-ext-update'
66
  );
67
  }
68
 
62
  private function get_wp_fs_tmp_dir()
63
  {
64
  return FW_WP_Filesystem::real_path_to_filesystem_path(
65
+ apply_filters('fw_tmp_dir', fw_fix_path(WP_CONTENT_DIR) .'/tmp') .'/fw-ext-update'
66
  );
67
  }
68
 
framework/helpers/class-fw-form.php CHANGED
@@ -1,10 +1,11 @@
1
- <?php if (!defined('FW')) die('Forbidden');
 
 
2
 
3
  /**
4
  * Dynamic forms
5
  */
6
- class FW_Form
7
- {
8
  /**
9
  * Store all form ids created with this class
10
  * @var FW_Form[] {'form_id' => instance}
@@ -68,35 +69,34 @@ class FW_Form
68
  * 'attr' => array() // Custom <form ...> attributes
69
  * )
70
  */
71
- public function __construct($id, $data = array())
72
- {
73
- if (isset(self::$forms[$id])) {
74
- trigger_error(sprintf(__('Form with id "%s" was already defined', 'fw'), $id), E_USER_ERROR);
75
  }
76
 
77
  $this->id = $id;
78
 
79
- self::$forms[$this->id] =& $this;
80
 
81
  // prepare $this->attr
82
  {
83
- if (!isset($data['attr']) || !is_array($data['attr'])) {
84
  $data['attr'] = array();
85
  }
86
 
87
- $data['attr']['id'] = 'fw_form_'. $this->id;
88
 
89
- if (isset($data['attr']['method'])) {
90
- $data['attr']['method'] = strtolower($data['attr']['method']);
91
 
92
- $data['attr']['method'] = in_array($data['attr']['method'], array('get', 'post'))
93
  ? $data['attr']['method']
94
  : 'post';
95
  } else {
96
  $data['attr']['method'] = 'post';
97
  }
98
 
99
- if (!isset($data['attr']['action'])) {
100
  $data['attr']['action'] = '';
101
  }
102
 
@@ -106,25 +106,25 @@ class FW_Form
106
  // prepare $this->callbacks
107
  {
108
  $this->callbacks = array(
109
- 'render' => empty($data['render']) ? false : $data['render'],
110
- 'validate' => empty($data['validate']) ? false : $data['validate'],
111
- 'save' => empty($data['save']) ? false : $data['save'],
112
  );
113
  }
114
 
115
- if (did_action('wp_loaded')) {
116
  // in case if form instance was created after action
117
  $this->_validate_and_save();
118
  } else {
119
  // attach to an action before 'send_headers' action, to be able to do redirects
120
- add_action('wp_loaded', array($this, '_validate_and_save'), 101);
121
  }
122
  }
123
 
124
- protected function validate()
125
- {
126
- if (is_array($this->errors)) {
127
- trigger_error(__METHOD__ .' already called', E_USER_WARNING);
128
  return;
129
  }
130
 
@@ -138,10 +138,10 @@ class FW_Form
138
  *
139
  * Callback must 'manually' extract input values from $_POST (or $_GET)
140
  */
141
- if ($this->callbacks['validate']) {
142
- $errors = call_user_func_array($this->callbacks['validate'], array($errors));
143
 
144
- if (!is_array($errors)) {
145
 
146
  $errors = array();
147
  }
@@ -150,19 +150,20 @@ class FW_Form
150
  /**
151
  * check nonce
152
  */
153
- if ($this->attr['method'] == 'post') {
154
- $nonce_name = '_nonce_'. md5($this->id);
155
 
156
- if (!isset($_REQUEST[$nonce_name]) || wp_verify_nonce($_REQUEST[$nonce_name], 'submit_fwf') === false) {
157
- $errors[$nonce_name] = __('Nonce verification failed', 'fw');
 
 
158
  }
159
  }
160
 
161
  $this->errors = $errors;
162
  }
163
 
164
- protected function save()
165
- {
166
  $save_data = array(
167
  // you can set here a url for redirect after save
168
  'redirect' => null
@@ -173,23 +174,31 @@ class FW_Form
173
  *
174
  * Callback must 'manually' extract input values from $_POST (or $_GET)
175
  */
176
- if ($this->callbacks['save']) {
177
- $data = call_user_func_array($this->callbacks['save'], array($save_data));
178
 
179
- if (!is_array($data)) {
180
  // fix if returned wrong data from callback
181
  $data = $save_data;
182
  }
183
 
184
  $save_data = $data;
185
 
186
- unset($data);
187
  }
188
 
189
- if (isset($save_data['redirect'])) {
190
- wp_redirect($save_data['redirect']);
191
- exit;
 
 
192
  }
 
 
 
 
 
 
193
  }
194
 
195
  /**
@@ -200,26 +209,38 @@ class FW_Form
200
  * @return bool|null
201
  * @internal
202
  */
203
- public function _validate_and_save()
204
- {
205
- if ($this->validate_and_save_called) {
206
- trigger_error(__METHOD__ .' already called', E_USER_WARNING);
207
  return null;
208
  } else {
209
  $this->validate_and_save_called = true;
210
  }
211
 
212
- if (!$this->is_submitted()) {
213
- return;
214
  }
215
 
216
  $this->validate();
217
 
218
- if (!$this->is_valid()) {
219
- return false;
220
- }
221
 
222
- $this->save();
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
  return true;
225
  }
@@ -227,8 +248,7 @@ class FW_Form
227
  /**
228
  * @return string
229
  */
230
- public function get_id()
231
- {
232
  return $this->id;
233
  }
234
 
@@ -236,12 +256,12 @@ class FW_Form
236
  * Get html attribute(s)
237
  *
238
  * @param null|string $name
 
239
  * @return array|string
240
  */
241
- public function attr($name = null)
242
- {
243
- if ($name) {
244
- return isset($this->attr[$name]) ? $this->attr[$name] : null;
245
  } else {
246
  return $this->attr;
247
  }
@@ -249,63 +269,65 @@ class FW_Form
249
 
250
  /**
251
  * Render form's html
 
 
252
  */
253
- public function render($data = array())
254
- {
255
- ?><form <?php echo fw_attr_to_html($this->attr) ?> ><?php
256
 
257
- if (!empty($this->attr['action']) && $this->attr['method'] == 'get') {
258
  /**
259
  * Add query vars from action attribute url to hidden inputs to not loose them
260
  * For cases when get_search_link() will return '.../?s=~',
261
  * the 's' will be lost after submit and no search page will be shown
262
  */
263
 
264
- parse_str(parse_url($this->attr['action'], PHP_URL_QUERY), $query_vars);
265
 
266
- if (!empty($query_vars)) {
267
- foreach ($query_vars as $var_name => $var_value) {
268
- ?><input type="hidden" name="<?php print esc_attr($var_name) ?>" value="<?php print fw_htmlspecialchars($var_value) ?>" /><?php
 
269
  }
270
  }
271
  }
272
 
273
  ?><input type="hidden" name="<?php print self::$id_input_name; ?>" value="<?php print $this->id ?>" /><?php
274
-
275
- if ($this->attr['method'] == 'post') {
276
- wp_nonce_field('submit_fwf', '_nonce_'. md5($this->id));
277
  }
278
 
279
  $render_data = array(
280
  'submit' => array(
281
- 'value' => __('Submit', 'fw'),
282
  /**
283
  * you can set here custom submit button html
284
  * and the 'value' parameter will not be used
285
  */
286
- 'html' => null,
287
  ),
288
- 'data' => $data,
289
- 'attr' => $this->attr,
290
  );
291
 
292
- unset($data);
293
 
294
- if ($this->callbacks['render']) {
295
- $data = call_user_func_array($this->callbacks['render'], array($render_data));
296
 
297
- if (empty($data)) {
298
  // fix if returned wrong data from callback
299
  $data = $render_data;
300
  }
301
 
302
  $render_data = $data;
303
 
304
- unset($data);
305
  }
306
 
307
  // In filter can be defined custom html for submit button
308
- if (isset($render_data['submit']['html'])):
309
  print $render_data['submit']['html'];
310
  else:
311
  ?><input type="submit" value="<?php print $render_data['submit']['value'] ?>"><?php
@@ -318,22 +340,22 @@ class FW_Form
318
  * If now is a submit of this form
319
  * @return bool
320
  */
321
- public function is_submitted()
322
- {
323
- if (is_null($this->is_submitted)) {
324
- $method = strtoupper($this->attr('method'));
325
 
326
- if ($method === 'POST') {
327
  $this->is_submitted = (
328
- isset($_POST[self::$id_input_name])
329
  &&
330
- FW_Request::POST(self::$id_input_name) === $this->id
331
  );
332
- } elseif ($method === 'GET') {
 
333
  $this->is_submitted = (
334
- isset($_GET[self::$id_input_name])
335
  &&
336
- FW_Request::GET(self::$id_input_name) === $this->id
337
  );
338
  } else {
339
  $this->is_submitted = false;
@@ -346,25 +368,25 @@ class FW_Form
346
  /**
347
  * @return bool
348
  */
349
- public function is_valid()
350
- {
351
- if (!$this->validate_and_save_called) {
352
- trigger_error(__METHOD__ .' called before validation', E_USER_WARNING);
353
  return null;
354
  }
355
 
356
- return empty($this->errors);
357
  }
358
 
359
  /**
360
  * Get validation errors
361
  * @return array
362
  */
363
- public function get_errors()
364
- {
365
- if (!$this->validate_and_save_called) {
366
- trigger_error(__METHOD__ .' called before validation', E_USER_WARNING);
367
- return array('~' => true);
368
  }
369
 
370
  return $this->errors;
@@ -374,23 +396,22 @@ class FW_Form
374
  * Get submitted form instance (or false if no form is currently submitted)
375
  * @return FW_Form|false
376
  */
377
- public static function get_submitted()
378
- {
379
- if (is_null(self::$submitted_id)) {
380
  // method called first time, search for submitted form
381
  do {
382
- foreach (self::$forms as $form) {
383
- if ($form->is_submitted()) {
384
  self::$submitted_id = $form->get_id();
385
  break 2;
386
  }
387
  }
388
 
389
  self::$submitted_id = false;
390
- } while(false);
391
  }
392
 
393
- if (is_string(self::$submitted_id)) {
394
  return self::$forms[ self::$submitted_id ];
395
  } else {
396
  return false;
@@ -398,20 +419,21 @@ class FW_Form
398
  }
399
  }
400
 
401
- if (is_admin()) {
402
  /**
403
  * Display form errors in admin side
404
  */
405
  function _action_show_fw_form_errors_in_admin() {
406
  $form = FW_Form::get_submitted();
407
 
408
- if (!$form || $form->is_valid()) {
409
  return;
410
  }
411
 
412
- foreach ($form->get_errors() as $input_name => $error_message) {
413
- FW_Flash_Messages::add('fw-form-admin-'. $input_name, $error_message, 'error');
414
  }
415
  }
416
- add_action('wp_loaded', '_action_show_fw_form_errors_in_admin', 111);
417
- }
 
1
+ <?php if ( ! defined( 'FW' ) ) {
2
+ die( 'Forbidden' );
3
+ }
4
 
5
  /**
6
  * Dynamic forms
7
  */
8
+ class FW_Form {
 
9
  /**
10
  * Store all form ids created with this class
11
  * @var FW_Form[] {'form_id' => instance}
69
  * 'attr' => array() // Custom <form ...> attributes
70
  * )
71
  */
72
+ public function __construct( $id, $data = array() ) {
73
+ if ( isset( self::$forms[ $id ] ) ) {
74
+ trigger_error( sprintf( __( 'Form with id "%s" was already defined', 'fw' ), $id ), E_USER_ERROR );
 
75
  }
76
 
77
  $this->id = $id;
78
 
79
+ self::$forms[ $this->id ] =& $this;
80
 
81
  // prepare $this->attr
82
  {
83
+ if ( ! isset( $data['attr'] ) || ! is_array( $data['attr'] ) ) {
84
  $data['attr'] = array();
85
  }
86
 
87
+ $data['attr']['class'] = 'fw_form_' . $this->id;
88
 
89
+ if ( isset( $data['attr']['method'] ) ) {
90
+ $data['attr']['method'] = strtolower( $data['attr']['method'] );
91
 
92
+ $data['attr']['method'] = in_array( $data['attr']['method'], array( 'get', 'post' ) )
93
  ? $data['attr']['method']
94
  : 'post';
95
  } else {
96
  $data['attr']['method'] = 'post';
97
  }
98
 
99
+ if ( ! isset( $data['attr']['action'] ) ) {
100
  $data['attr']['action'] = '';
101
  }
102
 
106
  // prepare $this->callbacks
107
  {
108
  $this->callbacks = array(
109
+ 'render' => empty( $data['render'] ) ? false : $data['render'],
110
+ 'validate' => empty( $data['validate'] ) ? false : $data['validate'],
111
+ 'save' => empty( $data['save'] ) ? false : $data['save'],
112
  );
113
  }
114
 
115
+ if ( did_action( 'wp_loaded' ) ) {
116
  // in case if form instance was created after action
117
  $this->_validate_and_save();
118
  } else {
119
  // attach to an action before 'send_headers' action, to be able to do redirects
120
+ add_action( 'wp_loaded', array( $this, '_validate_and_save' ), 101 );
121
  }
122
  }
123
 
124
+ protected function validate() {
125
+ if ( is_array( $this->errors ) ) {
126
+ trigger_error( __METHOD__ . ' already called', E_USER_WARNING );
127
+
128
  return;
129
  }
130
 
138
  *
139
  * Callback must 'manually' extract input values from $_POST (or $_GET)
140
  */
141
+ if ( $this->callbacks['validate'] ) {
142
+ $errors = call_user_func_array( $this->callbacks['validate'], array( $errors ) );
143
 
144
+ if ( ! is_array( $errors ) ) {
145
 
146
  $errors = array();
147
  }
150
  /**
151
  * check nonce
152
  */
153
+ if ( $this->attr['method'] == 'post' ) {
154
+ $nonce_name = '_nonce_' . md5( $this->id );
155
 
156
+ if ( ! isset( $_REQUEST[ $nonce_name ] ) || wp_verify_nonce( $_REQUEST[ $nonce_name ],
157
+ 'submit_fwf' ) === false
158
+ ) {
159
+ $errors[ $nonce_name ] = __( 'Nonce verification failed', 'fw' );
160
  }
161
  }
162
 
163
  $this->errors = $errors;
164
  }
165
 
166
+ protected function save() {
 
167
  $save_data = array(
168
  // you can set here a url for redirect after save
169
  'redirect' => null
174
  *
175
  * Callback must 'manually' extract input values from $_POST (or $_GET)
176
  */
177
+ if ( $this->callbacks['save'] ) {
178
+ $data = call_user_func_array( $this->callbacks['save'], array( $save_data ) );
179
 
180
+ if ( ! is_array( $data ) ) {
181
  // fix if returned wrong data from callback
182
  $data = $save_data;
183
  }
184
 
185
  $save_data = $data;
186
 
187
+ unset( $data );
188
  }
189
 
190
+ if ( ! $this->is_ajax() ) {
191
+ if ( isset( $save_data['redirect'] ) ) {
192
+ wp_redirect( $save_data['redirect'] );
193
+ exit;
194
+ }
195
  }
196
+
197
+ return $save_data;
198
+ }
199
+
200
+ protected function is_ajax() {
201
+ return defined( 'DOING_AJAX' ) && DOING_AJAX;
202
  }
203
 
204
  /**
209
  * @return bool|null
210
  * @internal
211
  */
212
+ public function _validate_and_save() {
213
+ if ( $this->validate_and_save_called ) {
214
+ trigger_error( __METHOD__ . ' already called', E_USER_WARNING );
215
+
216
  return null;
217
  } else {
218
  $this->validate_and_save_called = true;
219
  }
220
 
221
+ if ( ! $this->is_submitted() ) {
222
+ return null;
223
  }
224
 
225
  $this->validate();
226
 
227
+ if ( $this->is_ajax() ) {
228
+ if ( $this->is_valid() ) {
229
+ $this->save();
230
 
231
+ wp_send_json_success();
232
+ } else {
233
+ wp_send_json_error( array(
234
+ 'errors' => $this->get_errors()
235
+ ) );
236
+ }
237
+ } else {
238
+ if ( ! $this->is_valid() ) {
239
+ return false;
240
+ }
241
+
242
+ $this->save();
243
+ }
244
 
245
  return true;
246
  }
248
  /**
249
  * @return string
250
  */
251
+ public function get_id() {
 
252
  return $this->id;
253
  }
254
 
256
  * Get html attribute(s)
257
  *
258
  * @param null|string $name
259
+ *
260
  * @return array|string
261
  */
262
+ public function attr( $name = null ) {
263
+ if ( $name ) {
264
+ return isset( $this->attr[ $name ] ) ? $this->attr[ $name ] : null;
 
265
  } else {
266
  return $this->attr;
267
  }
269
 
270
  /**
271
  * Render form's html
272
+ *
273
+ * @param array $data
274
  */
275
+ public function render( $data = array() ) {
276
+ ?>
277
+ <form <?php echo fw_attr_to_html( $this->attr ) ?> ><?php
278
 
279
+ if ( ! empty( $this->attr['action'] ) && $this->attr['method'] == 'get' ) {
280
  /**
281
  * Add query vars from action attribute url to hidden inputs to not loose them
282
  * For cases when get_search_link() will return '.../?s=~',
283
  * the 's' will be lost after submit and no search page will be shown
284
  */
285
 
286
+ parse_str( parse_url( $this->attr['action'], PHP_URL_QUERY ), $query_vars );
287
 
288
+ if ( ! empty( $query_vars ) ) {
289
+ foreach ( $query_vars as $var_name => $var_value ) {
290
+ ?><input type="hidden" name="<?php print esc_attr( $var_name ) ?>"
291
+ value="<?php print fw_htmlspecialchars( $var_value ) ?>" /><?php
292
  }
293
  }
294
  }
295
 
296
  ?><input type="hidden" name="<?php print self::$id_input_name; ?>" value="<?php print $this->id ?>" /><?php
297
+ if ( $this->attr['method'] == 'post' ) {
298
+ wp_nonce_field( 'submit_fwf', '_nonce_' . md5( $this->id ) );
 
299
  }
300
 
301
  $render_data = array(
302
  'submit' => array(
303
+ 'value' => __( 'Submit', 'fw' ),
304
  /**
305
  * you can set here custom submit button html
306
  * and the 'value' parameter will not be used
307
  */
308
+ 'html' => null,
309
  ),
310
+ 'data' => $data,
311
+ 'attr' => $this->attr,
312
  );
313
 
314
+ unset( $data );
315
 
316
+ if ( $this->callbacks['render'] ) {
317
+ $data = call_user_func_array( $this->callbacks['render'], array( $render_data ) );
318
 
319
+ if ( empty( $data ) ) {
320
  // fix if returned wrong data from callback
321
  $data = $render_data;
322
  }
323
 
324
  $render_data = $data;
325
 
326
+ unset( $data );
327
  }
328
 
329
  // In filter can be defined custom html for submit button
330
+ if ( isset( $render_data['submit']['html'] ) ):
331
  print $render_data['submit']['html'];
332
  else:
333
  ?><input type="submit" value="<?php print $render_data['submit']['value'] ?>"><?php
340
  * If now is a submit of this form
341
  * @return bool
342
  */
343
+ public function is_submitted() {
344
+ if ( is_null( $this->is_submitted ) ) {
345
+ $method = strtoupper( $this->attr( 'method' ) );
 
346
 
347
+ if ( $method === 'POST' ) {
348
  $this->is_submitted = (
349
+ isset( $_POST[ self::$id_input_name ] )
350
  &&
351
+ FW_Request::POST( self::$id_input_name ) === $this->id
352
  );
353
+
354
+ } elseif ( $method === 'GET' ) {
355
  $this->is_submitted = (
356
+ isset( $_GET[ self::$id_input_name ] )
357
  &&
358
+ FW_Request::GET( self::$id_input_name ) === $this->id
359
  );
360
  } else {
361
  $this->is_submitted = false;
368
  /**
369
  * @return bool
370
  */
371
+ public function is_valid() {
372
+ if ( ! $this->validate_and_save_called ) {
373
+ trigger_error( __METHOD__ . ' called before validation', E_USER_WARNING );
374
+
375
  return null;
376
  }
377
 
378
+ return empty( $this->errors );
379
  }
380
 
381
  /**
382
  * Get validation errors
383
  * @return array
384
  */
385
+ public function get_errors() {
386
+ if ( ! $this->validate_and_save_called ) {
387
+ trigger_error( __METHOD__ . ' called before validation', E_USER_WARNING );
388
+
389
+ return array( '~' => true );
390
  }
391
 
392
  return $this->errors;
396
  * Get submitted form instance (or false if no form is currently submitted)
397
  * @return FW_Form|false
398
  */
399
+ public static function get_submitted() {
400
+ if ( is_null( self::$submitted_id ) ) {
 
401
  // method called first time, search for submitted form
402
  do {
403
+ foreach ( self::$forms as $form ) {
404
+ if ( $form->is_submitted() ) {
405
  self::$submitted_id = $form->get_id();
406
  break 2;
407
  }
408
  }
409
 
410
  self::$submitted_id = false;
411
+ } while ( false );
412
  }
413
 
414
+ if ( is_string( self::$submitted_id ) ) {
415
  return self::$forms[ self::$submitted_id ];
416
  } else {
417
  return false;
419
  }
420
  }
421
 
422
+ if ( is_admin() ) {
423
  /**
424
  * Display form errors in admin side
425
  */
426
  function _action_show_fw_form_errors_in_admin() {
427
  $form = FW_Form::get_submitted();
428
 
429
+ if ( ! $form || $form->is_valid() ) {
430
  return;
431
  }
432
 
433
+ foreach ( $form->get_errors() as $input_name => $error_message ) {
434
+ FW_Flash_Messages::add( 'fw-form-admin-' . $input_name, $error_message, 'error' );
435
  }
436
  }
437
+
438
+ add_action( 'wp_loaded', '_action_show_fw_form_errors_in_admin', 111 );
439
+ }
framework/helpers/class-fw-wp-filesystem.php CHANGED
@@ -83,10 +83,10 @@ class FW_WP_Filesystem
83
 
84
  /**
85
  * Convert real file path to WP Filesystem path
86
- * @param string $path
87
  * @return string
88
  */
89
- final public static function real_path_to_filesystem_path($path) {
90
  /** @var WP_Filesystem_Base $wp_filesystem */
91
  global $wp_filesystem;
92
 
@@ -94,11 +94,11 @@ class FW_WP_Filesystem
94
  trigger_error('Filesystem is not available', E_USER_ERROR);
95
  }
96
 
97
- $path = fw_fix_path($path);
98
-
99
  $real_abspath = fw_fix_path(ABSPATH);
100
  $wp_filesystem_abspath = fw_fix_path($wp_filesystem->abspath());
101
- $relative_path = preg_replace('/^'. preg_quote($real_abspath, '/') .'/', '', $path);
 
102
 
103
  return $wp_filesystem_abspath . $relative_path;
104
  }
@@ -117,9 +117,9 @@ class FW_WP_Filesystem
117
  }
118
 
119
  $wp_filesystem_path = fw_fix_path($wp_filesystem_path);
120
-
121
- $real_abspath = fw_fix_path(ABSPATH);
122
  $wp_filesystem_abspath = fw_fix_path($wp_filesystem->abspath());
 
 
123
  $relative_path = preg_replace('/^'. preg_quote($wp_filesystem_abspath, '/') .'/', '', $wp_filesystem_path);
124
 
125
  return $real_abspath . $relative_path;
@@ -127,9 +127,10 @@ class FW_WP_Filesystem
127
 
128
  /**
129
  * Check if there is direct filesystem access, so we can make changes without asking the credentials via form
 
130
  * @return bool
131
  */
132
- final public static function has_direct_access()
133
  {
134
  /** @var WP_Filesystem_Base $wp_filesystem */
135
  global $wp_filesystem;
@@ -138,10 +139,10 @@ class FW_WP_Filesystem
138
  return $wp_filesystem->method === 'direct';
139
  }
140
 
141
- if (get_filesystem_method() === 'direct') {
142
  ob_start();
143
  {
144
- $creds = request_filesystem_credentials(site_url() . '/wp-admin/', '', false, false, null);
145
  }
146
  ob_end_clean();
147
 
@@ -170,24 +171,27 @@ class FW_WP_Filesystem
170
 
171
  $path = '';
172
  $check_if_exists = true;
173
- $firs_loop = true;
174
  foreach (explode('/', $wp_filesystem_dir_path) as $dir_name) {
175
  if (empty($dir_name)) {
176
- if ($firs_loop) {
177
  /**
178
- * It's a unix style path staring with '/'
179
- * (On windows it starts with 'C:/')
180
  */
181
  $path = '/';
182
  } else {
183
  trigger_error('Invalid path: '. $wp_filesystem_dir_path, E_USER_WARNING);
184
  return false;
185
  }
 
 
 
186
  }
187
 
188
- $path .= ($firs_loop ? '' : '/') . $dir_name;
189
 
190
- $firs_loop = false;
191
 
192
  if ($check_if_exists) {
193
  if ($wp_filesystem->is_dir($path)) {
83
 
84
  /**
85
  * Convert real file path to WP Filesystem path
86
+ * @param string $real_path
87
  * @return string
88
  */
89
+ final public static function real_path_to_filesystem_path($real_path) {
90
  /** @var WP_Filesystem_Base $wp_filesystem */
91
  global $wp_filesystem;
92
 
94
  trigger_error('Filesystem is not available', E_USER_ERROR);
95
  }
96
 
97
+ $real_path = fw_fix_path($real_path);
 
98
  $real_abspath = fw_fix_path(ABSPATH);
99
  $wp_filesystem_abspath = fw_fix_path($wp_filesystem->abspath());
100
+
101
+ $relative_path = preg_replace('/^'. preg_quote($real_abspath, '/') .'/', '', $real_path);
102
 
103
  return $wp_filesystem_abspath . $relative_path;
104
  }
117
  }
118
 
119
  $wp_filesystem_path = fw_fix_path($wp_filesystem_path);
 
 
120
  $wp_filesystem_abspath = fw_fix_path($wp_filesystem->abspath());
121
+ $real_abspath = fw_fix_path(ABSPATH);
122
+
123
  $relative_path = preg_replace('/^'. preg_quote($wp_filesystem_abspath, '/') .'/', '', $wp_filesystem_path);
124
 
125
  return $real_abspath . $relative_path;
127
 
128
  /**
129
  * Check if there is direct filesystem access, so we can make changes without asking the credentials via form
130
+ * @param string|null $context
131
  * @return bool
132
  */
133
+ final public static function has_direct_access($context = null)
134
  {
135
  /** @var WP_Filesystem_Base $wp_filesystem */
136
  global $wp_filesystem;
139
  return $wp_filesystem->method === 'direct';
140
  }
141
 
142
+ if (get_filesystem_method(array(), $context) === 'direct') {
143
  ob_start();
144
  {
145
+ $creds = request_filesystem_credentials(admin_url(), '', false, $context, null);
146
  }
147
  ob_end_clean();
148
 
171
 
172
  $path = '';
173
  $check_if_exists = true;
174
+ $loop_counter = 1;
175
  foreach (explode('/', $wp_filesystem_dir_path) as $dir_name) {
176
  if (empty($dir_name)) {
177
+ if ($loop_counter === 1) {
178
  /**
179
+ * It's a unix style path staring with '/' -> ''
180
+ * On windows it starts with 'C:/' -> 'C:'
181
  */
182
  $path = '/';
183
  } else {
184
  trigger_error('Invalid path: '. $wp_filesystem_dir_path, E_USER_WARNING);
185
  return false;
186
  }
187
+ } elseif ($loop_counter === 2 && $path === '/') {
188
+ // prevent multiple slash prefix '//var/www'
189
+ $path = '';
190
  }
191
 
192
+ $path .= ($loop_counter === 1 ? '' : '/') . $dir_name;
193
 
194
+ $loop_counter++;
195
 
196
  if ($check_if_exists) {
197
  if ($wp_filesystem->is_dir($path)) {
framework/helpers/general.php CHANGED
@@ -211,6 +211,15 @@ function fw_print($value) {
211
  line-height: 16px;
212
  text-align: left;
213
  }
 
 
 
 
 
 
 
 
 
214
  </style>';
215
  echo str_replace(array(' ', "\n"), '', ob_get_clean());
216
 
@@ -222,9 +231,11 @@ function fw_print($value) {
222
  echo fw_htmlspecialchars(FW_Dumper::dump($value));
223
  echo '</pre></div>';
224
  } else {
 
225
  foreach (func_get_args() as $param) {
226
  fw_print($param);
227
  }
 
228
  }
229
  }
230
 
211
  line-height: 16px;
212
  text-align: left;
213
  }
214
+
215
+ div.fw_print_r_group {
216
+ background: #111;
217
+ margin: 10px 30px;
218
+ padding: 1px;
219
+ }
220
+ div.fw_print_r_group div.fw_print_r {
221
+ margin: 9px;
222
+ }
223
  </style>';
224
  echo str_replace(array(' ', "\n"), '', ob_get_clean());
225
 
231
  echo fw_htmlspecialchars(FW_Dumper::dump($value));
232
  echo '</pre></div>';
233
  } else {
234
+ echo '<div class="fw_print_r_group">';
235
  foreach (func_get_args() as $param) {
236
  fw_print($param);
237
  }
238
+ echo '</div>';
239
  }
240
  }
241
 
framework/manifest.php CHANGED
@@ -4,4 +4,4 @@ $manifest = array();
4
 
5
  $manifest['name'] = __('Unyson', 'fw');
6
 
7
- $manifest['version'] = '2.1.1';
4
 
5
  $manifest['name'] = __('Unyson', 'fw');
6
 
7
+ $manifest['version'] = '2.1.2';
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
4
  Requires at least: 4.0.0
5
  Tested up to: 4.0.1
6
- Stable tag: 2.1.1
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -82,6 +82,9 @@ Yes; Unyson will work with any theme.
82
 
83
  == Changelog ==
84
 
 
 
 
85
  = 2.1.1 =
86
  * Added the `FW_Extension::(get|set)_db_(settings_option|data)()` methods
87
  * Added README.md for Github
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
4
  Requires at least: 4.0.0
5
  Tested up to: 4.0.1
6
+ Stable tag: 2.1.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
82
 
83
  == Changelog ==
84
 
85
+ = 2.1.2 =
86
+ * Minor fixes and improvements in the extensions installation process
87
+
88
  = 2.1.1 =
89
  * Added the `FW_Extension::(get|set)_db_(settings_option|data)()` methods
90
  * Added README.md for Github
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.1.1
7
  * Author: ThemeFuse
8
  * Author URI: http://themefuse.com
9
  * License: GPL2+
@@ -83,4 +83,15 @@ require dirname( __FILE__ ) . '/framework/bootstrap.php';
83
  load_plugin_textdomain( 'fw', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
84
  }
85
  add_action( 'plugins_loaded', '_action_fw_textdomain' );
 
 
 
 
 
 
 
 
 
 
 
86
  }
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.1.2
7
  * Author: ThemeFuse
8
  * Author URI: http://themefuse.com
9
  * License: GPL2+
83
  load_plugin_textdomain( 'fw', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
84
  }
85
  add_action( 'plugins_loaded', '_action_fw_textdomain' );
86
+
87
+ /** @internal */
88
+ function _filter_fw_tmp_dir($dir) {
89
+ /**
90
+ * Some users force WP_Filesystem to use the 'direct' method <?php define( 'FS_METHOD', 'direct' ); ?> and set chmod 777 to the unyson/ plugin.
91
+ * By default tmp dir is WP_CONTENT_DIR.'/tmp' and WP_Filesystem can't create it with 'direct' method, then users can't download and install extensions.
92
+ * In order to prevent this situation, create the temporary directory inside the plugin folder.
93
+ */
94
+ return dirname(__FILE__) . '/tmp';
95
+ }
96
+ add_filter('fw_tmp_dir', '_filter_fw_tmp_dir');
97
  }