Cloud Templates & Patterns collection - Version 1.0.7

Version Description

Download this release

Release Info

Developer themeisle
Plugin Icon 128x128 Cloud Templates & Patterns collection
Version 1.0.7
Comparing to
See all releases

Version 1.0.7

Files changed (39) hide show
  1. .wordpress-org/.empty +0 -0
  2. CHANGELOG.md +31 -0
  3. CONTRIBUTING.md +14 -0
  4. README.md +73 -0
  5. includes/Admin.php +247 -0
  6. includes/Importers/Content_Importer.php +291 -0
  7. includes/Importers/Helpers/Helper.php +116 -0
  8. includes/Importers/Helpers/Importer_Alterator.php +216 -0
  9. includes/Importers/Helpers/Quiet_Skin.php +59 -0
  10. includes/Importers/Helpers/Quiet_Skin_Legacy.php +58 -0
  11. includes/Importers/Plugin_Importer.php +301 -0
  12. includes/Importers/Theme_Mods_Importer.php +185 -0
  13. includes/Importers/WP/Beaver_Data_Fix.php +72 -0
  14. includes/Importers/WP/Beaver_ParserXML.php +82 -0
  15. includes/Importers/WP/Elementor_Meta_Handler.php +116 -0
  16. includes/Importers/WP/WP_Import.php +906 -0
  17. includes/Importers/WP/WXR_Parser.php +95 -0
  18. includes/Importers/WP/WXR_Parser_SimpleXML.php +206 -0
  19. includes/Importers/WP/WXR_Parser_XML.php +239 -0
  20. includes/Importers/Widgets_Importer.php +232 -0
  21. includes/Importers/Zelle_Importer.php +1016 -0
  22. includes/Logger.php +223 -0
  23. includes/Main.php +167 -0
  24. includes/Rest_Server.php +240 -0
  25. includes/Sites_Listing.php +262 -0
  26. includes/WP_Cli.php +447 -0
  27. migration/zelle/zelle.json +1 -0
  28. migration/zelle/zelle.png +0 -0
  29. readme.txt +73 -0
  30. templates-patterns-collection.php +85 -0
  31. vendor/autoload.php +7 -0
  32. vendor/composer/ClassLoader.php +445 -0
  33. vendor/composer/LICENSE +21 -0
  34. vendor/composer/autoload_classmap.php +31 -0
  35. vendor/composer/autoload_namespaces.php +9 -0
  36. vendor/composer/autoload_psr4.php +10 -0
  37. vendor/composer/autoload_real.php +55 -0
  38. vendor/composer/autoload_static.php +57 -0
  39. vendor/composer/installed.json +1 -0
.wordpress-org/.empty ADDED
File without changes
CHANGELOG.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##### [Version 1.0.7](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.6...v1.0.7) (2020-07-29)
2
+
3
+ chore: adds SVN deployment workflow
4
+
5
+ ##### [Version 1.0.6](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.5...v1.0.6) (2020-07-27)
6
+
7
+ > Things are getting better every day. 🚀
8
+
9
+ ##### [Version 1.0.5](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.4...v1.0.5) (2020-07-27)
10
+
11
+ > Things are getting better every day. 🚀
12
+
13
+ ##### [Version 1.0.4](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.3...v1.0.4) (2020-07-24)
14
+
15
+ Fetch starter sites remotely
16
+
17
+ ##### [Version 1.0.3](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.2...v1.0.3) (2020-07-23)
18
+
19
+ > Things are getting better every day. 🚀
20
+
21
+ ##### [Version 1.0.2](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.1...v1.0.2) (2020-07-23)
22
+
23
+ > Things are getting better every day. 🚀
24
+
25
+ ##### [Version 1.0.1](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.0...v1.0.1) (2020-07-21)
26
+
27
+ - adds plugin code
28
+
29
+ #### Version1.0.0 (2020-07-21)
30
+
31
+ Initial Release
CONTRIBUTING.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ ## Releasing
3
+
4
+ This repository uses conventional [changelog commit](https://github.com/Codeinwp/conventional-changelog-simple-preset) messages to trigger release
5
+
6
+ How to release a new version:
7
+
8
+ - Clone the master branch
9
+ - Do your changes
10
+ - Send a PR to master and merge it using the following subject message
11
+ - `release: <release short description>` - for patch release
12
+ - `release(minor): <release short description>` - for minor release
13
+ - `release(major): <release short description>` - for major release
14
+ The release notes will inherit the body of the commit message which triggered the release. For more details check the [simple-preset](https://github.com/Codeinwp/conventional-changelog-simple-preset) that we use.
README.md ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Cloud Templates & Patterns collection #
2
+ **Contributors:** [themeisle](https://profiles.wordpress.org/themeisle)
3
+ **Tags:** neve, templates, patterns, blocks, starter, sites, demo, content, import
4
+ **Requires at least:** 4.7
5
+ **Tested up to:** 5.4
6
+ **Requires PHP:** 5.6
7
+ **Stable tag:** trunk
8
+ **License:** GPLv3
9
+ **License URI:** https://www.gnu.org/licenses/gpl-3.0.en.html
10
+
11
+ A cloud based service with 100+ templates and starter sites for Neve theme.
12
+
13
+ ## Description ##
14
+
15
+ ### TEMPLATE SERVICE FOR ELEMENTOR, BEAVER BUILDER, BRIZY AND GUTENBERG, DIVI and THRIVE ###
16
+
17
+
18
+ A cloud based templates library which enables you to create ready-made website in no time.
19
+
20
+ All templates can be previewed on [demosites.io](https://demosites.io/), their import into your site is facilitated by this plugin.
21
+
22
+ The plugin is relying on the service behind api.themeisle.com for accessing the template collection list and their individual structure on import.
23
+
24
+ No account is required to access the service template collection and the privacy policy can be found [here](https://themeisle.com/privacy-policy/).
25
+
26
+ ## Frequently Asked Questions ##
27
+
28
+ ## Changelog ##
29
+
30
+ ##### [Version 1.0.7](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.6...v1.0.7) (2020-07-29)
31
+
32
+ chore: adds SVN deployment workflow
33
+
34
+
35
+
36
+
37
+ ##### [Version 1.0.6](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.5...v1.0.6) (2020-07-27)
38
+
39
+ > Things are getting better every day. 🚀
40
+
41
+
42
+
43
+
44
+ ##### [Version 1.0.5](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.4...v1.0.5) (2020-07-27)
45
+
46
+ > Things are getting better every day. 🚀
47
+
48
+
49
+
50
+
51
+ ##### [Version 1.0.4](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.3...v1.0.4) (2020-07-24)
52
+
53
+ Fetch starter sites remotely
54
+
55
+
56
+
57
+
58
+ ##### [Version 1.0.3](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.2...v1.0.3) (2020-07-23)
59
+
60
+ > Things are getting better every day. 🚀
61
+
62
+
63
+
64
+
65
+ ##### [Version 1.0.2](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.1...v1.0.2) (2020-07-23)
66
+
67
+ > Things are getting better every day. 🚀
68
+
69
+
70
+
71
+
72
+
73
+
includes/Admin.php ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handles admin logic for the onboarding.
4
+ *
5
+ * @package templates-patterns-collection
6
+ */
7
+
8
+ namespace TIOB;
9
+
10
+ /**
11
+ * Class Admin
12
+ *
13
+ * @package templates-patterns-collection
14
+ */
15
+ class Admin {
16
+
17
+ /**
18
+ * Initialize the Admin.
19
+ */
20
+ public function init() {
21
+ add_filter( 'query_vars', array( $this, 'add_onboarding_query_var' ) );
22
+ add_action( 'after_switch_theme', array( $this, 'get_previous_theme' ) );
23
+ add_filter( 'neve_dashboard_page_data', array( $this, 'localize_sites_library' ) );
24
+ }
25
+
26
+ /**
27
+ * Memorize the previous theme to later display the import template for it.
28
+ */
29
+ public function get_previous_theme() {
30
+ $previous_theme = strtolower( get_option( 'theme_switched' ) );
31
+ set_theme_mod( 'ti_prev_theme', $previous_theme );
32
+ }
33
+
34
+ /**
35
+ * Add our onboarding query var.
36
+ *
37
+ * @param array $vars_array the registered query vars.
38
+ *
39
+ * @return array
40
+ */
41
+ public function add_onboarding_query_var( $vars_array ) {
42
+ array_push( $vars_array, 'onboarding' );
43
+
44
+ return $vars_array;
45
+ }
46
+
47
+ /**
48
+ * Localize the sites library.
49
+ *
50
+ * @param array $array the about page array.
51
+ *
52
+ * @return array
53
+ */
54
+ public function localize_sites_library( $array ) {
55
+ $api = array(
56
+ 'sites' => $this->get_sites_data(),
57
+ 'root' => esc_url_raw( rest_url( Main::API_ROOT ) ),
58
+ 'nonce' => wp_create_nonce( 'wp_rest' ),
59
+ 'homeUrl' => esc_url( home_url() ),
60
+ 'i18n' => $this->get_strings(),
61
+ 'onboarding' => false,
62
+ 'logUrl' => WP_Filesystem() ? Logger::get_instance()->get_log_url() : null,
63
+ );
64
+
65
+ $is_onboarding = isset( $_GET['onboarding'] ) && $_GET['onboarding'] === 'yes';
66
+ if ( $is_onboarding ) {
67
+ $api['onboarding'] = true;
68
+ }
69
+
70
+ $array['onboarding'] = $api;
71
+
72
+ return $array;
73
+ }
74
+
75
+ /**
76
+ * Get all the sites data.
77
+ *
78
+ * @return array
79
+ */
80
+ public function get_sites_data() {
81
+ $theme_support = get_theme_support( 'themeisle-demo-import' );
82
+ if ( empty( $theme_support[0] ) || ! is_array( $theme_support[0] ) ) {
83
+ return array();
84
+ }
85
+ $theme_support = $theme_support[0];
86
+ $sites = isset( $theme_support['remote'] ) ? $theme_support['remote'] : null;
87
+
88
+ foreach ( $sites as $builder => $sites_for_builder ) {
89
+ foreach ( $sites_for_builder as $slug => $data ) {
90
+ if ( ! isset( $data['upsell'] ) || $data['upsell'] !== true ) {
91
+ continue;
92
+ }
93
+ $sites[ $builder ][ $slug ]['utmOutboundLink'] = add_query_arg(
94
+ apply_filters(
95
+ 'ti_onboarding_outbound_query_args',
96
+ array(
97
+ 'utm_medium' => 'about-' . get_template(),
98
+ 'utm_source' => $slug,
99
+ 'utm_campaign' => 'siteslibrary',
100
+ )
101
+ ),
102
+ $theme_support['pro_link']
103
+ );
104
+ }
105
+ }
106
+
107
+ return array(
108
+ 'sites' => $sites,
109
+ 'migration' => $this->get_migrateable( $theme_support ),
110
+ );
111
+ }
112
+
113
+ /**
114
+ * Get migratable data.
115
+ *
116
+ * This is used if we can ensure migration from a previous theme to a template.
117
+ *
118
+ * @param array $theme_support the theme support array.
119
+ *
120
+ * @return array
121
+ */
122
+ private function get_migrateable( $theme_support ) {
123
+ if ( ! isset( $theme_support['can_migrate'] ) ) {
124
+ return null;
125
+ }
126
+
127
+ $data = $theme_support['can_migrate'];
128
+ $old_theme = get_theme_mod( 'ti_prev_theme', 'ti_onboarding_undefined' );
129
+ $folder_name = $old_theme;
130
+ $previous_theme_slug = $this->get_parent_theme( $old_theme );
131
+
132
+ if ( ! empty( $previous_theme_slug ) ) {
133
+ $folder_name = $previous_theme_slug;
134
+ $old_theme = $previous_theme_slug;
135
+ }
136
+
137
+ if ( ! array_key_exists( $old_theme, $data ) ) {
138
+ return null;
139
+ }
140
+
141
+ $content_imported = get_theme_mod( $data[ $old_theme ]['theme_mod_check'], 'not-imported' );
142
+ if ( $content_imported === 'yes' ) {
143
+ return null;
144
+ }
145
+
146
+ if ( in_array( $old_theme, array( 'zerif-lite', 'zerif-pro' ), true ) ) {
147
+ $folder_name = 'zelle';
148
+ }
149
+
150
+ $options = array(
151
+ 'theme_name' => ! empty( $data[ $old_theme ]['theme_name'] ) ? esc_html( $data[ $old_theme ]['theme_name'] ) : '',
152
+ 'screenshot' => get_template_directory_uri() . Main::OBOARDING_PATH . '/migration/' . $folder_name . '/' . $data[ $old_theme ]['template'] . '.png',
153
+ 'template' => get_template_directory() . Main::OBOARDING_PATH . '/migration/' . $folder_name . '/' . $data[ $old_theme ]['template'] . '.json',
154
+ 'template_name' => $data[ $old_theme ]['template'],
155
+ 'heading' => $data[ $old_theme ]['heading'],
156
+ 'description' => $data[ $old_theme ]['description'],
157
+ 'theme_mod' => $data[ $old_theme ]['theme_mod_check'],
158
+ 'mandatory_plugins' => isset( $data[ $old_theme ]['mandatory_plugins'] ) ? $data[ $old_theme ]['mandatory_plugins'] : array(),
159
+ 'recommended_plugins' => isset( $data[ $old_theme ]['recommended_plugins'] ) ? $data[ $old_theme ]['recommended_plugins'] : array(),
160
+ );
161
+
162
+ if ( ! empty( $previous_theme_slug ) ) {
163
+ $options['description'] = __( 'Hi! We\'ve noticed you were using a child theme of Zelle before. To make your transition easier, we can help you keep the same homepage settings you had before but in original Zelle\'s style, by converting it into an Elementor template.', 'neve' );
164
+ }
165
+
166
+ return $options;
167
+ }
168
+
169
+ /**
170
+ * Get previous theme parent if it's a child theme.
171
+ *
172
+ * @param string $previous_theme Previous theme slug.
173
+ *
174
+ * @return string
175
+ */
176
+ private function get_parent_theme( $previous_theme ) {
177
+ $available_themes = wp_get_themes();
178
+ if ( ! array_key_exists( $previous_theme, $available_themes ) ) {
179
+ return false;
180
+ }
181
+ $theme_object = $available_themes[ $previous_theme ];
182
+
183
+ return $theme_object->get( 'Template' );
184
+ }
185
+
186
+
187
+ /**
188
+ * Get strings.
189
+ *
190
+ * @return array
191
+ */
192
+ private function get_strings() {
193
+ return array(
194
+ 'preview_btn' => __( 'Preview', 'neve' ),
195
+ 'import_btn' => __( 'Import', 'neve' ),
196
+ 'pro_btn' => __( 'Get the PRO version!', 'neve' ),
197
+ 'importing' => __( 'Importing', 'neve' ),
198
+ 'cancel_btn' => __( 'Cancel', 'neve' ),
199
+ 'loading' => __( 'Loading', 'neve' ),
200
+ 'go_to_site' => __( 'View Website', 'neve' ),
201
+ 'edit_template' => __( 'Add your own content', 'neve' ),
202
+ 'back' => __( 'Back to Sites Library', 'neve' ),
203
+ 'note' => __( 'Note', 'neve' ),
204
+ 'advanced_options' => __( 'Advanced Options', 'neve' ),
205
+ 'plugins' => __( 'Plugins', 'neve' ),
206
+ 'general' => __( 'General', 'neve' ),
207
+ 'later' => __( 'Keep current layout', 'neve' ),
208
+ 'search' => __( 'Search', 'neve' ),
209
+ 'content' => __( 'Content', 'neve' ),
210
+ 'customizer' => __( 'Customizer', 'neve' ),
211
+ 'widgets' => __( 'Widgets', 'neve' ),
212
+ 'backup_disclaimer' => __( 'We recommend you backup your website content before attempting a full site import.', 'neve' ),
213
+ 'placeholders_disclaimer' => __( 'Due to copyright issues, some of the demo images will not be imported and will be replaced by placeholder images.', 'neve' ),
214
+ 'placeholders_disclaimer_new' => __( 'Some of the demo images will not be imported and will be replaced by placeholder images.', 'neve' ),
215
+ 'unsplash_gallery_link' => __( 'Here is our own collection of related images you can use for your site.', 'neve' ),
216
+ 'import_done' => __( 'Content was successfully imported. Enjoy your new site!', 'neve' ),
217
+ 'pro_demo' => __( 'Available in the PRO version', 'neve' ),
218
+ 'copy_error_code' => __( 'Copy error code', 'neve' ),
219
+ 'download_error_log' => __( 'Download error log', 'neve' ),
220
+ 'external_plugins_notice' => __( 'To import this demo you have to install the following plugins:', 'neve' ),
221
+ /* translators: 1 - 'here'. */
222
+ 'rest_not_working' => sprintf(
223
+ __( 'It seems that Rest API is not working properly on your website. Read about how you can fix it %1$s.', 'neve' ),
224
+ sprintf( '<a href="https://docs.themeisle.com/article/1157-starter-sites-library-import-is-not-working#rest-api">%1$s<i class="dashicons dashicons-external"></i></a>', __( 'here', 'neve' ) )
225
+ ),
226
+ /* translators: 1 - 'get in touch'. */
227
+ 'error_report' => sprintf(
228
+ __( 'Hi! It seems there is a configuration issue with your server that\'s causing the import to fail. Please %1$s with us with the error code below, so we can help you fix this.', 'neve' ),
229
+ sprintf( '<a href="https://themeisle.com/contact">%1$s <i class="dashicons dashicons-external"></i></a>', __( 'get in touch', 'neve' ) )
230
+ ),
231
+ /* translators: 1 - 'troubleshooting guide'. */
232
+ 'troubleshooting' => sprintf(
233
+ __( 'Hi! It seems there is a configuration issue with your server that\'s causing the import to fail. Take a look at our %1$s to see if any of the proposed solutions work.', 'neve' ),
234
+ sprintf( '<a href="https://docs.themeisle.com/article/1157-starter-sites-library-import-is-not-working">%1$s <i class="dashicons dashicons-external"></i></a>', __( 'troubleshooting guide', 'neve' ) )
235
+ ),
236
+ /* translators: 1 - 'get in touch'. */
237
+ 'support' => sprintf(
238
+ __( 'If none of the solutions in the guide work, please %1$s with us with the error code below, so we can help you fix this.', 'neve' ),
239
+ sprintf( '<a href="https://themeisle.com/contact">%1$s <i class="dashicons dashicons-external"></i></a>', __( 'get in touch', 'neve' ) )
240
+ ),
241
+ 'fsDown' => sprintf(
242
+ __( 'It seems that %s is not available. You can contact your site administrator or hosting provider to help you enable it.', 'neve' ),
243
+ sprintf( '<code>WP_Filesystem</code>' )
244
+ ),
245
+ );
246
+ }
247
+ }
includes/Importers/Content_Importer.php ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Content Import Handling
4
+ *
5
+ * @package templates-patterns-collection
6
+ */
7
+
8
+ namespace TIOB\Importers;
9
+
10
+ use TIOB\Importers\Helpers\Helper;
11
+ use TIOB\Importers\Helpers\Importer_Alterator;
12
+ use TIOB\Logger;
13
+ use TIOB\Importers\WP\WP_Import;
14
+ use WP_Error;
15
+ use WP_REST_Request;
16
+ use WP_REST_Response;
17
+
18
+ /**
19
+ * Class Content_Importer
20
+ *
21
+ * @package templates-patterns-collection
22
+ */
23
+ class Content_Importer {
24
+ use Helper;
25
+
26
+ private $logger = null;
27
+
28
+ /**
29
+ * Constructor.
30
+ */
31
+ public function __construct() {
32
+ $this->load_importer();
33
+ $this->logger = Logger::get_instance();
34
+ }
35
+
36
+ /**
37
+ * Import Remote XML file.
38
+ *
39
+ * @param WP_REST_Request $request the async request.
40
+ *
41
+ * @return WP_REST_Response
42
+ */
43
+ public function import_remote_xml( WP_REST_Request $request ) {
44
+ if ( ! current_user_can( 'manage_options' ) ) {
45
+ $this->logger->log( 'No manage_options permissions' );
46
+
47
+ return new WP_REST_Response(
48
+ array(
49
+ 'data' => 'ti__ob_permission_err_1',
50
+ 'success' => false,
51
+ )
52
+ );
53
+ }
54
+
55
+ do_action( 'themeisle_ob_before_xml_import' );
56
+
57
+ $body = $request->get_json_params();
58
+
59
+ $content_file_url = $body['contentFile'];
60
+ $page_builder = isset( $body['editor'] ) ? $body['editor'] : '';
61
+
62
+ if ( empty( $content_file_url ) ) {
63
+ $this->logger->log( "No content file to import at url {$content_file_url}" );
64
+
65
+ return new WP_REST_Response(
66
+ array(
67
+ 'data' => 'ti__ob_remote_err_1',
68
+ 'success' => false,
69
+ )
70
+ );
71
+ }
72
+
73
+ if ( ! isset( $body['source'] ) || empty( $body['source'] ) ) {
74
+ $this->logger->log( 'No source defined for the import.' );
75
+
76
+ return new WP_REST_Response(
77
+ array(
78
+ 'data' => 'ti__ob_remote_err_2',
79
+ 'success' => false,
80
+ )
81
+ );
82
+ }
83
+
84
+ set_time_limit( 0 );
85
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
86
+ require_once( ABSPATH . 'wp-admin/includes/image.php' );
87
+ require_once( ABSPATH . 'wp-admin/includes/media.php' );
88
+
89
+ if ( $body['source'] === 'remote' ) {
90
+ $this->logger->log( 'Saving remote XML', 'progress' );
91
+
92
+ $request_args = array(
93
+ 'headers' => array(
94
+ 'User-Agent' => 'WordPress/' . md5( get_site_url() ),
95
+ ),
96
+ );
97
+
98
+ $response_file = wp_remote_get( add_query_arg( 'key', apply_filters( 'product_neve_license_key', 'free' ), $content_file_url ), $request_args );
99
+
100
+ if ( is_wp_error( $response_file ) ) {
101
+ $this->logger->log( "Error saving the remote file: {$response_file->get_error_message()}.", 'success' );
102
+ }
103
+ $content_file_path = $this->save_xhr_return_path( wp_remote_retrieve_body( $response_file ) );
104
+ $this->logger->log( "Saved remote XML at path {$content_file_path}.", 'success' );
105
+ } else {
106
+ $this->logger->log( 'Using local XML.', 'success' );
107
+ $content_file_path = $content_file_url;
108
+ }
109
+
110
+ $this->logger->log( 'Starting content import...', 'progress' );
111
+ $import_status = $this->import_file( $content_file_path, $body, $page_builder );
112
+
113
+ if ( is_wp_error( $import_status ) ) {
114
+ $this->logger->log( "Import crashed with message: {$import_status->get_error_message()}" );
115
+
116
+ return new WP_REST_Response(
117
+ array(
118
+ 'data' => $import_status,
119
+ 'success' => false,
120
+ )
121
+ );
122
+ }
123
+
124
+ if ( $body['source'] === 'remote' ) {
125
+ unlink( $content_file_path );
126
+ }
127
+
128
+ do_action( 'themeisle_ob_after_xml_import' );
129
+
130
+ $this->logger->log( 'Busting elementor cache', 'progress' );
131
+ $this->maybe_bust_elementor_cache();
132
+
133
+ // Set front page.
134
+ if ( isset( $body['frontPage'] ) ) {
135
+ $frontpage_id = $this->setup_front_page( $body['frontPage'], $body['demoSlug'] );
136
+ }
137
+ do_action( 'themeisle_ob_after_front_page_setup' );
138
+
139
+ // Set shop pages.
140
+ if ( isset( $body['shopPages'] ) ) {
141
+ $this->setup_shop_pages( $body['shopPages'], $body['demoSlug'] );
142
+ }
143
+ do_action( 'themeisle_ob_after_shop_pages_setup' );
144
+
145
+ if ( empty( $frontpage_id ) ) {
146
+ $this->logger->log( 'No front page ID.' );
147
+ }
148
+
149
+ return new WP_REST_Response(
150
+ array(
151
+ 'success' => true,
152
+ 'frontpage_id' => $frontpage_id,
153
+ )
154
+ );
155
+ }
156
+
157
+ /**
158
+ * Save remote XML file and return the file path.
159
+ *
160
+ * @param string $content the content.
161
+ *
162
+ * @return string
163
+ */
164
+ public function save_xhr_return_path( $content ) {
165
+ $wp_upload_dir = wp_upload_dir( null, false );
166
+ $file_path = $wp_upload_dir['basedir'] . '/themeisle-demo-import.xml';
167
+ require_once( ABSPATH . '/wp-admin/includes/file.php' );
168
+ global $wp_filesystem;
169
+ WP_Filesystem();
170
+ $wp_filesystem->put_contents( $file_path, $content );
171
+
172
+ return $file_path;
173
+ }
174
+
175
+ /**
176
+ * Set up front page options by `post_name`.
177
+ *
178
+ * @param array $args the front page array.
179
+ * @param string $demo_slug the importing demo slug.
180
+ *
181
+ * @return int|void
182
+ */
183
+ public function setup_front_page( $args, $demo_slug ) {
184
+ if ( ! is_array( $args ) ) {
185
+ return;
186
+ }
187
+ if ( empty( $args['front_page'] ) && empty( $args['blog_page'] ) ) {
188
+ $this->logger->log( 'No front page to set up.', 'success' );
189
+
190
+ return null;
191
+ }
192
+
193
+ update_option( 'show_on_front', 'page' );
194
+
195
+ if ( isset( $args['front_page'] ) && $args['front_page'] !== null ) {
196
+ $front_page_obj = get_page_by_path( $this->cleanup_page_slug( $args['front_page'], $demo_slug ) );
197
+ if ( isset( $front_page_obj->ID ) ) {
198
+ update_option( 'page_on_front', $front_page_obj->ID );
199
+ }
200
+ }
201
+
202
+ if ( isset( $args['blog_page'] ) && $args['blog_page'] !== null ) {
203
+ $blog_page_obj = get_page_by_path( $this->cleanup_page_slug( $args['blog_page'], $demo_slug ) );
204
+ if ( isset( $blog_page_obj->ID ) ) {
205
+ update_option( 'page_for_posts', $blog_page_obj->ID );
206
+ }
207
+ }
208
+
209
+ if ( isset( $front_page_obj->ID ) ) {
210
+ $this->logger->log( "Front page set up with id: {$front_page_obj->ID}.", 'success' );
211
+
212
+ return $front_page_obj->ID;
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Set up shop pages options by `post_name`.
218
+ *
219
+ * @param array $pages the shop pages array.
220
+ * @param string $demo_slug the demo slug.
221
+ */
222
+ public function setup_shop_pages( $pages, $demo_slug ) {
223
+ $this->logger->log( 'Setting up shop page.', 'progress' );
224
+ if ( ! class_exists( 'WooCommerce' ) ) {
225
+ $this->logger->log( 'No WooCommerce.', 'success' );
226
+
227
+ return;
228
+ }
229
+ if ( ! is_array( $pages ) ) {
230
+ $this->logger->log( 'No Shop Pages.', 'success' );
231
+
232
+ return;
233
+ }
234
+ foreach ( $pages as $option_id => $slug ) {
235
+ if ( ! empty( $slug ) ) {
236
+ $page_object = get_page_by_path( $this->cleanup_page_slug( $slug, $demo_slug ) );
237
+ if ( isset( $page_object->ID ) ) {
238
+ update_option( $option_id, $page_object->ID );
239
+ }
240
+ }
241
+ }
242
+ $this->logger->log( 'Shop pages set up.', 'success' );
243
+ }
244
+
245
+ /**
246
+ * Maybe bust cache for elementor plugin.
247
+ */
248
+ private function maybe_bust_elementor_cache() {
249
+ if ( ! class_exists( '\Elementor\Plugin' ) ) {
250
+ return;
251
+ }
252
+ if ( null === \Elementor\Plugin::instance()->files_manager ) {
253
+ return;
254
+ }
255
+ \Elementor\Plugin::instance()->files_manager->clear_cache();
256
+ }
257
+
258
+ /**
259
+ * Import file
260
+ *
261
+ * @param string $file_path the file path to import.
262
+ * @param array $req_body the request body to be passed to the alterator.
263
+ * @param string $builder the page builder used.
264
+ *
265
+ * @return WP_Error|true
266
+ */
267
+ public function import_file( $file_path, $req_body = array(), $builder = '' ) {
268
+ if ( empty( $file_path ) || ! file_exists( $file_path ) || ! is_readable( $file_path ) ) {
269
+ return new WP_Error( 'ti__ob_content_err_1', 'No content file' );
270
+ }
271
+
272
+ $alterator = new Importer_Alterator( $req_body );
273
+ $importer = new WP_Import( $builder );
274
+
275
+ return $importer->import( $file_path );
276
+ }
277
+
278
+ /**
279
+ * Load the importer.
280
+ */
281
+ private function load_importer() {
282
+ if ( ! class_exists( '\WP_Importer' ) ) {
283
+ $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php';
284
+ if ( file_exists( $class_wp_importer ) && is_readable( $class_wp_importer ) ) {
285
+ require $class_wp_importer;
286
+ return false;
287
+ }
288
+ return new WP_Error( 'WP_Importer Core class doesn\'t exist.' );
289
+ }
290
+ }
291
+ }
includes/Importers/Helpers/Helper.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Themeisle Onboarding Trait
4
+ *
5
+ * @package templates-patterns-collection
6
+ */
7
+
8
+ namespace TIOB\Importers\Helpers;
9
+
10
+ trait Helper {
11
+ /**
12
+ * A list of allowed mimes.
13
+ *
14
+ * @var array
15
+ */
16
+ protected $extensions = array(
17
+ 'jpg|jpeg|jpe' => 'image/jpeg',
18
+ 'png' => 'image/png',
19
+ 'webp' => 'image/webp',
20
+ 'svg' => 'image/svg+xml',
21
+ );
22
+
23
+ /**
24
+ * Replace demo urls in meta with site urls.
25
+ */
26
+ public function replace_image_urls( $markup ) {
27
+ // Get all slashed and un-slashed urls.
28
+ $old_urls = $this->get_urls_to_replace( $markup );
29
+ if ( ! is_array( $old_urls ) || empty( $old_urls ) ) {
30
+ return $markup;
31
+ }
32
+
33
+ // Create an associative array.
34
+ $urls = array_combine( $old_urls, $old_urls );
35
+ // Unslash values of associative array.
36
+ $urls = array_map( 'wp_unslash', $urls );
37
+ // Remap host and directory path.
38
+ $urls = array_map( array( $this, 'remap_host' ), $urls );
39
+ // Replace image urls in meta.
40
+ $markup = str_replace( array_keys( $urls ), array_values( $urls ), $markup );
41
+
42
+ return $markup;
43
+ }
44
+
45
+ /**
46
+ * Get url replace array.
47
+ *
48
+ * @return array
49
+ */
50
+ private function get_urls_to_replace( $markup ) {
51
+ $regex = '/(?:http(?:s?):)(?:[\/\\\\\\\\|.|\w|\s|-])*\.(?:' . implode( '|', array_keys( $this->extensions ) ) . ')/m';
52
+
53
+ if ( ! is_string( $markup ) ) {
54
+ return array();
55
+ }
56
+
57
+ preg_match_all( $regex, $markup, $urls );
58
+
59
+ $urls = array_map(
60
+ function ( $value ) {
61
+ return rtrim( html_entity_decode( $value ), '\\' );
62
+ },
63
+ $urls[0]
64
+ );
65
+
66
+ $urls = array_unique( $urls );
67
+
68
+ return array_values( $urls );
69
+ }
70
+
71
+ /**
72
+ * Remap URLs host.
73
+ *
74
+ * @param $url
75
+ *
76
+ * @return string
77
+ */
78
+ private function remap_host( $url ) {
79
+ if ( ! strpos( $url, '/uploads/' ) ) {
80
+ return $url;
81
+ }
82
+ $old_url = $url;
83
+ $url_parts = parse_url( $url );
84
+
85
+ if ( ! isset( $url_parts['host'] ) ) {
86
+ return $url;
87
+ }
88
+ $url_parts['path'] = preg_split( '/\//', $url_parts['path'] );
89
+ $url_parts['path'] = array_slice( $url_parts['path'], - 3 );
90
+
91
+ $uploads_dir = wp_get_upload_dir();
92
+ $uploads_url = $uploads_dir['baseurl'];
93
+
94
+ $new_url = esc_url( $uploads_url . '/' . join( '/', $url_parts['path'] ) );
95
+
96
+ return str_replace( $old_url, $new_url, $url );
97
+ }
98
+
99
+ /**
100
+ * Hash the demo slug and prefix the page name with it. Drop words like demo, neve, or the demo slug from page slug.
101
+ *
102
+ * @param string $slug page slug.
103
+ * @param string $demo_slug demo slug.
104
+ *
105
+ * @return string
106
+ */
107
+ public function cleanup_page_slug( $slug, $demo_slug ) {
108
+ $hash = substr( md5( $demo_slug ), 0, 5 );
109
+ $slug = str_replace( $demo_slug, '', $slug );
110
+ $slug = str_replace( 'demo', '', $slug );
111
+ $slug = ltrim( $slug, '-' );
112
+ $slug = $hash . '-' . $slug;
113
+
114
+ return $slug;
115
+ }
116
+ }
includes/Importers/Helpers/Importer_Alterator.php ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Importer alterator.
4
+ *
5
+ * Used to alter import content.
6
+ *
7
+ * @package templates-patterns-collection
8
+ */
9
+
10
+
11
+ namespace TIOB\Importers\Helpers;
12
+ /**
13
+ * Class Importer_Alterator
14
+ */
15
+ class Importer_Alterator {
16
+ use Helper;
17
+
18
+ /**
19
+ * Post map. Holds post type / count.
20
+ *
21
+ * @var array
22
+ */
23
+ private $post_map = array();
24
+
25
+ /**
26
+ * Post types that will be ignored if there are more than 2 already on the site.
27
+ *
28
+ * @var array
29
+ */
30
+ private $filtered_post_types = array(
31
+ 'post',
32
+ 'product',
33
+ );
34
+
35
+ /**
36
+ * Data passed from the async request for individual site item.
37
+ *
38
+ * @var array
39
+ */
40
+ private $site_json_data;
41
+
42
+ /**
43
+ * Importer_Alterator constructor.
44
+ *
45
+ * @param array $site_json_data the sites data passed from content import.
46
+ */
47
+ public function __construct( $site_json_data ) {
48
+ $this->site_json_data = $site_json_data;
49
+ $this->count_posts_by_post_type();
50
+ add_filter( 'wp_import_posts', array( $this, 'skip_shop_pages' ), 10 );
51
+ add_filter( 'wp_import_posts', array( $this, 'skip_posts' ), 10 );
52
+ add_filter( 'wp_import_posts', array( $this, 'drop_slug_and_prefix_pages' ), 10 );
53
+ add_filter( 'wp_import_terms', array( $this, 'skip_terms' ), 10 );
54
+ add_filter( 'wp_insert_post_data', array( $this, 'encode_post_content' ), 10, 2 );
55
+ add_filter( 'wp_import_nav_menu_item_args', array( $this, 'change_nav_menu_item_link' ), 10, 2 );
56
+ add_filter( 'intermediate_image_sizes_advanced', '__return_null' );
57
+ }
58
+
59
+ /**
60
+ * Prefix Front / Blog page slug.
61
+ *
62
+ * @param array $posts the posts to import array.
63
+ *
64
+ * @return array
65
+ */
66
+ public function drop_slug_and_prefix_pages( $posts ) {
67
+ foreach ( $posts as $index => $post ) {
68
+ if ( $post['post_type'] !== 'page' ) {
69
+ continue;
70
+ }
71
+ $posts[ $index ]['post_name'] = $this->cleanup_page_slug( $post['post_name'], $this->site_json_data['demoSlug'] );
72
+ }
73
+
74
+ return $posts;
75
+ }
76
+
77
+ /**
78
+ * Change nav menu items link if needed.
79
+ *
80
+ * @param array $args menu item args.
81
+ * @param string $import_source_url the source url.
82
+ *
83
+ * @return array
84
+ */
85
+ public function change_nav_menu_item_link( $args, $import_source_url ) {
86
+ $args['menu-item-url'] = str_replace( $import_source_url, get_home_url(), $args['menu-item-url'] );
87
+
88
+ return $args;
89
+ }
90
+
91
+ /**
92
+ * Encode post content to UTF8 for possible issues with locales.
93
+ *
94
+ * @param array $data post data
95
+ * @param array $postarr post array
96
+ *
97
+ * @return array
98
+ */
99
+ public function encode_post_content( $data, $postarr ) {
100
+ if ( isset( $this->site_json_data['editor'] ) && $this->site_json_data['editor'] === 'gutenberg' ) {
101
+ return $data;
102
+ }
103
+ $data['post_content'] = utf8_encode( $data['post_content'] );
104
+
105
+ return $data;
106
+ }
107
+
108
+ /**
109
+ * Skip posts if there are more than 2 already.
110
+ *
111
+ * @param array $posts post data.
112
+ *
113
+ * @return array
114
+ */
115
+ public function skip_posts( $posts ) {
116
+ return array_filter(
117
+ $posts,
118
+ function ( $post_data ) {
119
+ if ( ! array_key_exists( $post_data['post_type'], $this->post_map ) ) {
120
+ return true;
121
+ }
122
+ if ( $this->post_map[ $post_data['post_type'] ] <= 2 ) {
123
+ return true;
124
+ }
125
+
126
+ return false;
127
+ }
128
+ );
129
+ }
130
+
131
+ /**
132
+ * Skip shop pages if no WooCommerce.
133
+ *
134
+ * @param array $posts posts data.
135
+ *
136
+ * @return array
137
+ */
138
+ public function skip_shop_pages( $posts ) {
139
+ if ( ! isset( $this->site_json_data['shopPages'] ) || $this->site_json_data['shopPages'] === null || ! is_array( $this->site_json_data['shopPages'] ) ) {
140
+ return $posts;
141
+ }
142
+
143
+ if ( class_exists( 'WooCommerce' ) ) {
144
+ return $posts;
145
+ }
146
+
147
+ return array_filter(
148
+ $posts,
149
+ function ( $post_data ) {
150
+ if ( $post_data['post_type'] === 'product' ) {
151
+ return false;
152
+ }
153
+ if (
154
+ $post_data['post_type'] === 'page' &&
155
+ in_array( $post_data['post_name'], $this->site_json_data['shopPages'] )
156
+ ) {
157
+ return false;
158
+ }
159
+
160
+ return true;
161
+ }
162
+ );
163
+ }
164
+
165
+ /**
166
+ * Skips terms for post types that were skipped.
167
+ *
168
+ * @param array $terms terms data.
169
+ *
170
+ * @return array
171
+ */
172
+ public function skip_terms( $terms ) {
173
+ foreach ( $this->filtered_post_types as $post_type ) {
174
+ if ( ! $this->post_map[ $post_type ] <= 2 ) {
175
+ continue;
176
+ }
177
+
178
+ $terms = array_filter(
179
+ $terms,
180
+ function ( $term ) use ( $post_type ) {
181
+ return $this->is_taxonomy_assigned_to_post_type( $post_type, $term['term_taxonomy'] );
182
+ }
183
+ );
184
+ }
185
+
186
+ return $terms;
187
+ }
188
+
189
+ /**
190
+ * Checks if taxonomy is assigned to post type.
191
+ *
192
+ * @param string $post_type post type slug.
193
+ * @param string $taxonomy taxonomy slug.
194
+ *
195
+ * @return bool
196
+ */
197
+ private function is_taxonomy_assigned_to_post_type( $post_type, $taxonomy ) {
198
+ $taxonomies = get_object_taxonomies( $post_type );
199
+
200
+ return in_array( $taxonomy, $taxonomies );
201
+ }
202
+
203
+ /**
204
+ * Count excluded post types.
205
+ */
206
+ private function count_posts_by_post_type() {
207
+ foreach ( $this->filtered_post_types as $post_type ) {
208
+ $args = array(
209
+ 'post_type' => $post_type,
210
+ );
211
+ $the_query = new \WP_Query( $args );
212
+
213
+ $this->post_map[ $post_type ] = absint( $the_query->found_posts );
214
+ }
215
+ }
216
+ }
includes/Importers/Helpers/Quiet_Skin.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The plugin upgrader quiet skin.
4
+ *
5
+ * Used to silence installation progress for plugins installs.
6
+ *
7
+ * @package templates-patterns-collection
8
+ */
9
+
10
+ namespace TIOB\Importers\Helpers;
11
+
12
+ use WP_Upgrader_Skin;
13
+
14
+ /**
15
+ * Class Quiet_Skin
16
+ *
17
+ * Silences plugin install and activate.
18
+ */
19
+ class Quiet_Skin extends WP_Upgrader_Skin {
20
+ /**
21
+ * Done Header.
22
+ *
23
+ * @var bool
24
+ */
25
+ public $done_header = true;
26
+
27
+ /**
28
+ * Done Footer.
29
+ *
30
+ * @var bool
31
+ */
32
+ public $done_footer = true;
33
+
34
+ /**
35
+ * Feedback function overwrite.
36
+ *
37
+ * @param string $string feedback string.
38
+ * @param mixed ...$args feedback args.
39
+ */
40
+ public function feedback( $string, ...$args ) {
41
+ // Keep install quiet.
42
+ }
43
+
44
+ /**
45
+ * Quiet after.
46
+ */
47
+ public function after() {
48
+ // Quiet after
49
+ }
50
+
51
+ /**
52
+ * Quiet before.
53
+ */
54
+ public function before() {
55
+ // Quiet before.
56
+ }
57
+
58
+
59
+ }
includes/Importers/Helpers/Quiet_Skin_Legacy.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The plugin upgrader quiet skin.
4
+ *
5
+ * Used to silence installation progress for plugins installs.
6
+ *
7
+ * @package templates-patterns-collection
8
+ */
9
+
10
+ namespace TIOB\Importers\Helpers;
11
+
12
+ use WP_Upgrader_Skin;
13
+
14
+ /**
15
+ * Class Quiet_Skin_Legacy
16
+ *
17
+ * Silences plugin install and activate.
18
+ */
19
+ class Quiet_Skin_Legacy extends WP_Upgrader_Skin {
20
+ /**
21
+ * Done Header.
22
+ *
23
+ * @var bool
24
+ */
25
+ public $done_header = true;
26
+
27
+ /**
28
+ * Done Footer.
29
+ *
30
+ * @var bool
31
+ */
32
+ public $done_footer = true;
33
+
34
+ /**
35
+ * Feedback function overwrite.
36
+ *
37
+ * @param string $string feedback string.
38
+ */
39
+ public function feedback( $string ) {
40
+ // Keep install quiet.
41
+ }
42
+
43
+ /**
44
+ * Quiet after.
45
+ */
46
+ public function after() {
47
+ // Quiet after
48
+ }
49
+
50
+ /**
51
+ * Quiet before.
52
+ */
53
+ public function before() {
54
+ // Quiet before.
55
+ }
56
+
57
+
58
+ }
includes/Importers/Plugin_Importer.php ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin Importer.
4
+ *
5
+ * @package templates-patterns-collection
6
+ */
7
+
8
+ namespace TIOB\Importers;
9
+
10
+ use Plugin_Upgrader;
11
+ use TIOB\Importers\Helpers\Quiet_Skin;
12
+ use TIOB\Importers\Helpers\Quiet_Skin_Legacy;
13
+ use TIOB\Logger;
14
+ use WP_REST_Request;
15
+ use WP_REST_Response;
16
+
17
+ /**
18
+ * Class Plugin_Importer
19
+ */
20
+ class Plugin_Importer {
21
+
22
+ /**
23
+ * Log
24
+ *
25
+ * @var string
26
+ */
27
+ public $log = '';
28
+
29
+ /**
30
+ * Logger Instance.
31
+ *
32
+ * @var Logger
33
+ */
34
+ private $logger;
35
+
36
+ /**
37
+ * Exceptions entry files mapping.
38
+ *
39
+ * slug => entry-file
40
+ *
41
+ * @var array
42
+ */
43
+ private $exception_mapping = array(
44
+ 'advanced-css-editor' => 'css-editor.php',
45
+ 'contact-form-7' => 'wp-contact-form-7.php',
46
+ 'wpforms-lite' => 'wpforms.php',
47
+ 'beaver-builder-lite-version' => 'fl-builder.php',
48
+ 'wpzoom-addons-for-beaver-builder' => 'wpzoom-bb-addon-pack.php',
49
+ );
50
+
51
+ public function __construct() {
52
+ $this->logger = Logger::get_instance();
53
+ }
54
+
55
+ /**
56
+ * Install Plugins.
57
+ *
58
+ * @param WP_REST_Request $request contains the plugins that should be installed.
59
+ *
60
+ * @return WP_REST_Response
61
+ */
62
+ public function install_plugins( WP_REST_Request $request ) {
63
+ if ( ! current_user_can( 'install_plugins' ) ) {
64
+ $this->logger->log( 'Current user cannot install plugins' );
65
+
66
+ return new WP_REST_Response(
67
+ array(
68
+ 'success' => false,
69
+ 'log' => $this->log,
70
+ 'data' => 'ti__ob_perm_err_1',
71
+ )
72
+ );
73
+ }
74
+
75
+ do_action( 'themeisle_ob_before_plugins_install' );
76
+
77
+ $plugins = $request->get_json_params();
78
+ if ( empty( $plugins ) || ! is_array( $plugins ) ) {
79
+ return new WP_REST_Response(
80
+ array(
81
+ 'success' => true,
82
+ 'log' => $this->log,
83
+ )
84
+ );
85
+ }
86
+
87
+ foreach ( $plugins as $slug => $state ) {
88
+ if ( ! $state || empty( $state ) ) {
89
+ unset( $plugins[ $slug ] );
90
+ }
91
+ }
92
+
93
+ $this->run_plugins_install( $plugins );
94
+
95
+ return new WP_REST_Response(
96
+ array(
97
+ 'success' => true,
98
+ 'log' => $this->log,
99
+ )
100
+ );
101
+ }
102
+
103
+ /**
104
+ * Install and activate plugins.
105
+ *
106
+ * @param array $plugins_array plugins formated slug => true.
107
+ */
108
+ public function run_plugins_install( $plugins_array ) {
109
+ $active_plugins = get_option( 'active_plugins' );
110
+
111
+ foreach ( $plugins_array as $plugin_slug => $true ) {
112
+ if ( in_array( $plugin_slug, $active_plugins ) ) {
113
+ continue;
114
+ }
115
+ $this->logger->log( "Installing {$plugin_slug}.", 'progress' );
116
+ $this->install_single_plugin( $plugin_slug );
117
+ $this->logger->log( "Activating {$plugin_slug}.", 'progress' );
118
+ $this->activate_single_plugin( $plugin_slug );
119
+ }
120
+
121
+ $this->remove_possible_redirects();
122
+ $this->logger->log( 'Installed and activated plugins.', 'success' );
123
+
124
+ do_action( 'themeisle_ob_after_plugins_install' );
125
+
126
+ update_option( 'themeisle_ob_plugins_installed', 'yes' );
127
+ }
128
+
129
+ /**
130
+ * Remove admin redirects.
131
+ */
132
+ private function remove_possible_redirects() {
133
+ delete_transient( '_wc_activation_redirect' );
134
+ delete_transient( 'wpforms_activation_redirect' );
135
+ update_option( 'themeisle_blocks_settings_redirect', false );
136
+ }
137
+
138
+ /**
139
+ * Install a single plugin
140
+ *
141
+ * @param string $plugin_slug plugin slug.
142
+ */
143
+ private function install_single_plugin( $plugin_slug ) {
144
+ $plugin_dir = WP_PLUGIN_DIR . '/' . $plugin_slug;
145
+
146
+ if ( is_dir( $plugin_dir ) ) {
147
+ return;
148
+ }
149
+
150
+ do_action( 'themeisle_ob_before_single_plugin_install', $plugin_slug );
151
+
152
+ require_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
153
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
154
+ require_once( ABSPATH . 'wp-admin/includes/misc.php' );
155
+ require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
156
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
157
+
158
+ $api = plugins_api(
159
+ 'plugin_information',
160
+ array(
161
+ 'slug' => $plugin_slug,
162
+ 'fields' => array(
163
+ 'short_description' => false,
164
+ 'sections' => false,
165
+ 'requires' => false,
166
+ 'rating' => false,
167
+ 'ratings' => false,
168
+ 'downloaded' => false,
169
+ 'last_updated' => false,
170
+ 'added' => false,
171
+ 'tags' => false,
172
+ 'compatibility' => false,
173
+ 'homepage' => false,
174
+ 'donate_link' => false,
175
+ ),
176
+ )
177
+ );
178
+
179
+ if ( version_compare( PHP_VERSION, '5.6' ) === -1 ) {
180
+ $skin = new Quiet_Skin_Legacy(
181
+ array(
182
+ 'api' => $api,
183
+ )
184
+ );
185
+ } else {
186
+ $skin = new Quiet_Skin(
187
+ array(
188
+ 'api' => $api,
189
+ )
190
+ );
191
+ }
192
+ $upgrader = new Plugin_Upgrader( $skin );
193
+ $install = $upgrader->install( $api->download_link );
194
+ if ( $install !== true ) {
195
+ $this->log .= 'Error: Install process failed (' . ucwords( $plugin_slug ) . ').' . "\n";
196
+
197
+ return;
198
+ }
199
+ $this->log .= 'Installed "' . ucwords( $plugin_slug ) . '"' . "\n ";
200
+
201
+ do_action( 'themeisle_ob_after_single_plugin_install', $plugin_slug );
202
+ }
203
+
204
+ /**
205
+ * Get full plugin path.
206
+ *
207
+ * @param string $slug The plugin slug.
208
+ *
209
+ * @return string
210
+ */
211
+ private function get_plugin_path( $slug ) {
212
+ $plugin_dir = WP_PLUGIN_DIR . '/' . $slug;
213
+
214
+ if ( array_key_exists( $slug, $this->exception_mapping ) ) {
215
+ return trailingslashit( $plugin_dir ) . $this->exception_mapping[ $slug ];
216
+ }
217
+
218
+ $plugin_path = $plugin_dir . '/' . $slug . '.php';
219
+
220
+ if ( ! file_exists( $plugin_path ) ) {
221
+ $plugin_path = $plugin_dir . '/' . 'index.php';
222
+ }
223
+
224
+ return $plugin_path;
225
+ }
226
+
227
+ /**
228
+ * Get plugin entry file.
229
+ *
230
+ * @param string $slug The plugin slug.
231
+ *
232
+ * @return string
233
+ */
234
+ private function get_plugin_entry( $slug ) {
235
+ if ( $slug === 'advanced-css-editor' ) {
236
+ return $slug . '/css-editor.php';
237
+ }
238
+
239
+ if ( $slug === 'contact-form-7' ) {
240
+ return $slug . '/wp-contact-form-7.php';
241
+ }
242
+
243
+ if ( $slug === 'wpforms-lite' ) {
244
+ return $slug . '/wpforms.php';
245
+ }
246
+
247
+ $plugins_dir = WP_PLUGIN_DIR . '/';
248
+ $entry = $slug . '/' . $slug . '.php';
249
+ if ( ! file_exists( $plugins_dir . $entry ) ) {
250
+ $entry = $slug . '/index.php';
251
+ }
252
+
253
+ return $entry;
254
+ }
255
+
256
+ /**
257
+ * Activate a single plugin
258
+ *
259
+ * @param string $plugin_slug plugin slug.
260
+ */
261
+ private function activate_single_plugin( $plugin_slug ) {
262
+ $plugin_dir = WP_PLUGIN_DIR . '/' . $plugin_slug;
263
+
264
+ $plugin_path = $this->get_plugin_path( $plugin_slug );
265
+ $plugin_entry = $this->get_plugin_entry( $plugin_slug );
266
+
267
+ if ( ! file_exists( $plugin_path ) ) {
268
+ $this->log .= 'No plugin with the slug "' . $plugin_slug . '" under that directory.' . "\n";
269
+
270
+ return;
271
+ }
272
+
273
+ do_action( 'themeisle_ob_before_single_plugin_activation', $plugin_slug );
274
+
275
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
276
+
277
+ if ( is_plugin_active( $plugin_entry ) ) {
278
+ $this->log .= '"' . ucwords( $plugin_slug ) . '" already active.' . "\n";
279
+
280
+ return;
281
+ }
282
+ $this->maybe_provide_activation_help( $plugin_slug, $plugin_dir );
283
+
284
+ activate_plugin( $plugin_path );
285
+ $this->log .= 'Activated ' . ucwords( $plugin_slug ) . '.' . "\n";
286
+
287
+ do_action( 'themeisle_ob_after_single_plugin_activation', $plugin_slug );
288
+ }
289
+
290
+ /**
291
+ * Take care of plugins that need special conditions on activation.
292
+ *
293
+ * @param string $slug plugin slug.
294
+ * @param string $path plugin path.
295
+ */
296
+ private function maybe_provide_activation_help( $slug, $path ) {
297
+ if ( $slug === 'woocommerce' ) {
298
+ require_once( $path . '/includes/admin/wc-admin-functions.php' );
299
+ }
300
+ }
301
+ }
includes/Importers/Theme_Mods_Importer.php ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Theme Mods Importer.
4
+ *
5
+ * @package templates-patterns-collection
6
+ */
7
+
8
+ namespace TIOB\Importers;
9
+
10
+ use TIOB\Importers\Helpers\Helper;
11
+ use WP_REST_Request;
12
+ use WP_REST_Response;
13
+
14
+ /**
15
+ * Class Theme_Mods_Importer
16
+ */
17
+ class Theme_Mods_Importer {
18
+ use Helper;
19
+
20
+ /**
21
+ * Log
22
+ *
23
+ * @var
24
+ */
25
+ private $log = '';
26
+
27
+ /**
28
+ * Source URL.
29
+ *
30
+ * @var string
31
+ */
32
+ private $source_url = '';
33
+
34
+ /**
35
+ * Theme mods array.
36
+ *
37
+ * @var array
38
+ */
39
+ private $theme_mods = array();
40
+
41
+ /**
42
+ * Options array.
43
+ *
44
+ * @var array
45
+ */
46
+ private $options = array();
47
+
48
+ /**
49
+ * Import theme mods.
50
+ *
51
+ * @param WP_REST_Request $request the async request.
52
+ *
53
+ * @return WP_REST_Response
54
+ */
55
+ public function import_theme_mods( WP_REST_Request $request ) {
56
+ if ( ! current_user_can( 'customize' ) ) {
57
+ return new WP_REST_Response(
58
+ array(
59
+ 'data' => 'ti__ob_permission_err_2',
60
+ 'success' => false,
61
+ )
62
+ );
63
+ }
64
+
65
+ do_action( 'themeisle_ob_before_customizer_import' );
66
+
67
+ $data = $request->get_json_params();
68
+
69
+ if ( ! isset( $data['source_url'] ) || empty( $data['source_url'] ) ) {
70
+
71
+ return new WP_REST_Response(
72
+ array(
73
+ 'data' => 'ti__ob_theme_mods_err_1',
74
+ 'success' => false,
75
+ )
76
+ );
77
+ }
78
+
79
+ if ( ! isset( $data['theme_mods'] ) || empty( $data['theme_mods'] ) ) {
80
+ return new WP_REST_Response(
81
+ array(
82
+ 'data' => 'ti__ob_theme_mods_err_2',
83
+ 'success' => false,
84
+ )
85
+ );
86
+ }
87
+ $this->source_url = $data['source_url'];
88
+ $this->theme_mods = $data['theme_mods'];
89
+ array_walk( $this->theme_mods, array( $this, 'change_theme_mods_root_url' ) );
90
+
91
+ foreach ( $this->theme_mods as $mod => $value ) {
92
+ if ( $mod === '__ti_import_menus_location' ) {
93
+ continue;
94
+ }
95
+ if ( $value === 'true' ) {
96
+ $value = true;
97
+ }
98
+
99
+ if ( $value === 'false' ) {
100
+ $value = false;
101
+ }
102
+ set_theme_mod( $mod, $value );
103
+ }
104
+
105
+ $this->options = isset( $data['wp_options'] ) ? $data['wp_options'] : array();
106
+ foreach ( $this->options as $key => $value ) {
107
+ if ( is_array( $value ) ) {
108
+ array_walk_recursive(
109
+ $value,
110
+ function ( &$item ) {
111
+ if ( $item == 'true' ) {
112
+ $item = true;
113
+ } elseif ( $item == 'false' ) {
114
+ $item = false;
115
+ } elseif ( is_numeric( $item ) ) {
116
+ $item = intval( $item );
117
+ }
118
+ }
119
+ );
120
+ }
121
+ update_option( $key, $value );
122
+ }
123
+
124
+ // Set nav menu locations.
125
+ if ( isset( $this->theme_mods['__ti_import_menus_location'] ) ) {
126
+ $menus = $this->theme_mods['__ti_import_menus_location'];
127
+ $this->setup_nav_menus( $menus );
128
+ }
129
+
130
+ do_action( 'themeisle_ob_after_customizer_import' );
131
+
132
+ return new WP_REST_Response(
133
+ array(
134
+ 'data' => 'success',
135
+ 'success' => true,
136
+ 'log' => $this->log,
137
+ )
138
+ );
139
+ }
140
+
141
+ /**
142
+ * Set up the `nav_menu_locations` theme mod.
143
+ *
144
+ * @param array $menus represents the menu data as as [location => slug] retrieved from the API.
145
+ */
146
+ public function setup_nav_menus( $menus ) {
147
+ do_action( 'themeisle_ob_before_nav_menus_setup' );
148
+
149
+ if ( empty( $menus ) || ! is_array( $menus ) ) {
150
+ return;
151
+ }
152
+
153
+ $setup_menus = array();
154
+ foreach ( $menus as $location => $menu_slug ) {
155
+
156
+ $menu_object = wp_get_nav_menu_object( $menu_slug );
157
+ $term_id = $menu_object->term_id;
158
+ $setup_menus[ $location ] = $term_id;
159
+ }
160
+ if ( empty( $setup_menus ) ) {
161
+ $this->log .= 'No menus to set up locations for.' . "\n";
162
+
163
+ return;
164
+ }
165
+ set_theme_mod( 'nav_menu_locations', $setup_menus );
166
+
167
+ $this->log .= 'Menus are set up.' . "\n";
168
+
169
+ do_action( 'themeisle_ob_after_nav_menus_setup' );
170
+ }
171
+
172
+ /**
173
+ * Change the theme mods root url.
174
+ *
175
+ * @param string $item theme mod.
176
+ *
177
+ * @return void
178
+ */
179
+ private function change_theme_mods_root_url( &$item ) {
180
+ do_action( 'themeisle_ob_before_change_theme_mods_root_url' );
181
+ $item = $this->replace_image_urls( $item );
182
+ do_action( 'themeisle_ob_after_change_theme_mods_root_url' );
183
+ }
184
+
185
+ }
includes/Importers/WP/Beaver_Data_Fix.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace TIOB\Importers\WP;
3
+
4
+ /**
5
+ * Brought in from Beaver Builder Lite
6
+ *
7
+ * Portions borrowed from https://github.com/Blogestudio/Fix-Serialization/blob/master/fix-serialization.php
8
+ *
9
+ * Attempts to fix broken serialized data.
10
+ *
11
+ * @since 1.8
12
+ */
13
+ final class Beaver_Data_Fix {
14
+
15
+ /**
16
+ * @since 1.8
17
+ * @return string
18
+ */
19
+ static public function run( $data ) {
20
+ // return if empty
21
+ if ( empty( $data ) ) {
22
+ return $data;
23
+ }
24
+
25
+ $data = maybe_unserialize( $data );
26
+
27
+ // return if maybe_unserialize() returns an object or array, this is good.
28
+ if ( is_object( $data ) || is_array( $data ) ) {
29
+ return $data;
30
+ }
31
+
32
+ return preg_replace_callback( '!s:(\d+):([\\\\]?"[\\\\]?"|[\\\\]?"((.*?)[^\\\\])[\\\\]?");!', 'TIOB\Importers\WP\Beaver_Data_Fix::regex_callback', $data );
33
+ }
34
+
35
+ /**
36
+ * @since 1.8
37
+ * @return string
38
+ */
39
+ static public function regex_callback( $matches ) {
40
+ if ( ! isset( $matches[3] ) ) {
41
+ return $matches[0];
42
+ }
43
+
44
+ return 's:' . strlen( self::unescape_mysql( $matches[3] ) ) . ':"' . self::unescape_quotes( $matches[3] ) . '";';
45
+ }
46
+
47
+ /**
48
+ * Unescape to avoid dump-text issues.
49
+ *
50
+ * @since 1.8
51
+ * @access private
52
+ * @return string
53
+ */
54
+ static private function unescape_mysql( $value ) {
55
+ return str_replace(
56
+ array( '\\\\', "\\0", "\\n", "\\r", '\Z', "\'", '\"' ),
57
+ array( '\\', "\0", "\n", "\r", "\x1a", "'", '"' ),
58
+ $value
59
+ );
60
+ }
61
+
62
+ /**
63
+ * Fix strange behaviour if you have escaped quotes in your replacement.
64
+ *
65
+ * @since 1.8
66
+ * @access private
67
+ * @return string
68
+ */
69
+ static private function unescape_quotes( $value ) {
70
+ return str_replace( '\"', '"', $value );
71
+ }
72
+ }
includes/Importers/WP/Beaver_ParserXML.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TIOB\Importers\WP;
4
+
5
+ /**
6
+ * Class Beaver_ParserXML
7
+ *
8
+ * Brought in from Beaver Builder Lite.
9
+ *
10
+ * Beaver XML Parser
11
+ */
12
+ class Beaver_ParserXML extends WXR_Parser_XML {
13
+
14
+ function tag_close( $parser, $tag ) {
15
+ switch ( $tag ) {
16
+ case 'wp:comment':
17
+ unset( $this->sub_data['key'], $this->sub_data['value'] ); // remove meta sub_data
18
+ if ( ! empty( $this->sub_data ) ) {
19
+ $this->data['comments'][] = $this->sub_data;
20
+ }
21
+ $this->sub_data = false;
22
+ break;
23
+ case 'wp:commentmeta':
24
+ $this->sub_data['commentmeta'][] = array(
25
+ 'key' => $this->sub_data['key'],
26
+ 'value' => $this->sub_data['value'],
27
+ );
28
+ break;
29
+ case 'category':
30
+ if ( ! empty( $this->sub_data ) ) {
31
+ $this->sub_data['name'] = $this->cdata;
32
+ $this->data['terms'][] = $this->sub_data;
33
+ }
34
+ $this->sub_data = false;
35
+ break;
36
+ case 'wp:postmeta':
37
+ if ( ! empty( $this->sub_data ) ) {
38
+ if ( stristr( $this->sub_data['key'], '_fl_builder_' ) ) {
39
+ $this->sub_data['value'] = Beaver_Data_Fix::run( serialize( $this->sub_data['value'] ) );
40
+ }
41
+ $this->data['postmeta'][] = $this->sub_data;
42
+ }
43
+ $this->sub_data = false;
44
+ break;
45
+ case 'item':
46
+ $this->posts[] = $this->data;
47
+ $this->data = false;
48
+ break;
49
+ case 'wp:category':
50
+ case 'wp:tag':
51
+ case 'wp:term':
52
+ $n = substr( $tag, 3 );
53
+ array_push( $this->$n, $this->data );
54
+ $this->data = false;
55
+ break;
56
+ case 'wp:author':
57
+ if ( ! empty( $this->data['author_login'] ) ) {
58
+ $this->authors[ $this->data['author_login'] ] = $this->data;
59
+ }
60
+ $this->data = false;
61
+ break;
62
+ case 'wp:base_site_url':
63
+ $this->base_url = $this->cdata;
64
+ break;
65
+ case 'wp:base_blog_url':
66
+ $this->base_blog_url = $this->cdata;
67
+ break;
68
+ case 'wp:wxr_version':
69
+ $this->wxr_version = $this->cdata;
70
+ break;
71
+ default:
72
+ if ( $this->in_sub_tag ) {
73
+ $this->sub_data[ $this->in_sub_tag ] = ! empty( $this->cdata ) ? $this->cdata : '';
74
+ $this->in_sub_tag = false;
75
+ } elseif ( $this->in_tag ) {
76
+ $this->data[ $this->in_tag ] = ! empty( $this->cdata ) ? $this->cdata : '';
77
+ $this->in_tag = false;
78
+ }
79
+ }
80
+ $this->cdata = false;
81
+ }
82
+ }
includes/Importers/WP/Elementor_Meta_Handler.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Elementor Meta import handler.
4
+ *
5
+ * This is needed because by default, the importer breaks our JSON meta.
6
+ *
7
+ * @package templates-patterns-collection
8
+ */
9
+
10
+ namespace TIOB\Importers\WP;
11
+
12
+ use TIOB\Importers\Helpers\Helper;
13
+
14
+ /**
15
+ * Class Elementor_Meta_Handler
16
+ *
17
+ * @package templates-patterns-collection
18
+ */
19
+ class Elementor_Meta_Handler {
20
+ use Helper;
21
+
22
+ /**
23
+ * Elementor meta key.
24
+ *
25
+ * @var string
26
+ */
27
+ private $meta_key = '_elementor_data';
28
+
29
+ /**
30
+ * Meta value.
31
+ *
32
+ * @var null
33
+ */
34
+ private $value = null;
35
+
36
+ /**
37
+ * Imported site url.
38
+ *
39
+ * @var null
40
+ */
41
+ private $import_url = null;
42
+
43
+ /**
44
+ * Elementor_Meta_Handler constructor.
45
+ *
46
+ * @param string $unfiltered_value the unfiltered meta value.
47
+ * @param string $site_url the site url.
48
+ */
49
+ public function __construct( $unfiltered_value, $site_url ) {
50
+ $this->value = $unfiltered_value;
51
+ $this->import_url = $site_url;
52
+ }
53
+
54
+ /**
55
+ * Filter the meta to allow escaped JSON values.
56
+ */
57
+ public function filter_meta() {
58
+ add_filter( 'sanitize_post_meta_' . $this->meta_key, array( $this, 'allow_escaped_json_meta' ), 10, 3 );
59
+ }
60
+
61
+ /**
62
+ * Allow JSON escaping.
63
+ *
64
+ * @param string $val meta value.
65
+ * @param string $key meta key.
66
+ * @param string $type meta type.
67
+ *
68
+ * @return array|string
69
+ */
70
+ public function allow_escaped_json_meta( $val, $key, $type ) {
71
+ if ( empty( $this->value ) ) {
72
+ return $val;
73
+ }
74
+
75
+ $this->value = $this->replace_image_urls( $this->value );
76
+ $this->replace_link_urls();
77
+
78
+ return $this->value;
79
+ }
80
+
81
+ /**
82
+ * Replace link urls.
83
+ *
84
+ * @return void
85
+ */
86
+ private function replace_link_urls() {
87
+ $decoded_meta = json_decode( $this->value, true );
88
+ if ( ! is_array( $decoded_meta ) ) {
89
+ return;
90
+ }
91
+
92
+ $site_url = get_site_url();
93
+ $url_parts = parse_url( $site_url );
94
+
95
+ array_walk_recursive(
96
+ $decoded_meta,
97
+ function ( &$value, $key ) use ( $site_url, $url_parts ) {
98
+ if ( filter_var( $value, FILTER_VALIDATE_URL ) === false ) {
99
+ return;
100
+ }
101
+
102
+ $url = parse_url( $value );
103
+
104
+ if ( ! isset( $url['host'] ) || ! isset( $url_parts['host'] ) ) {
105
+ return;
106
+ }
107
+
108
+ if ( $url['host'] !== $url_parts['host'] ) {
109
+ $value = str_replace( $this->import_url, $site_url, $value );
110
+ }
111
+ }
112
+ );
113
+
114
+ $this->value = json_encode( $decoded_meta );
115
+ }
116
+ }
includes/Importers/WP/WP_Import.php ADDED
@@ -0,0 +1,906 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WordPress WXR Importer.
4
+ */
5
+
6
+ namespace TIOB\Importers\WP;
7
+
8
+ use TIOB\Importers\Helpers\Helper;
9
+ use TIOB\Logger;
10
+ use WP_Error;
11
+ use WP_Importer;
12
+
13
+ /**
14
+ * WordPress Importer class for managing the import process of a WXR file
15
+ *
16
+ * @package templates-patterns-collection
17
+ */
18
+ class WP_Import extends WP_Importer {
19
+ use Helper;
20
+ /**
21
+ * @var Logger
22
+ */
23
+ private $logger;
24
+
25
+ public $max_wxr_version = 1.2; // max. supported WXR version
26
+ public $id; // WXR attachment ID
27
+ // information to import from WXR file
28
+ public $version;
29
+ public $posts = array();
30
+ public $terms = array();
31
+ public $categories = array();
32
+ public $tags = array();
33
+ public $base_url = '';
34
+ public $base_blog_url = '';
35
+ // mappings from old information to new
36
+ public $processed_posts = array();
37
+ public $processed_terms = array();
38
+ public $post_orphans = array();
39
+ public $processed_menu_items = array();
40
+ public $menu_item_orphans = array();
41
+ public $missing_menu_items = array();
42
+ public $fetch_attachments = true;
43
+ public $url_remap = array();
44
+ public $featured_images = array();
45
+ public $page_builder = null;
46
+
47
+ /**
48
+ * WP_Import constructor.
49
+ *
50
+ * @param string $page_builder the page builder used.
51
+ */
52
+ public function __construct( $page_builder = '' ) {
53
+ $this->page_builder = $page_builder;
54
+ require_once ABSPATH . 'wp-admin/includes/import.php';
55
+ require_once ABSPATH . 'wp-admin/includes/post.php';
56
+ require_once ABSPATH . 'wp-admin/includes/taxonomy.php';
57
+ }
58
+
59
+
60
+ /**
61
+ * The main controller for the actual import stage.
62
+ *
63
+ * @param string $file Path to the WXR file for importing
64
+ */
65
+ function import( $file ) {
66
+ $this->set_logger();
67
+ add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
68
+ add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
69
+ $this->import_start( $file );
70
+ wp_suspend_cache_invalidation( true );
71
+ $this->process_categories();
72
+ $this->process_tags();
73
+ $this->process_terms();
74
+ $this->process_posts();
75
+ wp_suspend_cache_invalidation( false );
76
+ // update incorrect/missing information in the DB
77
+ $this->backfill_parents();
78
+ $this->backfill_attachment_urls();
79
+ $this->remap_featured_images();
80
+ $this->import_end();
81
+ }
82
+
83
+ /**
84
+ * Logger initialized.
85
+ */
86
+ private function set_logger() {
87
+ $this->logger = Logger::get_instance();
88
+ }
89
+
90
+ /**
91
+ * Parses the WXR file and prepares us for the task of processing parsed data
92
+ *
93
+ * @param string $file Path to the WXR file for importing
94
+ */
95
+ private function import_start( $file ) {
96
+ $this->logger->log( 'Import started.', 'success' );
97
+ if ( ! is_file( $file ) ) {
98
+ $this->logger->log( 'No file to import.' );
99
+ die();
100
+ }
101
+ $import_data = $this->parse( $file );
102
+ if ( is_wp_error( $import_data ) ) {
103
+ $this->logger->log( 'Error parsing WXR file.' );
104
+ die();
105
+ }
106
+ $this->version = $import_data['version'];
107
+ $this->posts = $import_data['posts'];
108
+ $this->terms = $import_data['terms'];
109
+ $this->categories = $import_data['categories'];
110
+ $this->tags = $import_data['tags'];
111
+ $this->base_url = esc_url( $import_data['base_url'] );
112
+ $this->base_blog_url = esc_url( $import_data['base_blog_url'] );
113
+ wp_defer_term_counting( true );
114
+ wp_defer_comment_counting( true );
115
+ do_action( 'import_start' );
116
+ }
117
+
118
+ /**
119
+ * Performs post-import cleanup of files and the cache
120
+ */
121
+ private function import_end() {
122
+ $this->logger->log( "Cleaning up import with id {$this->id}...", 'progress' );
123
+ wp_import_cleanup( $this->id );
124
+ $this->logger->log( 'Done cleanup. Flushing cache...', 'progress' );
125
+ wp_cache_flush();
126
+ $this->logger->log( 'Flushed cache. Removing temporary data..', 'progress' );
127
+ foreach ( get_taxonomies() as $tax ) {
128
+ delete_option( "{$tax}_children" );
129
+ _get_term_hierarchy( $tax );
130
+ }
131
+ wp_defer_term_counting( false );
132
+ wp_defer_comment_counting( false );
133
+ $this->logger->log( 'Done importing', 'success' );
134
+ do_action( 'import_end' );
135
+ }
136
+
137
+ /**
138
+ * Create new categories based on import information
139
+ *
140
+ * Doesn't create a new category if its slug already exists
141
+ */
142
+ private function process_categories() {
143
+ $this->logger->log( 'Processing categories...', 'progress' );
144
+ $this->categories = apply_filters( 'wp_import_categories', $this->categories );
145
+ if ( empty( $this->categories ) ) {
146
+ $this->logger->log( 'No categories to process.', 'warning' );
147
+
148
+ return;
149
+ }
150
+ foreach ( $this->categories as $cat ) {
151
+ // if the category already exists leave it alone
152
+ $term_id = term_exists( $cat['category_nicename'], 'category' );
153
+ if ( $term_id ) {
154
+ if ( is_array( $term_id ) ) {
155
+ $term_id = $term_id['term_id'];
156
+ }
157
+ if ( isset( $cat['term_id'] ) ) {
158
+ $this->processed_terms[ intval( $cat['term_id'] ) ] = (int) $term_id;
159
+ }
160
+ continue;
161
+ }
162
+ $category_parent = empty( $cat['category_parent'] ) ? 0 : category_exists( $cat['category_parent'] );
163
+ $category_description = isset( $cat['category_description'] ) ? $cat['category_description'] : '';
164
+ $catarr = array(
165
+ 'category_nicename' => $cat['category_nicename'],
166
+ 'category_parent' => $category_parent,
167
+ 'cat_name' => $cat['cat_name'],
168
+ 'category_description' => $category_description,
169
+ );
170
+ $catarr = wp_slash( $catarr );
171
+ $id = wp_insert_category( $catarr );
172
+ if ( ! is_wp_error( $id ) ) {
173
+ if ( isset( $cat['term_id'] ) ) {
174
+ $this->processed_terms[ intval( $cat['term_id'] ) ] = $id;
175
+ }
176
+ } else {
177
+ $this->logger->log( $id->get_error_message() );
178
+ continue;
179
+ }
180
+ $this->process_termmeta( $cat, $id['term_id'] );
181
+ }
182
+ unset( $this->categories );
183
+ $this->logger->log( 'Processed categories.', 'success' );
184
+ }
185
+
186
+ /**
187
+ * Create new post tags based on import information
188
+ *
189
+ * Doesn't create a tag if its slug already exists
190
+ */
191
+ private function process_tags() {
192
+ $this->logger->log( 'Processing tags...', 'progress' );
193
+ $this->tags = apply_filters( 'wp_import_tags', $this->tags );
194
+ if ( empty( $this->tags ) ) {
195
+ $this->logger->log( 'No tags to process.', 'success' );
196
+
197
+ return;
198
+ }
199
+ foreach ( $this->tags as $tag ) {
200
+ // if the tag already exists leave it alone
201
+ $term_id = term_exists( $tag['tag_slug'], 'post_tag' );
202
+ if ( $term_id ) {
203
+ if ( is_array( $term_id ) ) {
204
+ $term_id = $term_id['term_id'];
205
+ }
206
+ if ( isset( $tag['term_id'] ) ) {
207
+ $this->processed_terms[ intval( $tag['term_id'] ) ] = (int) $term_id;
208
+ }
209
+ continue;
210
+ }
211
+ $tag = wp_slash( $tag );
212
+ $tag_desc = isset( $tag['tag_description'] ) ? $tag['tag_description'] : '';
213
+ $tagarr = array(
214
+ 'slug' => $tag['tag_slug'],
215
+ 'description' => $tag_desc,
216
+ );
217
+ $id = wp_insert_term( $tag['tag_name'], 'post_tag', $tagarr );
218
+ if ( ! is_wp_error( $id ) ) {
219
+ if ( isset( $tag['term_id'] ) ) {
220
+ $this->processed_terms[ intval( $tag['term_id'] ) ] = $id['term_id'];
221
+ }
222
+ } else {
223
+ $this->logger->log( "Failed to import post tag {$tag['tag_name']}" );
224
+ $this->logger->log( $id->get_error_message() );
225
+ continue;
226
+ }
227
+ $this->process_termmeta( $tag, $id['term_id'] );
228
+ }
229
+ $this->logger->log( 'Processed tags.', 'success' );
230
+ unset( $this->tags );
231
+ }
232
+
233
+ /**
234
+ * Create new terms based on import information
235
+ *
236
+ * Doesn't create a term its slug already exists
237
+ */
238
+ private function process_terms() {
239
+ $this->logger->log( 'Processing terms...', 'progress' );
240
+ $this->terms = apply_filters( 'wp_import_terms', $this->terms );
241
+ if ( empty( $this->terms ) ) {
242
+ $this->logger->log( 'No terms to process.', 'success' );
243
+
244
+ return;
245
+ }
246
+ foreach ( $this->terms as $term ) {
247
+ // if the term already exists in the correct taxonomy leave it alone
248
+ $term_id = term_exists( $term['slug'], $term['term_taxonomy'] );
249
+ if ( $term_id ) {
250
+ if ( is_array( $term_id ) ) {
251
+ $term_id = $term_id['term_id'];
252
+ }
253
+ if ( isset( $term['term_id'] ) ) {
254
+ $this->processed_terms[ intval( $term['term_id'] ) ] = (int) $term_id;
255
+ }
256
+ continue;
257
+ }
258
+ if ( empty( $term['term_parent'] ) ) {
259
+ $parent = 0;
260
+ } else {
261
+ $parent = term_exists( $term['term_parent'], $term['term_taxonomy'] );
262
+ if ( is_array( $parent ) ) {
263
+ $parent = $parent['term_id'];
264
+ }
265
+ }
266
+ $term = wp_slash( $term );
267
+ $description = isset( $term['term_description'] ) ? $term['term_description'] : '';
268
+ $termarr = array(
269
+ 'slug' => $term['slug'],
270
+ 'description' => $description,
271
+ 'parent' => intval( $parent ),
272
+ );
273
+ $id = wp_insert_term( $term['term_name'], $term['term_taxonomy'], $termarr );
274
+ if ( ! is_wp_error( $id ) ) {
275
+ if ( isset( $term['term_id'] ) ) {
276
+ $this->processed_terms[ intval( $term['term_id'] ) ] = $id['term_id'];
277
+ }
278
+ } else {
279
+ $this->logger->log( "Failed to import {$term['term_taxonomy']} {$term['term_name']}", 'warning' );
280
+ $this->logger->log( $id->get_error_message() );
281
+ continue;
282
+ }
283
+ $this->process_termmeta( $term, $id['term_id'] );
284
+ }
285
+ unset( $this->terms );
286
+ $this->logger->log( 'Processed terms.', 'success' );
287
+ }
288
+
289
+ /**
290
+ * Add metadata to imported term.
291
+ *
292
+ * @since 0.6.2
293
+ *
294
+ * @param array $term Term data from WXR import.
295
+ * @param int $term_id ID of the newly created term.
296
+ */
297
+ private function process_termmeta( $term, $term_id ) {
298
+ if ( ! isset( $term['termmeta'] ) ) {
299
+ $term['termmeta'] = array();
300
+ }
301
+ /**
302
+ * Filters the metadata attached to an imported term.
303
+ *
304
+ * @since 0.6.2
305
+ *
306
+ * @param array $termmeta Array of term meta.
307
+ * @param int $term_id ID of the newly created term.
308
+ * @param array $term Term data from the WXR import.
309
+ */
310
+ $term['termmeta'] = apply_filters( 'wp_import_term_meta', $term['termmeta'], $term_id, $term );
311
+ if ( empty( $term['termmeta'] ) ) {
312
+ return;
313
+ }
314
+ foreach ( $term['termmeta'] as $meta ) {
315
+ /**
316
+ * Filters the meta key for an imported piece of term meta.
317
+ *
318
+ * @since 0.6.2
319
+ *
320
+ * @param string $meta_key Meta key.
321
+ * @param int $term_id ID of the newly created term.
322
+ * @param array $term Term data from the WXR import.
323
+ */
324
+ $key = apply_filters( 'import_term_meta_key', $meta['key'], $term_id, $term );
325
+ if ( ! $key ) {
326
+ continue;
327
+ }
328
+ // Export gets meta straight from the DB so could have a serialized string
329
+ $value = maybe_unserialize( $meta['value'] );
330
+ add_term_meta( $term_id, $key, $value );
331
+ /**
332
+ * Fires after term meta is imported.
333
+ *
334
+ * @since 0.6.2
335
+ *
336
+ * @param int $term_id ID of the newly created term.
337
+ * @param string $key Meta key.
338
+ * @param mixed $value Meta value.
339
+ */
340
+ do_action( 'import_term_meta', $term_id, $key, $value );
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Create new posts based on import information
346
+ *
347
+ * Posts marked as having a parent which doesn't exist will become top level items.
348
+ * Doesn't create a new post if: the post type doesn't exist, the given post ID
349
+ * is already noted as imported or a post with the same title and date already exists.
350
+ * Note that new/updated terms, comments and meta are imported for the last of the above.
351
+ */
352
+ private function process_posts() {
353
+ $this->logger->log( 'Processing posts...', 'progress' );
354
+ $this->posts = apply_filters( 'wp_import_posts', $this->posts );
355
+ foreach ( $this->posts as $post ) {
356
+ $post = apply_filters( 'wp_import_post_data_raw', $post );
357
+ if ( ! post_type_exists( $post['post_type'] ) ) {
358
+ $this->logger->log( "Failed to import {$post['post_title']}. Invalid post type {$post['post_type']}" );
359
+ do_action( 'wp_import_post_exists', $post );
360
+ continue;
361
+ }
362
+ if ( isset( $this->processed_posts[ $post['post_id'] ] ) && ! empty( $post['post_id'] ) ) {
363
+ continue;
364
+ }
365
+ if ( $post['status'] == 'auto-draft' ) {
366
+ continue;
367
+ }
368
+ if ( 'nav_menu_item' == $post['post_type'] ) {
369
+ $this->process_menu_item( $post );
370
+ continue;
371
+ }
372
+ $post_type_object = get_post_type_object( $post['post_type'] );
373
+ $post_exists = post_exists( $post['post_title'], '', $post['post_date'] );
374
+ /**
375
+ * Filter ID of the existing post corresponding to post currently importing.
376
+ *
377
+ * Return 0 to force the post to be imported. Filter the ID to be something else
378
+ * to override which existing post is mapped to the imported post.
379
+ *
380
+ * @see post_exists()
381
+ * @since 0.6.2
382
+ *
383
+ * @param int $post_exists Post ID, or 0 if post did not exist.
384
+ * @param array $post The post array to be inserted.
385
+ */
386
+ $post_exists = apply_filters( 'wp_import_existing_post', $post_exists, $post );
387
+ if ( $post_exists && get_post_type( $post_exists ) == $post['post_type'] ) {
388
+ $this->logger->log( $post_type_object->labels->singular_name . ' ' . esc_html( $post['post_title'] ) . ' already exists.', 'success' );
389
+ $comment_post_id = $post_id = $post_exists;
390
+ $this->processed_posts[ intval( $post['post_id'] ) ] = intval( $post_exists );
391
+ } else {
392
+ $post_parent = (int) $post['post_parent'];
393
+ if ( $post_parent ) {
394
+ // if we already know the parent, map it to the new local ID
395
+ if ( isset( $this->processed_posts[ $post_parent ] ) ) {
396
+ $post_parent = $this->processed_posts[ $post_parent ];
397
+ // otherwise record the parent for later
398
+ } else {
399
+ $this->post_orphans[ intval( $post['post_id'] ) ] = $post_parent;
400
+ $post_parent = 0;
401
+ }
402
+ }
403
+ $author = (int) get_current_user_id();
404
+ $postdata = array(
405
+ 'import_id' => $post['post_id'],
406
+ 'post_author' => $author,
407
+ 'post_date' => $post['post_date'],
408
+ 'post_date_gmt' => $post['post_date_gmt'],
409
+ 'post_content' => $post['post_content'],
410
+ 'post_excerpt' => $post['post_excerpt'],
411
+ 'post_title' => $post['post_title'],
412
+ 'post_status' => $post['status'],
413
+ 'post_name' => $post['post_name'],
414
+ 'comment_status' => $post['comment_status'],
415
+ 'ping_status' => $post['ping_status'],
416
+ 'guid' => $post['guid'],
417
+ 'post_parent' => $post_parent,
418
+ 'menu_order' => $post['menu_order'],
419
+ 'post_type' => $post['post_type'],
420
+ 'post_password' => $post['post_password'],
421
+ );
422
+ $original_post_id = $post['post_id'];
423
+ $postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $post );
424
+ $postdata = wp_slash( $postdata );
425
+ if ( 'attachment' == $postdata['post_type'] ) {
426
+ $remote_url = ! empty( $post['attachment_url'] ) ? $post['attachment_url'] : $post['guid'];
427
+ // try to use _wp_attached file for upload folder placement to ensure the same location as the export site
428
+ // e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
429
+ $postdata['upload_date'] = $post['post_date'];
430
+ if ( isset( $post['postmeta'] ) ) {
431
+ foreach ( $post['postmeta'] as $meta ) {
432
+ if ( $meta['key'] == '_wp_attached_file' ) {
433
+ if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta['value'], $matches ) ) {
434
+ $postdata['upload_date'] = $matches[0];
435
+ }
436
+ break;
437
+ }
438
+ }
439
+ }
440
+ $comment_post_id = $post_id = $this->process_attachment( $postdata, $remote_url );
441
+ } else {
442
+ $this->logger->log( "Inserting {$postdata['post_type']}: {$postdata['post_title']}.", 'progress' );
443
+ $comment_post_id = $post_id = wp_insert_post( $postdata, true );
444
+ $this->logger->log( "Done inserting {$postdata['post_type']}: {$postdata['post_title']}.", 'success' );
445
+ do_action( 'wp_import_insert_post', $post_id, $original_post_id, $postdata, $post );
446
+ }
447
+ if ( is_wp_error( $post_id ) ) {
448
+ $this->logger->log( "Failed to import {$post_type_object->labels->singular_name} {$post['post_title']}. \n {$post_id->get_error_message()}" );
449
+ continue;
450
+ }
451
+ if ( $post['is_sticky'] == 1 ) {
452
+ stick_post( $post_id );
453
+ }
454
+ }
455
+ // map pre-import ID to local ID
456
+ $this->processed_posts[ intval( $post['post_id'] ) ] = (int) $post_id;
457
+ if ( ! isset( $post['terms'] ) ) {
458
+ $post['terms'] = array();
459
+ }
460
+ $post['terms'] = apply_filters( 'wp_import_post_terms', $post['terms'], $post_id, $post );
461
+ // add categories, tags and other terms
462
+ if ( ! empty( $post['terms'] ) ) {
463
+ $terms_to_set = array();
464
+ foreach ( $post['terms'] as $term ) {
465
+ // back compat with WXR 1.0 map 'tag' to 'post_tag'
466
+ $taxonomy = ( 'tag' == $term['domain'] ) ? 'post_tag' : $term['domain'];
467
+ $term_exists = term_exists( $term['slug'], $taxonomy );
468
+ $term_id = is_array( $term_exists ) ? $term_exists['term_id'] : $term_exists;
469
+ if ( ! $term_id ) {
470
+ $t = wp_insert_term( $term['name'], $taxonomy, array( 'slug' => $term['slug'] ) );
471
+ if ( ! is_wp_error( $t ) ) {
472
+ $term_id = $t['term_id'];
473
+ do_action( 'wp_import_insert_term', $t, $term, $post_id, $post );
474
+ } else {
475
+ $this->logger->log( "Failed to import {$taxonomy} {$term['name']}", 'success' );
476
+ $this->logger->log( $t->get_error_message() );
477
+ do_action( 'wp_import_insert_term_failed', $t, $term, $post_id, $post );
478
+ continue;
479
+ }
480
+ }
481
+ $terms_to_set[ $taxonomy ][] = intval( $term_id );
482
+ }
483
+ foreach ( $terms_to_set as $tax => $ids ) {
484
+ $tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
485
+ do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $post );
486
+ }
487
+ unset( $post['terms'], $terms_to_set );
488
+ }
489
+ if ( ! isset( $post['comments'] ) ) {
490
+ $post['comments'] = array();
491
+ }
492
+ $post['comments'] = apply_filters( 'wp_import_post_comments', $post['comments'], $post_id, $post );
493
+
494
+ if ( ! isset( $post['postmeta'] ) ) {
495
+ $post['postmeta'] = array();
496
+ }
497
+ $post['postmeta'] = apply_filters( 'wp_import_post_meta', $post['postmeta'], $post_id, $post );
498
+ // add/update post meta
499
+ if ( ! empty( $post['postmeta'] ) ) {
500
+ foreach ( $post['postmeta'] as $meta ) {
501
+ $key = apply_filters( 'import_post_meta_key', $meta['key'], $post_id, $post );
502
+ $value = false;
503
+ if ( '_edit_last' == $key ) {
504
+ $key = false;
505
+ }
506
+ if ( $key ) {
507
+ // export gets meta straight from the DB so could have a serialized string
508
+ if ( ! $value ) {
509
+ $value = maybe_unserialize( $meta['value'] );
510
+ }
511
+ if ( $key === '_elementor_data' ) {
512
+ $this->logger->log( 'Filtering elementor meta...', 'progress' );
513
+ $meta_handler = new Elementor_Meta_Handler( $value, $this->base_blog_url );
514
+ $meta_handler->filter_meta();
515
+ $this->logger->log( 'Filtered elementor meta.', 'success' );
516
+ }
517
+ if ( in_array(
518
+ $key,
519
+ array(
520
+ 'tve_custom_css',
521
+ 'tve_content_before_more',
522
+ 'tve_updated_post',
523
+ )
524
+ ) ) {
525
+ $value = $this->replace_image_urls( $value );
526
+ }
527
+ add_post_meta( $post_id, $key, $value );
528
+ do_action( 'import_post_meta', $post_id, $key, $value );
529
+ // if the post has a featured image, take note of this in case of remap
530
+ if ( '_thumbnail_id' == $key ) {
531
+ $this->featured_images[ $post_id ] = (int) $value;
532
+ }
533
+ }
534
+ }
535
+ }
536
+ }
537
+ unset( $this->posts );
538
+ $this->logger->log( 'Processed posts.', 'success' );
539
+ }
540
+
541
+ /**
542
+ * Attempt to create a new menu item from import data
543
+ *
544
+ * Fails for draft, orphaned menu items and those without an associated nav_menu
545
+ * or an invalid nav_menu term. If the post type or term object which the menu item
546
+ * represents doesn't exist then the menu item will not be imported (waits until the
547
+ * end of the import to retry again before discarding).
548
+ *
549
+ * @param array $item Menu item details from WXR file
550
+ */
551
+ private function process_menu_item( $item ) {
552
+ $this->logger->log( "Processing single menu item '{$item['post_title']}'...", 'progress' );
553
+ // skip draft, orphaned menu items
554
+ if ( 'draft' == $item['status'] ) {
555
+ return;
556
+ }
557
+ $menu_slug = false;
558
+ if ( isset( $item['terms'] ) ) {
559
+ // loop through terms, assume first nav_menu term is correct menu
560
+ foreach ( $item['terms'] as $term ) {
561
+ if ( 'nav_menu' == $term['domain'] ) {
562
+ $menu_slug = $term['slug'];
563
+ break;
564
+ }
565
+ }
566
+ }
567
+ // no nav_menu term associated with this menu item
568
+ if ( ! $menu_slug ) {
569
+ $this->logger->log( 'Menu item skipped. Missing slug.', 'error' );
570
+
571
+ return;
572
+ }
573
+ $menu_id = term_exists( $menu_slug, 'nav_menu' );
574
+ if ( ! $menu_id ) {
575
+ $this->logger->log( "Menu item invalid slug: {$menu_slug}", 'success' );
576
+
577
+ return;
578
+ } else {
579
+ $menu_id = is_array( $menu_id ) ? $menu_id['term_id'] : $menu_id;
580
+ }
581
+ foreach ( $item['postmeta'] as $meta ) {
582
+ ${$meta['key']} = $meta['value'];
583
+ }
584
+ if ( 'taxonomy' == $_menu_item_type && isset( $this->processed_terms[ intval( $_menu_item_object_id ) ] ) ) {
585
+ $_menu_item_object_id = $this->processed_terms[ intval( $_menu_item_object_id ) ];
586
+ } elseif ( 'post_type' == $_menu_item_type && isset( $this->processed_posts[ intval( $_menu_item_object_id ) ] ) ) {
587
+ $_menu_item_object_id = $this->processed_posts[ intval( $_menu_item_object_id ) ];
588
+ } elseif ( 'custom' != $_menu_item_type ) {
589
+ // associated object is missing or not imported yet, we'll retry later
590
+ $this->missing_menu_items[] = $item;
591
+
592
+ return;
593
+ }
594
+ if ( isset( $this->processed_menu_items[ intval( $_menu_item_menu_item_parent ) ] ) ) {
595
+ $_menu_item_menu_item_parent = $this->processed_menu_items[ intval( $_menu_item_menu_item_parent ) ];
596
+ } elseif ( $_menu_item_menu_item_parent ) {
597
+ $this->menu_item_orphans[ intval( $item['post_id'] ) ] = (int) $_menu_item_menu_item_parent;
598
+ $_menu_item_menu_item_parent = 0;
599
+ }
600
+ // wp_update_nav_menu_item expects CSS classes as a space separated string
601
+ $_menu_item_classes = maybe_unserialize( $_menu_item_classes );
602
+ if ( is_array( $_menu_item_classes ) ) {
603
+ $_menu_item_classes = implode( ' ', $_menu_item_classes );
604
+ }
605
+ $args = array(
606
+ 'menu-item-object-id' => $_menu_item_object_id,
607
+ 'menu-item-object' => $_menu_item_object,
608
+ 'menu-item-parent-id' => $_menu_item_menu_item_parent,
609
+ 'menu-item-position' => intval( $item['menu_order'] ),
610
+ 'menu-item-type' => $_menu_item_type,
611
+ 'menu-item-title' => $item['post_title'],
612
+ 'menu-item-url' => $_menu_item_url,
613
+ 'menu-item-description' => $item['post_content'],
614
+ 'menu-item-attr-title' => $item['post_excerpt'],
615
+ 'menu-item-target' => $_menu_item_target,
616
+ 'menu-item-classes' => $_menu_item_classes,
617
+ 'menu-item-xfn' => $_menu_item_xfn,
618
+ 'menu-item-status' => $item['status'],
619
+ );
620
+ $args = apply_filters( 'wp_import_nav_menu_item_args', $args, $this->base_blog_url );
621
+ $existing = wp_get_nav_menu_items( $menu_id );
622
+ foreach ( $existing as $existing_item ) {
623
+ if ( $args['menu-item-url'] === $existing_item->url ) {
624
+ $this->logger->log( 'Menu item already exists.', 'success' );
625
+
626
+ return;
627
+ }
628
+ }
629
+
630
+ $id = wp_update_nav_menu_item( $menu_id, 0, $args );
631
+ if ( $id && ! is_wp_error( $id ) ) {
632
+ $this->processed_menu_items[ intval( $item['post_id'] ) ] = (int) $id;
633
+ }
634
+ $this->logger->log( 'Processed single menu item.', 'success' );
635
+ }
636
+
637
+ /**
638
+ * If fetching attachments is enabled then attempt to create a new attachment
639
+ *
640
+ * @param array $post Attachment post details from WXR
641
+ * @param string $url URL to fetch attachment from
642
+ *
643
+ * @return int|WP_Error Post ID on success, WP_Error otherwise
644
+ */
645
+ private function process_attachment( $post, $url ) {
646
+ $this->logger->log( "Processing attachment: {$url}...", 'progress' );
647
+ if ( ! $this->fetch_attachments ) {
648
+ $this->logger->log( 'Fetching attachments is not enabled', 'error' );
649
+ }
650
+ // if the URL is absolute, but does not contain address, then upload it assuming base_site_url
651
+ if ( preg_match( '|^/[\w\W]+$|', $url ) ) {
652
+ $url = rtrim( $this->base_url, '/' ) . $url;
653
+ }
654
+ $upload = $this->fetch_remote_file( $url, $post );
655
+ if ( is_wp_error( $upload ) ) {
656
+ $this->logger->log( $upload );
657
+
658
+ return $upload;
659
+ }
660
+ $info = wp_check_filetype( $upload['file'] );
661
+ if ( $info ) {
662
+ $post['post_mime_type'] = $info['type'];
663
+ } else {
664
+ $error = new WP_Error( 'attachment_processing_error', 'Invalid file type' );
665
+ $this->logger->log( $error->get_error_message() );
666
+
667
+ return $error;
668
+ }
669
+ $post['guid'] = $upload['url'];
670
+ // as per wp-admin/includes/upload.php
671
+ $this->logger->log( 'Inserting attachment...', 'progress' );
672
+ $post_id = wp_insert_attachment( $post, $upload['file'] );
673
+ $this->logger->log( 'Attachment inserted', 'success' );
674
+ wp_update_attachment_metadata( $post_id, wp_generate_attachment_metadata( $post_id, $upload['file'] ) );
675
+ // remap resized image URLs, works by stripping the extension and remapping the URL stub.
676
+ if ( preg_match( '!^image/!', $info['type'] ) ) {
677
+ $parts = pathinfo( $url );
678
+ $name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2
679
+ $parts_new = pathinfo( $upload['url'] );
680
+ $name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );
681
+ $this->url_remap[ $parts['dirname'] . '/' . $name ] = $parts_new['dirname'] . '/' . $name_new;
682
+ }
683
+ $this->logger->log( 'Processed attachment.', 'success' );
684
+
685
+ return $post_id;
686
+ }
687
+
688
+ /**
689
+ * Attempt to download a remote file attachment
690
+ *
691
+ * @param string $url URL of item to fetch
692
+ * @param array $post Attachment details
693
+ *
694
+ * @return array|WP_Error Local file location details on success, WP_Error otherwise
695
+ */
696
+ private function fetch_remote_file( $url, $post ) {
697
+ $this->logger->log( "Fetching attachment from url: {$url}...", 'progress' );
698
+ // extract the file name and extension from the url
699
+ $file_name = basename( $url );
700
+ // get placeholder file in the upload dir with a unique, sanitized filename
701
+ $upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
702
+ if ( $upload['error'] ) {
703
+ return new WP_Error( 'upload_dir_error', $upload['error'] );
704
+ }
705
+ // fetch the remote url and write it to the placeholder file
706
+ $remote_response = wp_safe_remote_get(
707
+ $url,
708
+ array(
709
+ 'timeout' => 300,
710
+ 'stream' => true,
711
+ 'filename' => $upload['file'],
712
+ )
713
+ );
714
+ $headers = wp_remote_retrieve_headers( $remote_response );
715
+ // request failed
716
+ if ( ! $headers ) {
717
+ @unlink( $upload['file'] );
718
+ $error = new WP_Error( 'import_file_error', 'Remote server did not respond' );
719
+ $this->logger->log( $error->get_error_message() );
720
+
721
+ return $error;
722
+ }
723
+ $remote_response_code = wp_remote_retrieve_response_code( $remote_response );
724
+ // make sure the fetch was successful
725
+ if ( $remote_response_code != '200' ) {
726
+ @unlink( $upload['file'] );
727
+ $error = new WP_Error( 'import_file_error', sprintf( 'Remote server returned error response %1$d %2$s', esc_html( $remote_response_code ), get_status_header_desc( $remote_response_code ) ) );
728
+ $this->logger->log( $error->get_error_message() );
729
+
730
+ return $error;
731
+ }
732
+ $filesize = filesize( $upload['file'] );
733
+ if ( isset( $headers['content-length'] ) && $filesize != $headers['content-length'] ) {
734
+ @unlink( $upload['file'] );
735
+ $error = new WP_Error( 'import_file_error', 'Remote file is incorrect size' );
736
+ $this->logger->log( $error->get_error_message() );
737
+
738
+ return $error;
739
+ }
740
+ if ( 0 == $filesize ) {
741
+ @unlink( $upload['file'] );
742
+ $error = new WP_Error( 'import_file_error', 'Zero size file downloaded' );
743
+ $this->logger->log( $error->get_error_message() );
744
+
745
+ return $error;
746
+ }
747
+ $max_size = (int) $this->max_attachment_size();
748
+ if ( ! empty( $max_size ) && $filesize > $max_size ) {
749
+ @unlink( $upload['file'] );
750
+ $error = new WP_Error( 'import_file_error', sprintf( 'Remote file is too large, limit is %s', size_format( $max_size ) ) );
751
+ $this->logger->log( $error->get_error_message() );
752
+
753
+ return $error;
754
+ }
755
+ // keep track of the old and new urls so we can substitute them later
756
+ $this->url_remap[ $url ] = $upload['url'];
757
+ $this->url_remap[ $post['guid'] ] = $upload['url']; // r13735, really needed?
758
+ // keep track of the destination if the remote url is redirected somewhere else
759
+ if ( isset( $headers['x-final-location'] ) && $headers['x-final-location'] != $url ) {
760
+ $this->url_remap[ $headers['x-final-location'] ] = $upload['url'];
761
+ }
762
+
763
+ $this->logger->log( 'Fetched remote attachment.', 'success' );
764
+
765
+ return $upload;
766
+ }
767
+
768
+ /**
769
+ * Attempt to associate posts and menu items with previously missing parents
770
+ *
771
+ * An imported post's parent may not have been imported when it was first created
772
+ * so try again. Similarly for child menu items and menu items which were missing
773
+ * the object (e.g. post) they represent in the menu
774
+ */
775
+ function backfill_parents() {
776
+ global $wpdb;
777
+ // find parents for post orphans
778
+ foreach ( $this->post_orphans as $child_id => $parent_id ) {
779
+ $local_child_id = $local_parent_id = false;
780
+ if ( isset( $this->processed_posts[ $child_id ] ) ) {
781
+ $local_child_id = $this->processed_posts[ $child_id ];
782
+ }
783
+ if ( isset( $this->processed_posts[ $parent_id ] ) ) {
784
+ $local_parent_id = $this->processed_posts[ $parent_id ];
785
+ }
786
+ if ( $local_child_id && $local_parent_id ) {
787
+ $wpdb->update( $wpdb->posts, array( 'post_parent' => $local_parent_id ), array( 'ID' => $local_child_id ), '%d', '%d' );
788
+ clean_post_cache( $local_child_id );
789
+ }
790
+ }
791
+ // all other posts/terms are imported, retry menu items with missing associated object
792
+ $missing_menu_items = $this->missing_menu_items;
793
+ foreach ( $missing_menu_items as $item ) {
794
+ $this->process_menu_item( $item );
795
+ }
796
+ // find parents for menu item orphans
797
+ foreach ( $this->menu_item_orphans as $child_id => $parent_id ) {
798
+ $local_child_id = $local_parent_id = 0;
799
+ if ( isset( $this->processed_menu_items[ $child_id ] ) ) {
800
+ $local_child_id = $this->processed_menu_items[ $child_id ];
801
+ }
802
+ if ( isset( $this->processed_menu_items[ $parent_id ] ) ) {
803
+ $local_parent_id = $this->processed_menu_items[ $parent_id ];
804
+ }
805
+ if ( $local_child_id && $local_parent_id ) {
806
+ update_post_meta( $local_child_id, '_menu_item_menu_item_parent', (int) $local_parent_id );
807
+ }
808
+ }
809
+ }
810
+
811
+ /**
812
+ * Use stored mapping information to update old attachment URLs
813
+ */
814
+ function backfill_attachment_urls() {
815
+ global $wpdb;
816
+ // make sure we do the longest urls first, in case one is a substring of another
817
+ uksort( $this->url_remap, array( &$this, 'cmpr_strlen' ) );
818
+ foreach ( $this->url_remap as $from_url => $to_url ) {
819
+ // remap urls in post_content
820
+ $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url ) );
821
+ // remap enclosure urls
822
+ $result = $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url ) );
823
+ }
824
+ }
825
+
826
+ /**
827
+ * Update _thumbnail_id meta to new, imported attachment IDs
828
+ */
829
+ function remap_featured_images() {
830
+ // cycle through posts that have a featured image
831
+ foreach ( $this->featured_images as $post_id => $value ) {
832
+ if ( isset( $this->processed_posts[ $value ] ) ) {
833
+ $new_id = $this->processed_posts[ $value ];
834
+ // only update if there's a difference
835
+ if ( $new_id != $value ) {
836
+ update_post_meta( $post_id, '_thumbnail_id', $new_id );
837
+ }
838
+ }
839
+ }
840
+ }
841
+
842
+ /**
843
+ * Parse a WXR file
844
+ *
845
+ * @param string $file Path to WXR file for parsing
846
+ *
847
+ * @return array Information gathered from the WXR file
848
+ */
849
+ private function parse( $file ) {
850
+ $this->logger->log( 'Parsing XML file.', 'success' );
851
+ $parser = new WXR_Parser( $this->page_builder );
852
+
853
+ return $parser->parse( $file );
854
+ }
855
+
856
+ /**
857
+ * Decide if the given meta key maps to information we will want to import
858
+ *
859
+ * @param string $key The meta key to check
860
+ *
861
+ * @return string|bool The key if we do want to import, false if not
862
+ */
863
+ public function is_valid_meta_key( $key ) {
864
+ // skip attachment metadata since we'll regenerate it from scratch
865
+ // skip _edit_lock as not relevant for import
866
+ if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) {
867
+ return false;
868
+ }
869
+
870
+ return $key;
871
+ }
872
+
873
+ /**
874
+ * Decide whether or not the importer should attempt to download attachment files.
875
+ * Default is true, can be filtered via import_allow_fetch_attachments. The choice
876
+ * made at the import options screen must also be true, false here hides that checkbox.
877
+ *
878
+ * @return bool True if downloading attachments is allowed
879
+ */
880
+ function allow_fetch_attachments() {
881
+ return apply_filters( 'import_allow_fetch_attachments', true );
882
+ }
883
+
884
+ /**
885
+ * Decide what the maximum file size for downloaded attachments is.
886
+ * Default is 0 (unlimited), can be filtered via import_attachment_size_limit
887
+ *
888
+ * @return int Maximum attachment file size to import
889
+ */
890
+ private function max_attachment_size() {
891
+ return apply_filters( 'import_attachment_size_limit', 0 );
892
+ }
893
+
894
+ /**
895
+ * Added to http_request_timeout filter to force timeout at 60 seconds during import
896
+ * @return int 60
897
+ */
898
+ public function bump_request_timeout( $val ) {
899
+ return 60;
900
+ }
901
+
902
+ // return the difference in length between two strings
903
+ public function cmpr_strlen( $a, $b ) {
904
+ return strlen( $b ) - strlen( $a );
905
+ }
906
+ }
includes/Importers/WP/WXR_Parser.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TIOB\Importers\WP;
4
+
5
+ use TIOB\Logger;
6
+
7
+ /**
8
+ * WordPress Importer class for managing parsing of WXR files.
9
+ */
10
+ class WXR_Parser {
11
+ /**
12
+ * Logger instance.
13
+ *
14
+ * @var Logger
15
+ */
16
+ private $logger;
17
+
18
+ /**
19
+ * Used page builder.
20
+ *
21
+ * @var string
22
+ */
23
+ private $page_builder;
24
+
25
+ /**
26
+ * WXR_Parser constructor.
27
+ *
28
+ * @param string $page_builder the page builder used.
29
+ */
30
+ public function __construct( $page_builder = '' ) {
31
+ $this->page_builder = $page_builder;
32
+ $this->logger = Logger::get_instance();
33
+ }
34
+
35
+ /**
36
+ * Parse XML file.
37
+ *
38
+ * @param string $file file path.
39
+ *
40
+ * @return array|WP_Error
41
+ */
42
+ public function parse( $file ) {
43
+ $this->logger->log( "Starting parsing file:{$file}", 'progress' );
44
+ $result = null;
45
+
46
+ if ( $this->page_builder === 'beaver-builder' || $this->page_builder === 'beaver builder' ) {
47
+ if ( extension_loaded( 'xml' ) ) {
48
+ $parser = new Beaver_ParserXML();
49
+
50
+ $result = $parser->parse( $file );
51
+ } else {
52
+ $this->logger->log( 'xml not active.' );
53
+ }
54
+ if ( is_wp_error( $result ) ) {
55
+ $this->logger->log( "Parse failed with message: {$result->get_error_message()}" );
56
+ }
57
+
58
+ if ( $result === null ) {
59
+ $this->logger->log( 'Nothing got parsed from XML.' );
60
+ }
61
+
62
+ return $result;
63
+ }
64
+
65
+ // Attempt to use proper XML parsers first
66
+ if ( extension_loaded( 'simplexml' ) ) {
67
+ $parser = new WXR_Parser_SimpleXML();
68
+ $this->logger->log( 'Using WXR_Parser_SimpleXML...', 'progress' );
69
+ $result = $parser->parse( $file );
70
+ // If SimpleXML succeeds or this is an invalid WXR file then return the results
71
+ if ( ! is_wp_error( $result ) || 'SimpleXML_parse_error' != $result->get_error_code() ) {
72
+ $this->logger->log( 'Parsed XML', 'success' );
73
+
74
+ return $result;
75
+ }
76
+ } elseif ( extension_loaded( 'xml' ) ) {
77
+ $this->logger->log( 'Using WXR_Parser_XML...', 'progress' );
78
+ $parser = new WXR_Parser_XML;
79
+ $result = $parser->parse( $file );
80
+ // If XMLParser succeeds or this is an invalid WXR file then return the results
81
+ if ( ! is_wp_error( $result ) || 'XML_parse_error' != $result->get_error_code() ) {
82
+ $this->logger->log( 'Parsed XML', 'success' );
83
+
84
+ return $result;
85
+ }
86
+ }
87
+
88
+ if ( is_wp_error( $result ) ) {
89
+ $this->logger->log( 'simplexml and xml not active.' );
90
+ $this->logger->log( "Parse failed with message: {$result->get_error_message()}" );
91
+ }
92
+
93
+ return $result;
94
+ }
95
+ }
includes/Importers/WP/WXR_Parser_SimpleXML.php ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TIOB\Importers\WP;
4
+
5
+ /**
6
+ * WXR Parser that makes use of the SimpleXML PHP extension.
7
+ */
8
+ class WXR_Parser_SimpleXML {
9
+ /**
10
+ * @param string $file file path.
11
+ *
12
+ * @return array | WP_Error
13
+ */
14
+ public function parse( $file ) {
15
+ global $wp_filesystem;
16
+ WP_Filesystem();
17
+ $authors = $posts = $categories = $tags = $terms = array();
18
+ $internal_errors = libxml_use_internal_errors( true );
19
+ $dom = new \DOMDocument;
20
+ $old_value = null;
21
+ if ( function_exists( 'libxml_disable_entity_loader' ) ) {
22
+ $old_value = libxml_disable_entity_loader( true );
23
+ }
24
+ $success = $dom->loadXML( $wp_filesystem->get_contents( $file ) );
25
+ if ( ! is_null( $old_value ) ) {
26
+ libxml_disable_entity_loader( $old_value );
27
+ }
28
+ if ( ! $success || isset( $dom->doctype ) ) {
29
+ return new WP_Error( 'SimpleXML_parse_error', 'There was an error when reading this WXR file', libxml_get_errors() );
30
+ }
31
+ $xml = simplexml_import_dom( $dom );
32
+ unset( $dom );
33
+ // halt if loading produces an error
34
+ if ( ! $xml ) {
35
+ return new WP_Error( 'SimpleXML_parse_error', 'There was an error when reading this WXR file', libxml_get_errors() );
36
+ }
37
+ $wxr_version = $xml->xpath( '/rss/channel/wp:wxr_version' );
38
+ if ( ! $wxr_version ) {
39
+ return new WP_Error( 'WXR_parse_error', 'This does not appear to be a WXR file, missing/invalid WXR version number' );
40
+ }
41
+ $wxr_version = (string) trim( $wxr_version[0] );
42
+ // confirm that we are dealing with the correct file format
43
+ if ( ! preg_match( '/^\d+\.\d+$/', $wxr_version ) ) {
44
+ return new WP_Error( 'WXR_parse_error', 'This does not appear to be a WXR file, missing/invalid WXR version number' );
45
+ }
46
+ $base_url = $xml->xpath( '/rss/channel/wp:base_site_url' );
47
+ $base_url = (string) trim( $base_url[0] );
48
+ $base_blog_url = $xml->xpath( '/rss/channel/wp:base_blog_url' );
49
+ $base_blog_url = (string) trim( $base_blog_url[0] );
50
+ $namespaces = $xml->getDocNamespaces();
51
+ if ( ! isset( $namespaces['wp'] ) ) {
52
+ $namespaces['wp'] = 'http://wordpress.org/export/1.1/';
53
+ }
54
+ if ( ! isset( $namespaces['excerpt'] ) ) {
55
+ $namespaces['excerpt'] = 'http://wordpress.org/export/1.1/excerpt/';
56
+ }
57
+ // grab authors
58
+ foreach ( $xml->xpath( '/rss/channel/wp:author' ) as $author_arr ) {
59
+ $a = $author_arr->children( $namespaces['wp'] );
60
+ $login = (string) $a->author_login;
61
+ $authors[ $login ] = array(
62
+ 'author_id' => (int) $a->author_id,
63
+ 'author_login' => $login,
64
+ 'author_email' => (string) $a->author_email,
65
+ 'author_display_name' => (string) $a->author_display_name,
66
+ 'author_first_name' => (string) $a->author_first_name,
67
+ 'author_last_name' => (string) $a->author_last_name,
68
+ );
69
+ }
70
+ // grab cats, tags and terms
71
+ foreach ( $xml->xpath( '/rss/channel/wp:category' ) as $term_arr ) {
72
+ $t = $term_arr->children( $namespaces['wp'] );
73
+ $category = array(
74
+ 'term_id' => (int) $t->term_id,
75
+ 'category_nicename' => (string) $t->category_nicename,
76
+ 'category_parent' => (string) $t->category_parent,
77
+ 'cat_name' => (string) $t->cat_name,
78
+ 'category_description' => (string) $t->category_description,
79
+ );
80
+ foreach ( $t->termmeta as $meta ) {
81
+ $category['termmeta'][] = array(
82
+ 'key' => (string) $meta->meta_key,
83
+ 'value' => (string) $meta->meta_value,
84
+ );
85
+ }
86
+ $categories[] = $category;
87
+ }
88
+ foreach ( $xml->xpath( '/rss/channel/wp:tag' ) as $term_arr ) {
89
+ $t = $term_arr->children( $namespaces['wp'] );
90
+ $tag = array(
91
+ 'term_id' => (int) $t->term_id,
92
+ 'tag_slug' => (string) $t->tag_slug,
93
+ 'tag_name' => (string) $t->tag_name,
94
+ 'tag_description' => (string) $t->tag_description,
95
+ );
96
+ foreach ( $t->termmeta as $meta ) {
97
+ $tag['termmeta'][] = array(
98
+ 'key' => (string) $meta->meta_key,
99
+ 'value' => (string) $meta->meta_value,
100
+ );
101
+ }
102
+ $tags[] = $tag;
103
+ }
104
+ foreach ( $xml->xpath( '/rss/channel/wp:term' ) as $term_arr ) {
105
+ $t = $term_arr->children( $namespaces['wp'] );
106
+ $term = array(
107
+ 'term_id' => (int) $t->term_id,
108
+ 'term_taxonomy' => (string) $t->term_taxonomy,
109
+ 'slug' => (string) $t->term_slug,
110
+ 'term_parent' => (string) $t->term_parent,
111
+ 'term_name' => (string) $t->term_name,
112
+ 'term_description' => (string) $t->term_description,
113
+ );
114
+ foreach ( $t->termmeta as $meta ) {
115
+ $term['termmeta'][] = array(
116
+ 'key' => (string) $meta->meta_key,
117
+ 'value' => (string) $meta->meta_value,
118
+ );
119
+ }
120
+ $terms[] = $term;
121
+ }
122
+ // grab posts
123
+ foreach ( $xml->channel->item as $item ) {
124
+ $post = array(
125
+ 'post_title' => (string) $item->title,
126
+ 'guid' => (string) $item->guid,
127
+ );
128
+ $dc = $item->children( 'http://purl.org/dc/elements/1.1/' );
129
+ $post['post_author'] = (string) $dc->creator;
130
+ $content = $item->children( 'http://purl.org/rss/1.0/modules/content/' );
131
+ $excerpt = $item->children( $namespaces['excerpt'] );
132
+ $post['post_content'] = (string) $content->encoded;
133
+ $post['post_excerpt'] = (string) $excerpt->encoded;
134
+ $wp = $item->children( $namespaces['wp'] );
135
+ $post['post_id'] = (int) $wp->post_id;
136
+ $post['post_date'] = (string) $wp->post_date;
137
+ $post['post_date_gmt'] = (string) $wp->post_date_gmt;
138
+ $post['comment_status'] = (string) $wp->comment_status;
139
+ $post['ping_status'] = (string) $wp->ping_status;
140
+ $post['post_name'] = (string) $wp->post_name;
141
+ $post['status'] = (string) $wp->status;
142
+ $post['post_parent'] = (int) $wp->post_parent;
143
+ $post['menu_order'] = (int) $wp->menu_order;
144
+ $post['post_type'] = (string) $wp->post_type;
145
+ $post['post_password'] = (string) $wp->post_password;
146
+ $post['is_sticky'] = (int) $wp->is_sticky;
147
+ if ( isset( $wp->attachment_url ) ) {
148
+ $post['attachment_url'] = (string) $wp->attachment_url;
149
+ }
150
+ foreach ( $item->category as $c ) {
151
+ $att = $c->attributes();
152
+ if ( isset( $att['nicename'] ) ) {
153
+ $post['terms'][] = array(
154
+ 'name' => (string) $c,
155
+ 'slug' => (string) $att['nicename'],
156
+ 'domain' => (string) $att['domain'],
157
+ );
158
+ }
159
+ }
160
+ foreach ( $wp->postmeta as $meta ) {
161
+ $post['postmeta'][] = array(
162
+ 'key' => (string) $meta->meta_key,
163
+ 'value' => (string) $meta->meta_value,
164
+ );
165
+ }
166
+ foreach ( $wp->comment as $comment ) {
167
+ $meta = array();
168
+ if ( isset( $comment->commentmeta ) ) {
169
+ foreach ( $comment->commentmeta as $m ) {
170
+ $meta[] = array(
171
+ 'key' => (string) $m->meta_key,
172
+ 'value' => (string) $m->meta_value,
173
+ );
174
+ }
175
+ }
176
+ $post['comments'][] = array(
177
+ 'comment_id' => (int) $comment->comment_id,
178
+ 'comment_author' => (string) $comment->comment_author,
179
+ 'comment_author_email' => (string) $comment->comment_author_email,
180
+ 'comment_author_IP' => (string) $comment->comment_author_IP,
181
+ 'comment_author_url' => (string) $comment->comment_author_url,
182
+ 'comment_date' => (string) $comment->comment_date,
183
+ 'comment_date_gmt' => (string) $comment->comment_date_gmt,
184
+ 'comment_content' => (string) $comment->comment_content,
185
+ 'comment_approved' => (string) $comment->comment_approved,
186
+ 'comment_type' => (string) $comment->comment_type,
187
+ 'comment_parent' => (string) $comment->comment_parent,
188
+ 'comment_user_id' => (int) $comment->comment_user_id,
189
+ 'commentmeta' => $meta,
190
+ );
191
+ }
192
+ $posts[] = $post;
193
+ }
194
+
195
+ return array(
196
+ 'authors' => $authors,
197
+ 'posts' => $posts,
198
+ 'categories' => $categories,
199
+ 'tags' => $tags,
200
+ 'terms' => $terms,
201
+ 'base_url' => $base_url,
202
+ 'base_blog_url' => $base_blog_url,
203
+ 'version' => $wxr_version,
204
+ );
205
+ }
206
+ }
includes/Importers/WP/WXR_Parser_XML.php ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TIOB\Importers\WP;
4
+
5
+ /**
6
+ * WXR Parser that makes use of the XML Parser PHP extension.
7
+ */
8
+ class WXR_Parser_XML {
9
+ /**
10
+ * XML Tags.
11
+ *
12
+ * @var array
13
+ */
14
+ public $wp_tags = array(
15
+ 'wp:post_id',
16
+ 'wp:post_date',
17
+ 'wp:post_date_gmt',
18
+ 'wp:comment_status',
19
+ 'wp:ping_status',
20
+ 'wp:attachment_url',
21
+ 'wp:status',
22
+ 'wp:post_name',
23
+ 'wp:post_parent',
24
+ 'wp:menu_order',
25
+ 'wp:post_type',
26
+ 'wp:post_password',
27
+ 'wp:is_sticky',
28
+ 'wp:term_id',
29
+ 'wp:category_nicename',
30
+ 'wp:category_parent',
31
+ 'wp:cat_name',
32
+ 'wp:category_description',
33
+ 'wp:tag_slug',
34
+ 'wp:tag_name',
35
+ 'wp:tag_description',
36
+ 'wp:term_taxonomy',
37
+ 'wp:term_parent',
38
+ 'wp:term_name',
39
+ 'wp:term_description',
40
+ 'wp:author_id',
41
+ 'wp:author_login',
42
+ 'wp:author_email',
43
+ 'wp:author_display_name',
44
+ 'wp:author_first_name',
45
+ 'wp:author_last_name',
46
+ );
47
+ public $wp_sub_tags = array(
48
+ 'wp:comment_id',
49
+ 'wp:comment_author',
50
+ 'wp:comment_author_email',
51
+ 'wp:comment_author_url',
52
+ 'wp:comment_author_IP',
53
+ 'wp:comment_date',
54
+ 'wp:comment_date_gmt',
55
+ 'wp:comment_content',
56
+ 'wp:comment_approved',
57
+ 'wp:comment_type',
58
+ 'wp:comment_parent',
59
+ 'wp:comment_user_id',
60
+ );
61
+
62
+ /**
63
+ * Parse the XML
64
+ *
65
+ * @param $file
66
+ *
67
+ * @return array|WP_Error
68
+ */
69
+ public function parse( $file ) {
70
+ global $wp_filesystem;
71
+ WP_Filesystem();
72
+ $this->wxr_version = $this->in_post = $this->cdata = $this->data = $this->sub_data = $this->in_tag = $this->in_sub_tag = false;
73
+ $this->authors = $this->posts = $this->term = $this->category = $this->tag = array();
74
+ $xml = xml_parser_create( 'UTF-8' );
75
+ xml_parser_set_option( $xml, XML_OPTION_SKIP_WHITE, 1 );
76
+ xml_parser_set_option( $xml, XML_OPTION_CASE_FOLDING, 0 );
77
+ xml_set_object( $xml, $this );
78
+ xml_set_character_data_handler( $xml, 'cdata' );
79
+ xml_set_element_handler( $xml, 'tag_open', 'tag_close' );
80
+ if ( ! xml_parse( $xml, $wp_filesystem->get_contents( $file ), true ) ) {
81
+ $current_line = xml_get_current_line_number( $xml );
82
+ $current_column = xml_get_current_column_number( $xml );
83
+ $error_code = xml_get_error_code( $xml );
84
+ $error_string = xml_error_string( $error_code );
85
+
86
+ return new WP_Error(
87
+ 'XML_parse_error',
88
+ 'There was an error when reading this WXR file',
89
+ array(
90
+ $current_line,
91
+ $current_column,
92
+ $error_string,
93
+ )
94
+ );
95
+ }
96
+ xml_parser_free( $xml );
97
+ if ( ! preg_match( '/^\d+\.\d+$/', $this->wxr_version ) ) {
98
+ return new WP_Error( 'WXR_parse_error', 'This does not appear to be a WXR file, missing/invalid WXR version number' );
99
+ }
100
+
101
+ return array(
102
+ 'authors' => $this->authors,
103
+ 'posts' => $this->posts,
104
+ 'categories' => $this->category,
105
+ 'tags' => $this->tag,
106
+ 'terms' => $this->term,
107
+ 'base_url' => $this->base_url,
108
+ 'base_blog_url' => $this->base_blog_url,
109
+ 'version' => $this->wxr_version,
110
+ );
111
+ }
112
+
113
+ public function tag_open( $parse, $tag, $attr ) {
114
+ if ( in_array( $tag, $this->wp_tags ) ) {
115
+ $this->in_tag = substr( $tag, 3 );
116
+
117
+ return;
118
+ }
119
+ if ( in_array( $tag, $this->wp_sub_tags ) ) {
120
+ $this->in_sub_tag = substr( $tag, 3 );
121
+
122
+ return;
123
+ }
124
+ switch ( $tag ) {
125
+ case 'category':
126
+ if ( isset( $attr['domain'], $attr['nicename'] ) ) {
127
+ $this->sub_data['domain'] = $attr['domain'];
128
+ $this->sub_data['slug'] = $attr['nicename'];
129
+ }
130
+ break;
131
+ case 'item':
132
+ $this->in_post = true;
133
+ break;
134
+ case 'title':
135
+ if ( $this->in_post ) {
136
+ $this->in_tag = 'post_title';
137
+ }
138
+ break;
139
+ case 'guid':
140
+ $this->in_tag = 'guid';
141
+ break;
142
+ case 'dc:creator':
143
+ $this->in_tag = 'post_author';
144
+ break;
145
+ case 'content:encoded':
146
+ $this->in_tag = 'post_content';
147
+ break;
148
+ case 'excerpt:encoded':
149
+ $this->in_tag = 'post_excerpt';
150
+ break;
151
+ case 'wp:term_slug':
152
+ $this->in_tag = 'slug';
153
+ break;
154
+ case 'wp:meta_key':
155
+ $this->in_sub_tag = 'key';
156
+ break;
157
+ case 'wp:meta_value':
158
+ $this->in_sub_tag = 'value';
159
+ break;
160
+ }
161
+ }
162
+
163
+ public function cdata( $parser, $cdata ) {
164
+ if ( ! trim( $cdata ) ) {
165
+ return;
166
+ }
167
+ if ( false !== $this->in_tag || false !== $this->in_sub_tag ) {
168
+ $this->cdata .= $cdata;
169
+ } else {
170
+ $this->cdata .= trim( $cdata );
171
+ }
172
+ }
173
+
174
+ public function tag_close( $parser, $tag ) {
175
+ switch ( $tag ) {
176
+ case 'wp:comment':
177
+ unset( $this->sub_data['key'], $this->sub_data['value'] ); // remove meta sub_data
178
+ if ( ! empty( $this->sub_data ) ) {
179
+ $this->data['comments'][] = $this->sub_data;
180
+ }
181
+ $this->sub_data = false;
182
+ break;
183
+ case 'wp:commentmeta':
184
+ $this->sub_data['commentmeta'][] = array(
185
+ 'key' => $this->sub_data['key'],
186
+ 'value' => $this->sub_data['value'],
187
+ );
188
+ break;
189
+ case 'category':
190
+ if ( ! empty( $this->sub_data ) ) {
191
+ $this->sub_data['name'] = $this->cdata;
192
+ $this->data['terms'][] = $this->sub_data;
193
+ }
194
+ $this->sub_data = false;
195
+ break;
196
+ case 'wp:postmeta':
197
+ if ( ! empty( $this->sub_data ) ) {
198
+ $this->data['postmeta'][] = $this->sub_data;
199
+ }
200
+ $this->sub_data = false;
201
+ break;
202
+ case 'item':
203
+ $this->posts[] = $this->data;
204
+ $this->data = false;
205
+ break;
206
+ case 'wp:category':
207
+ case 'wp:tag':
208
+ case 'wp:term':
209
+ $n = substr( $tag, 3 );
210
+ array_push( $this->$n, $this->data );
211
+ $this->data = false;
212
+ break;
213
+ case 'wp:author':
214
+ if ( ! empty( $this->data['author_login'] ) ) {
215
+ $this->authors[ $this->data['author_login'] ] = $this->data;
216
+ }
217
+ $this->data = false;
218
+ break;
219
+ case 'wp:base_site_url':
220
+ $this->base_url = $this->cdata;
221
+ break;
222
+ case 'wp:base_blog_url':
223
+ $this->base_blog_url = $this->cdata;
224
+ break;
225
+ case 'wp:wxr_version':
226
+ $this->wxr_version = $this->cdata;
227
+ break;
228
+ default:
229
+ if ( $this->in_sub_tag ) {
230
+ $this->sub_data[ $this->in_sub_tag ] = ! empty( $this->cdata ) ? $this->cdata : '';
231
+ $this->in_sub_tag = false;
232
+ } elseif ( $this->in_tag ) {
233
+ $this->data[ $this->in_tag ] = ! empty( $this->cdata ) ? $this->cdata : '';
234
+ $this->in_tag = false;
235
+ }
236
+ }
237
+ $this->cdata = false;
238
+ }
239
+ }
includes/Importers/Widgets_Importer.php ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widgets Importer.
4
+ *
5
+ * Author: Andrei Baicus <andrei@themeisle.com>
6
+ * On: 21/06/2018
7
+ *
8
+ * @package templates-patterns-collection
9
+ * @soundtrack Milk Carton Kid - The Milk Carton Kids
10
+ */
11
+
12
+ namespace TIOB\Importers;
13
+
14
+ use WP_Error;
15
+ use WP_REST_Request;
16
+ use WP_REST_Response;
17
+
18
+ /**
19
+ * Class Widgets_Importer
20
+ */
21
+ class Widgets_Importer {
22
+
23
+ /**
24
+ * Import Widgets.
25
+ *
26
+ * @param WP_REST_Request $request contains the widgets that should be imported.
27
+ *
28
+ * @return WP_REST_Response
29
+ */
30
+ public function import_widgets( WP_REST_Request $request ) {
31
+ $widgets = $request->get_json_params();
32
+
33
+ if ( empty( $widgets ) || ! is_array( $widgets ) ) {
34
+ return new WP_REST_Response(
35
+ array(
36
+ 'success' => true,
37
+ )
38
+ );
39
+ }
40
+
41
+ do_action( 'themeisle_ob_before_widgets_import' );
42
+
43
+ $import = $this->actually_import( $widgets );
44
+
45
+ if ( is_wp_error( $import ) ) {
46
+ return new WP_REST_Response(
47
+ array(
48
+ 'data' => 'ti__ob_widgets_err_1',
49
+ 'success' => false,
50
+ )
51
+ );
52
+ }
53
+
54
+ do_action( 'themeisle_ob_after_widgets_import' );
55
+
56
+ return new WP_REST_Response(
57
+ array(
58
+ 'success' => true,
59
+ )
60
+ );
61
+ }
62
+
63
+ /**
64
+ * Widget import process.
65
+ *
66
+ * @param array $data Widgets data.
67
+ * @return \WP_Error
68
+ */
69
+ public function actually_import( $data ) {
70
+ global $wp_registered_sidebars;
71
+ if ( empty( $data ) || ! is_array( $data ) ) {
72
+ return new WP_Error( 'ti__ob_widget_err_1' );
73
+ }
74
+
75
+ $available_widgets = $this->available_widgets();
76
+
77
+ $widget_instances = array();
78
+ foreach ( $available_widgets as $widget_data ) {
79
+ $widget_instances[ $widget_data['id_base'] ] = get_option( 'widget_' . $widget_data['id_base'] );
80
+ }
81
+
82
+ foreach ( $data as $sidebar_id => $widgets ) {
83
+ if ( 'wp_inactive_widgets' === $sidebar_id ) {
84
+ continue;
85
+ }
86
+
87
+ if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
88
+ $sidebar_available = true;
89
+ $use_sidebar_id = $sidebar_id;
90
+ } else {
91
+ $sidebar_available = false;
92
+ $use_sidebar_id = 'wp_inactive_widgets'; // Add to inactive if sidebar does not exist in theme.
93
+ }
94
+
95
+ // Loop widgets.
96
+ foreach ( $widgets as $widget_instance_id => $widget ) {
97
+
98
+ $fail = false;
99
+
100
+ // Get id_base (remove -# from end) and instance ID number.
101
+ $id_base = preg_replace( '/-[0-9]+$/', '', $widget_instance_id );
102
+ $instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id );
103
+
104
+ // Does site support this widget?
105
+ if ( ! $fail && ! isset( $available_widgets[ $id_base ] ) ) {
106
+ $fail = true;
107
+ }
108
+
109
+ // Convert multidimensional objects to multidimensional arrays
110
+ $widget = json_decode( wp_json_encode( $widget ), true );
111
+
112
+ // Does widget with identical settings already exist in same sidebar?
113
+ if ( ! $fail && isset( $widget_instances[ $id_base ] ) ) {
114
+
115
+ // Get existing widgets in this sidebar.
116
+ $sidebars_widgets = get_option( 'sidebars_widgets' );
117
+ $sidebar_widgets = isset( $sidebars_widgets[ $use_sidebar_id ] ) ? $sidebars_widgets[ $use_sidebar_id ] : array(); // Check Inactive if that's where will go.
118
+
119
+ // Loop widgets with ID base.
120
+ $single_widget_instances = ! empty( $widget_instances[ $id_base ] ) ? $widget_instances[ $id_base ] : array();
121
+ foreach ( $single_widget_instances as $check_id => $check_widget ) {
122
+
123
+ // Is widget in same sidebar and has identical settings?
124
+ if ( in_array( "$id_base-$check_id", $sidebar_widgets, true ) && (array) $widget === $check_widget ) {
125
+ $fail = true;
126
+ break;
127
+
128
+ }
129
+ }
130
+ }
131
+
132
+ // No failure.
133
+ if ( ! $fail ) {
134
+
135
+ // Add widget instance
136
+ $single_widget_instances = get_option( 'widget_' . $id_base ); // All instances for that widget ID base, get fresh every time.
137
+ $single_widget_instances = ! empty( $single_widget_instances ) ? $single_widget_instances : array(
138
+ '_multiwidget' => 1, // Start fresh if have to.
139
+ );
140
+ $single_widget_instances[] = $widget; // Add it.
141
+
142
+ // Get the key it was given.
143
+ end( $single_widget_instances );
144
+ $new_instance_id_number = key( $single_widget_instances );
145
+
146
+ // If key is 0, make it 1
147
+ // When 0, an issue can occur where adding a widget causes data from other widget to load,
148
+ // and the widget doesn't stick (reload wipes it).
149
+ if ( '0' === strval( $new_instance_id_number ) ) {
150
+ $new_instance_id_number = 1;
151
+ $single_widget_instances[ $new_instance_id_number ] = $single_widget_instances[0];
152
+ unset( $single_widget_instances[0] );
153
+ }
154
+
155
+ // Move _multiwidget to end of array for uniformity.
156
+ if ( isset( $single_widget_instances['_multiwidget'] ) ) {
157
+ $multiwidget = $single_widget_instances['_multiwidget'];
158
+ unset( $single_widget_instances['_multiwidget'] );
159
+ $single_widget_instances['_multiwidget'] = $multiwidget;
160
+ }
161
+
162
+ // Update option with new widget.
163
+ update_option( 'widget_' . $id_base, $single_widget_instances );
164
+
165
+ // Assign widget instance to sidebar.
166
+ // Which sidebars have which widgets, get fresh every time.
167
+ $sidebars_widgets = get_option( 'sidebars_widgets' );
168
+
169
+ // Avoid rarely fatal error when the option is an empty string
170
+ if ( ! $sidebars_widgets ) {
171
+ $sidebars_widgets = array();
172
+ }
173
+
174
+ // Use ID number from new widget instance.
175
+ $new_instance_id = $id_base . '-' . $new_instance_id_number;
176
+
177
+ // Add new instance to sidebar.
178
+ $sidebars_widgets[ $use_sidebar_id ][] = $new_instance_id;
179
+
180
+ // Save the amended data.
181
+ update_option( 'sidebars_widgets', $sidebars_widgets );
182
+
183
+ // After widget import action.
184
+ $after_widget_import = array(
185
+ 'sidebar' => $use_sidebar_id,
186
+ 'sidebar_old' => $sidebar_id,
187
+ 'widget' => $widget,
188
+ 'widget_type' => $id_base,
189
+ 'widget_id' => $new_instance_id,
190
+ 'widget_id_old' => $widget_instance_id,
191
+ 'widget_id_num' => $new_instance_id_number,
192
+ 'widget_id_num_old' => $instance_id_number,
193
+ );
194
+ do_action( 'themeisle_ob_after_single_widget_import', $after_widget_import );
195
+
196
+ }
197
+ }
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Available widgets
203
+ *
204
+ * Gather site's widgets into array with ID base, name, etc.
205
+ * Used by export and import functions.
206
+ *
207
+ * @return array Widget information
208
+ * @global array $wp_registered_widget_updates
209
+ * @since 0.4
210
+ */
211
+ public function available_widgets() {
212
+
213
+ global $wp_registered_widget_controls;
214
+
215
+ $widget_controls = $wp_registered_widget_controls;
216
+
217
+ $available_widgets = array();
218
+
219
+ foreach ( $widget_controls as $widget ) {
220
+
221
+ // No duplicates.
222
+ if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[ $widget['id_base'] ] ) ) {
223
+ $available_widgets[ $widget['id_base'] ]['id_base'] = $widget['id_base'];
224
+ $available_widgets[ $widget['id_base'] ]['name'] = $widget['name'];
225
+ }
226
+ }
227
+
228
+ return $available_widgets;
229
+
230
+ }
231
+
232
+ }
includes/Importers/Zelle_Importer.php ADDED
@@ -0,0 +1,1016 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Import Zelle to Elementor template.
4
+ *
5
+ * @package templates-patterns-collection
6
+ */
7
+
8
+ namespace TIOB\Importers;
9
+
10
+ use WP_Error;
11
+
12
+ /**
13
+ * Class to import Zelle to an Elementor template.
14
+ *
15
+ * @package templates-patterns-collection
16
+ */
17
+ class Zelle_Importer {
18
+
19
+ /**
20
+ * The page template name.
21
+ *
22
+ * @var string
23
+ */
24
+ protected $name = 'Zelle Frontpage';
25
+
26
+ /**
27
+ * Previous theme content.
28
+ *
29
+ * @var array
30
+ */
31
+ protected $previous_theme_content = array();
32
+
33
+ /**
34
+ * Content.
35
+ *
36
+ * @var array
37
+ */
38
+ protected $content = array();
39
+
40
+ /**
41
+ * A property where we cache the content.
42
+ *
43
+ * @var array
44
+ */
45
+ protected $default_content = array();
46
+
47
+ /**
48
+ * The callback of an ajax request when the user requests an import action.
49
+ *
50
+ * @return WP_Error
51
+ */
52
+ public function import_zelle_frontpage( $template_path, $theme_slug ) {
53
+ $this->previous_theme_content = get_option( 'theme_mods_' . $theme_slug );
54
+
55
+ require_once( ABSPATH . '/wp-admin/includes/image.php' );
56
+ require_once( ABSPATH . '/wp-admin/includes/file.php' );
57
+
58
+ $local_template = $template_path;
59
+
60
+ global $wp_filesystem;
61
+
62
+ WP_Filesystem();
63
+
64
+ $data = json_decode( $wp_filesystem->get_contents( $local_template ), true );
65
+ $this->default_content = $data['content'];
66
+ $this->content = $this->default_content;
67
+
68
+ // we don't need a footer for this page
69
+ unset( $this->content[9] );
70
+
71
+ if ( empty( $data ) ) {
72
+ return new WP_Error( 'ti__ob_zelle_err_3' );
73
+ }
74
+
75
+ $this->map_bigtitle_section();
76
+ $this->map_our_focus_section();
77
+ $this->map_about_us_section();
78
+ $this->map_our_team_section();
79
+ $this->map_testimonials_section();
80
+ $this->map_ribbon_section();
81
+ $this->map_latest_news_section();
82
+ $this->map_contact_us_section();
83
+
84
+ $data['title'] = $this->name;
85
+ $data['content'] = array_values( $this->content );
86
+
87
+ require_once( ABSPATH . 'wp-admin' . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'file.php' );
88
+ $uploads = wp_upload_dir();
89
+ $path_to_file = $uploads['basedir'] . '/zelle.json';
90
+
91
+ // Mime a supported document type.
92
+ $elementor_plugin = \Elementor\Plugin::$instance;
93
+ $elementor_plugin->documents->register_document_type( 'not-supported', \Elementor\Modules\Library\Documents\Page::get_class_full_name() );
94
+
95
+ $wp_filesystem->put_contents( $path_to_file, json_encode( $data ), 0644 );
96
+
97
+ $_FILES['file']['tmp_name'] = $path_to_file;
98
+
99
+ $elementor = new \Elementor\TemplateLibrary\Source_Local;
100
+
101
+ $el_template_post = $elementor->import_template( $this->name, $path_to_file );
102
+
103
+ if ( empty( $el_template_post ) ) {
104
+ return new WP_Error( 'ti__ob_zelle_err_4' );
105
+ }
106
+
107
+ unlink( $path_to_file );
108
+ $post_id = $this->insert_page( $el_template_post[0]['template_id'] );
109
+
110
+ if ( $post_id ) {
111
+ // * Mark the import as success and update the flag option to true.
112
+ set_theme_mod( 'zelle_frontpage_was_imported', 'yes' );
113
+
114
+ update_option( 'page_on_front', $post_id );
115
+ update_option( 'show_on_front', 'page' );
116
+
117
+ set_theme_mod( 'ti_content_imported', 'yes' );
118
+
119
+ // on success we return the page url because we'll redirect to it.
120
+ return $post_id;
121
+ }
122
+
123
+ return new WP_Error( 'ti__ob_zelle_err_5' );
124
+
125
+ }
126
+
127
+ /**
128
+ * Returns the content from Our focus, Testimonials, Team and About in json format
129
+ *
130
+ * @param string $widget_ids List with widget ids.
131
+ * @param string $prefix Prefix of widgets in that sidebar.
132
+ *
133
+ * @since 1.1.51
134
+ * @access private
135
+ * @return array|string
136
+ */
137
+ private function get_sidebar_content( $widget_ids, $prefix ) {
138
+ if ( empty( $widget_ids ) ) {
139
+ return '';
140
+ }
141
+ $data_in_hestia_format = array();
142
+ $ids_to_grab = array();
143
+ foreach ( $widget_ids as $widget_id ) {
144
+ if ( strpos( $widget_id, $prefix ) !== false ) {
145
+ $short_id_transient = explode( '-', $widget_id );
146
+ $short_id = end( $short_id_transient );
147
+ array_push( $ids_to_grab, $short_id );
148
+ }
149
+ }
150
+ $all_widgets = get_option( 'widget_' . $prefix . '-widget' );
151
+ foreach ( $ids_to_grab as $key ) {
152
+ $widget_data = array();
153
+ if ( array_key_exists( $key, $all_widgets ) ) {
154
+ $current_widget = $all_widgets[ $key ];
155
+ if ( ! empty( $current_widget ) ) {
156
+ $social_repeater = array();
157
+ foreach ( $current_widget as $key => $value ) {
158
+ $repeater_key = $this->get_key( $key );
159
+ if ( ! empty( $value ) && ! empty( $repeater_key ) ) {
160
+ if ( $repeater_key === 'social_repeater' ) {
161
+ $social = $this->get_repeater_social( $key, $value );
162
+ array_push( $social_repeater, $social );
163
+ } else {
164
+ $widget_data[ $repeater_key ] = $value;
165
+ }
166
+ }
167
+ }
168
+ $widget_data['social_repeater'] = json_encode( $social_repeater );
169
+ $widget_data['choice'] = 'customizer_repeater_image';
170
+ }
171
+ }
172
+ if ( ! empty( $widget_data ) ) {
173
+ array_push( $data_in_hestia_format, $widget_data );
174
+ }
175
+ }
176
+
177
+ return json_encode( $data_in_hestia_format );
178
+ }
179
+
180
+ /**
181
+ * Return content to add to social repeater. Used for team members.
182
+ *
183
+ * @param string $social_name Name of social link.
184
+ * @param string $value Link of social.
185
+ *
186
+ * @since 1.1.51
187
+ * @access private
188
+ * @return array
189
+ */
190
+ private function get_repeater_social( $social_name, $value ) {
191
+ $result = array(
192
+ 'icon' => '',
193
+ 'link' => $value,
194
+ );
195
+ switch ( $social_name ) {
196
+ case 'fb_link':
197
+ $result['icon'] = 'fa-facebook';
198
+ break;
199
+ case 'tw_link':
200
+ $result['icon'] = 'fa-twitter';
201
+ break;
202
+ case 'bh_link':
203
+ $result['icon'] = 'fa-behance';
204
+ break;
205
+ case 'db_link':
206
+ $result['icon'] = 'fa-dribbble';
207
+ break;
208
+ case 'ln_link':
209
+ $result['icon'] = 'fa-linkedin';
210
+ break;
211
+ case 'gp_link':
212
+ $result['icon'] = 'fa-google-plus';
213
+ break;
214
+ case 'pinterest_link':
215
+ $result['icon'] = 'fa-pinterest-p';
216
+ break;
217
+ case 'tumblr_link':
218
+ $result['icon'] = 'fa-tumblr';
219
+ break;
220
+ case 'reddit_link':
221
+ $result['icon'] = 'fa-reddit-alien';
222
+ break;
223
+ case 'youtube_link':
224
+ $result['icon'] = 'fa-youtube';
225
+ break;
226
+ case 'instagram_link':
227
+ $result['icon'] = 'fa-instagram';
228
+ break;
229
+ case 'website_link':
230
+ $result['icon'] = 'fa-globe';
231
+ break;
232
+ case 'email_link':
233
+ $result['icon'] = 'fa-envelope';
234
+ break;
235
+ case 'phone_link':
236
+ $result['icon'] = 'fa-phone';
237
+ break;
238
+ case 'profile_link':
239
+ $result['icon'] = 'fa-user';
240
+ break;
241
+ }
242
+
243
+ return $result;
244
+ }
245
+
246
+ /**
247
+ * Map widgets inputs names to repeater inputs
248
+ *
249
+ * @param string $key Name of the inputs.
250
+ *
251
+ * @since 1.1.51
252
+ * @access private
253
+ * @return bool|string
254
+ */
255
+ private function get_key( $key ) {
256
+ $repeater_map = array(
257
+ 'image_url' => array( 'image_url', 'image_uri' ),
258
+ 'title' => array( 'title', 'name' ),
259
+ 'subtitle' => array( 'subtitle', 'position', 'details' ),
260
+ 'text' => array( 'text', 'description' ),
261
+ 'link' => array( 'link' ),
262
+ 'social_repeater' => array(
263
+ 'fb_link',
264
+ 'tw_link',
265
+ 'bh_link',
266
+ 'db_link',
267
+ 'ln_link',
268
+ 'gp_link',
269
+ 'pinterest_link',
270
+ 'tumblr_link',
271
+ 'reddit_link',
272
+ 'youtube_link',
273
+ 'instagram_link',
274
+ 'website_link',
275
+ 'email_link',
276
+ 'phone_link',
277
+ 'profile_link',
278
+ ),
279
+ );
280
+ foreach ( $repeater_map as $k => $v ) {
281
+ if ( in_array( $key, $v ) ) {
282
+ return $k;
283
+ }
284
+ }
285
+
286
+ return false;
287
+ }
288
+
289
+ /**
290
+ * Map the bigtitle options from Zerif theme_mod in the Elementor template.
291
+ */
292
+ function map_bigtitle_section() {
293
+ if ( isset( $this->previous_theme_content['zerif_bigtitle_show'] ) && $this->previous_theme_content['zerif_bigtitle_show'] ) {
294
+ unset( $this->content[0] );
295
+
296
+ return;
297
+ }
298
+
299
+ // background settings
300
+ if ( ! empty( $this->previous_theme_content['background_image'] ) ) {
301
+ $this->content[0]['settings']['background_image']['url'] = wp_kses_post( $this->previous_theme_content['background_image'] );
302
+ $this->content[0]['settings']['background_image']['id'] = $this->get_image_id_by_url( $this->previous_theme_content['background_image'] );
303
+ }
304
+
305
+ if ( ! empty( $this->previous_theme_content['background_position_x'] ) && ! empty( $this->previous_theme_content['background_position_y'] ) ) {
306
+ $this->content[0]['settings']['background_position'] = wp_kses_post( $this->previous_theme_content['background_position_x'] . ' ' . $this->previous_theme_content['background_position_y'] );
307
+ }
308
+
309
+ if ( ! empty( $this->previous_theme_content['background_attachment'] ) ) {
310
+ $this->content[0]['settings']['background_attachment'] = wp_kses_post( $this->previous_theme_content['background_attachment'] );
311
+ }
312
+
313
+ // big title is always first.
314
+ $data = $this->content[0]['elements'][0]['elements'];
315
+
316
+ // heading settings
317
+ $h_el = $data[0];
318
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_title'] ) ) {
319
+ $h_el['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_title'] );
320
+ } elseif ( ! empty( $this->previous_theme_content['zerif_bigtitle_title_2'] ) ) {
321
+ $h_el['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_title_2'] );
322
+ }
323
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_header_color'] ) ) {
324
+ $h_el['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_header_color'] );
325
+ }
326
+ $data[0] = $h_el;
327
+
328
+ $buttons = $data[1]['elements'];
329
+
330
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_redbutton_label'] ) ) {
331
+ $buttons[0]['elements'][0]['settings']['text'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_redbutton_label'] );
332
+ }
333
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_redbutton_label_2'] ) ) {
334
+ $buttons[1]['elements'][0]['settings']['text'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_redbutton_label_2'] );
335
+ }
336
+
337
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_redbutton_url'] ) ) {
338
+ $buttons[0]['elements'][0]['settings']['href'] = esc_url( $this->previous_theme_content['zerif_bigtitle_redbutton_url'] );
339
+ }
340
+
341
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_greenbutton_label'] ) ) {
342
+ $buttons[1]['elements'][0]['settings']['text'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_greenbutton_label'] );
343
+ }
344
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_greenbutton_url'] ) ) {
345
+ $buttons[1]['elements'][0]['settings']['href'] = esc_url( $this->previous_theme_content['zerif_bigtitle_greenbutton_url'] );
346
+ }
347
+
348
+ // first button.
349
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_1button_color'] ) ) {
350
+ $buttons[0]['elements'][0]['settings']['button_text_color'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_1button_color'] );
351
+ }
352
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_1button_color_hover'] ) ) {
353
+ $buttons[0]['elements'][0]['settings']['hover_color'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_1button_color_hover'] );
354
+ }
355
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_1button_background_color'] ) ) {
356
+ $buttons[0]['elements'][0]['settings']['background_color'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_1button_background_color'] );
357
+ }
358
+
359
+ // second button.
360
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_2button_color'] ) ) {
361
+ $buttons[1]['elements'][0]['settings']['button_text_color'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_2button_color'] );
362
+ }
363
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_2button_color_hover'] ) ) {
364
+ $buttons[1]['elements'][0]['settings']['hover_color'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_2button_color_hover'] );
365
+ }
366
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_2button_background_color'] ) ) {
367
+ $buttons[1]['elements'][0]['settings']['background_color'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_2button_background_color'] );
368
+ }
369
+ if ( ! empty( $this->previous_theme_content['zerif_bigtitle_2button_background_color_hover'] ) ) {
370
+ $buttons[1]['elements'][0]['settings']['button_background_hover_color'] = wp_kses_post( $this->previous_theme_content['zerif_bigtitle_2button_background_color_hover'] );
371
+ }
372
+
373
+ $data[1]['elements'] = $buttons;
374
+
375
+ $this->content[0]['elements'][0]['elements'] = $data;
376
+ }
377
+
378
+ /**
379
+ * Map Our focus section.
380
+ */
381
+ function map_our_focus_section() {
382
+ if ( isset( $this->previous_theme_content['zerif_ourfocus_show'] ) && $this->previous_theme_content['zerif_ourfocus_show'] ) {
383
+ unset( $this->content[1] );
384
+
385
+ return;
386
+ }
387
+
388
+ if ( ! empty( $this->previous_theme_content['zerif_ourfocus_background'] ) ) {
389
+ $this->content[1]['settings']['background_color'] = wp_kses_post( $this->previous_theme_content['zerif_ourfocus_background'] );
390
+ }
391
+
392
+ $data = $this->content[1]['elements'][0]['elements'];
393
+
394
+ if ( ! empty( $this->previous_theme_content['zerif_ourfocus_title'] ) ) {
395
+ $data[0]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_ourfocus_title'] );
396
+ }
397
+
398
+ if ( ! empty( $this->previous_theme_content['zerif_ourfocus_header'] ) ) {
399
+ $data[0]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_ourfocus_header'] );
400
+ }
401
+
402
+ if ( ! empty( $this->previous_theme_content['zerif_ourfocus_subtitle'] ) ) {
403
+ $data[1]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_ourfocus_subtitle'] );
404
+ }
405
+
406
+ $widget_ids = $this->previous_theme_content['sidebars_widgets']['data']['sidebar-ourfocus'];
407
+ if ( empty( $widget_ids ) ) {
408
+ return;
409
+ }
410
+ $content = $this->get_sidebar_content( $widget_ids, 'ctup-ads' );
411
+
412
+ $old_values = json_decode( $content, true );
413
+
414
+ if ( empty( $old_values ) ) {
415
+ return;
416
+ }
417
+
418
+ $count_features = count( $old_values );
419
+
420
+ $default_feature = $data[2]['elements'][0];
421
+
422
+ switch ( $count_features ) {
423
+ case 1:
424
+ case 3:
425
+ $column_size = 33;
426
+ break;
427
+ case 2:
428
+ $column_size = 25;
429
+ break;
430
+ default:
431
+ $column_size = round( 100 / $count_features );
432
+ };
433
+ $empty_feature = array(
434
+ 'id' => \Elementor\Utils::generate_random_string(),
435
+ 'settings' => array(
436
+ '_column_size' => $column_size,
437
+ '_inline_size' => $column_size,
438
+ ),
439
+ 'elements' => array(),
440
+ 'isInner' => true,
441
+ 'elType' => 'column',
442
+ );
443
+ $new_widgets = array();
444
+ if ( $count_features < 3 ) {
445
+ $new_widgets[] = $empty_feature;
446
+ }
447
+ foreach ( $old_values as $index_key => $widget_data ) {
448
+ $this_feature = $default_feature;
449
+
450
+ // image
451
+ if ( ! empty( $widget_data['image_url'] ) ) {
452
+ $this_feature['elements'][0]['settings']['image']['url'] = $widget_data['image_url'];
453
+ $this_feature['elements'][0]['settings']['image']['id'] = $this->get_image_id_by_url( $widget_data['image_url'] );
454
+ $this_feature['elements'][0]['settings']['image_size'] = 'thumbnail';
455
+ $this_feature['elements'][0]['settings']['link_to'] = $widget_data['link'];
456
+
457
+ if ( ! empty( $widget_data['link'] ) ) {
458
+ $this_feature['elements'][0]['settings']['link_to'] = 'custom';
459
+ $this_feature['elements'][0]['settings']['url'] = $widget_data['link'];
460
+ }
461
+
462
+ // colors: this doesn't work with anything else than exactly 4 features; disabling for the moment.
463
+ $this_feature['elements'][0]['settings']['_border_border'] = 'none';
464
+ $this_feature['elements'][0]['settings']['_border_hover_border'] = 'none';
465
+ }
466
+
467
+ // title
468
+ $this_feature['elements'][1]['settings']['title'] = $widget_data['title'];
469
+ // description
470
+ $this_feature['elements'][3]['settings']['editor'] = '<p style="text-align:center">' . $widget_data['text'] . '</p>';
471
+ // recalculate box sizes
472
+ $this_feature['settings']['_column_size'] = 25;
473
+ $this_feature['settings']['_inline_size'] = $column_size;
474
+
475
+ $this_feature['id'] = \Elementor\Utils::generate_random_string();
476
+
477
+ $new_widgets[] = $this_feature;
478
+ }
479
+ if ( $count_features < 3 ) {
480
+ $new_widgets[] = $empty_feature;
481
+ }
482
+
483
+ $data[2]['elements'] = $new_widgets;
484
+
485
+ $this->content[1]['elements'][0]['elements'] = $data;
486
+ }
487
+
488
+ /**
489
+ * Map About Us section.
490
+ */
491
+ function map_about_us_section() {
492
+ if ( isset( $this->previous_theme_content['zerif_aboutus_show'] ) && $this->previous_theme_content['zerif_aboutus_show'] ) {
493
+ unset( $this->content[3] );
494
+
495
+ return;
496
+ }
497
+
498
+ if ( ! empty( $this->previous_theme_content['zerif_aboutus_background'] ) ) {
499
+ $this->content[3]['settings']['background_color'] = wp_kses_post( $this->previous_theme_content['zerif_aboutus_background'] );
500
+ }
501
+
502
+ $data = $this->content[3]['elements'][0]['elements'];
503
+
504
+ $title = $data[0]['elements'][0]['elements'];
505
+
506
+ if ( ! empty( $this->previous_theme_content['zerif_aboutus_title'] ) ) {
507
+ $title[0]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_aboutus_title'] );
508
+ }
509
+ if ( ! empty( $this->previous_theme_content['zerif_aboutus_title_color'] ) ) {
510
+ $title[0]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_aboutus_title_color'] );
511
+ }
512
+
513
+ if ( ! empty( $this->previous_theme_content['zerif_aboutus_subtitle'] ) ) {
514
+ $title[1]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_aboutus_subtitle'] );
515
+ }
516
+
517
+ $data[0]['elements'][0]['elements'] = $title;
518
+
519
+ $content = $data[1]['elements'];
520
+
521
+ if ( ! empty( $this->previous_theme_content['zerif_aboutus_biglefttitle'] ) ) {
522
+ $content[0]['elements'][0]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_aboutus_biglefttitle'] );
523
+ }
524
+
525
+ if ( ! empty( $this->previous_theme_content['zerif_aboutus_text'] ) ) {
526
+ $content[1]['elements'][0]['settings']['editor'] = wp_kses_post( $this->previous_theme_content['zerif_aboutus_text'] );
527
+ }
528
+
529
+ $features = $content[2]['elements'];
530
+
531
+ foreach ( $features as $key => $feature ) {
532
+
533
+ if ( empty( $this->previous_theme_content[ 'zerif_aboutus_feature' . $key . '_text' ] ) ) {
534
+ continue;
535
+ }
536
+
537
+ $features[ $key ]['settings']['title_text'] = $this->previous_theme_content[ 'zerif_aboutus_feature' . $key . '_title' ];
538
+ // the `zerif_aboutus_feature1_nr` `zerif_aboutus_feature1_text` won't be imported
539
+ }
540
+
541
+ $content[2]['elements'] = $features;
542
+
543
+ $data[1]['elements'] = $content;
544
+
545
+ // we cannot import clients since they are custom widgets.
546
+ unset( $data[2] );
547
+ unset( $data[3] );
548
+
549
+ $this->content[3]['elements'][0]['elements'] = $data;
550
+ }
551
+
552
+ /**
553
+ * Map Our Team section.
554
+ */
555
+ function map_our_team_section() {
556
+ if ( isset( $this->previous_theme_content['zerif_ourteam_show'] ) && $this->previous_theme_content['zerif_ourteam_show'] ) {
557
+ unset( $this->content[4] );
558
+
559
+ return;
560
+ }
561
+
562
+ $widget_ids = $this->previous_theme_content['sidebars_widgets']['data']['sidebar-ourteam'];
563
+ if ( empty( $widget_ids ) ) {
564
+ return;
565
+ }
566
+ $content = $this->get_sidebar_content( $widget_ids, 'zerif_team' );
567
+
568
+ $old_widget = json_decode( $content, true );
569
+
570
+ if ( ! empty( $this->previous_theme_content['zerif_ourteam_background'] ) ) {
571
+ $this->content[4]['settings']['background_color'] = wp_kses_post( $this->previous_theme_content['zerif_ourteam_background'] );
572
+ }
573
+
574
+ $data = $this->content[4]['elements'][0]['elements'];
575
+
576
+ // title $data[0]
577
+ if ( ! empty( $this->previous_theme_content['zerif_ourteam_title'] ) ) {
578
+ $data[0]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_ourteam_title'] );
579
+ // now the color
580
+ if ( ! empty( $this->previous_theme_content['zerif_ourteam_header'] ) ) {
581
+ $data[0]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_ourteam_header'] );
582
+ }
583
+ }
584
+
585
+ // subtitle $data[1]
586
+ if ( ! empty( $this->previous_theme_content['zerif_ourteam_subtitle'] ) ) {
587
+ $data[1]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_ourteam_subtitle'] );
588
+ // now the color
589
+ if ( ! empty( $this->previous_theme_content['zerif_ourteam_text'] ) ) {
590
+ $data[1]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_ourteam_text'] );
591
+ }
592
+ }
593
+
594
+ if ( ! empty( $old_widget ) ) {
595
+ $widgets_nr = count( $old_widget );
596
+ $default_team = $data[2]['elements'][0];
597
+ $new_widgets = array();
598
+ foreach ( $old_widget as $index => $widget ) {
599
+ $new_team = $default_team;
600
+
601
+ if ( ! empty( $widget['image_url'] ) ) {
602
+ $new_team['elements'][0]['settings'] = $this->map_widget_image( $new_team['elements'][0]['settings'], $widget['image_url'] );
603
+ $new_team['elements'][0]['settings']['align'] = 'center';
604
+ }
605
+
606
+ $color_key = 'zerif_ourteam_' . ( $index + 1 ) . 'box';
607
+ if ( ! empty( $this->previous_theme_content[ $color_key ] ) ) {
608
+ $new_team['elements'][0]['settings']['_border_color'] = wp_kses_post( $this->previous_theme_content[ $color_key ] );
609
+ $new_team['elements'][2]['settings']['color'] = wp_kses_post( $this->previous_theme_content[ $color_key ] );
610
+ }
611
+
612
+ if ( ! empty( $widget['title'] ) ) {
613
+ $new_team['elements'][1]['settings']['title'] = $widget['title'];
614
+ }
615
+
616
+ if ( ! empty( $widget['subtitle'] ) ) {
617
+ $new_team['elements'][3]['settings']['editor'] = wp_kses_post( '<p style="text-align: center;">' . $widget['subtitle'] . '</p>' );
618
+ }
619
+
620
+ if ( ! empty( $widget['text'] ) ) {
621
+ $new_team['elements'][3]['settings']['editor'] = wp_kses_post( '<p style="text-align: center;">' . $widget['subtitle'] . '</p>' );
622
+ }
623
+
624
+ if ( ! empty( $this->previous_theme_content['zerif_ourteam_socials'] ) ) {
625
+ $new_team['elements'][4]['settings']['icon_secondary_color'] = wp_kses_post( $this->previous_theme_content['zerif_ourteam_socials'] );
626
+
627
+ if ( ! empty( $this->previous_theme_content['zerif_ourteam_socials_hover'] ) ) {
628
+ $new_team['elements'][4]['settings']['hover_secondary_color'] = wp_kses_post( $this->previous_theme_content['zerif_ourteam_socials_hover'] );
629
+ }
630
+ }
631
+
632
+ if ( ! empty( $widget['social_repeater'] ) ) {
633
+ $social_links = json_decode( $widget['social_repeater'], true );
634
+
635
+ foreach ( $social_links as $social_index => $social_link ) {
636
+ $new_link = array(
637
+ 'social' => 'fa ' . $social_link['icon'],
638
+ 'link' => array(
639
+ 'is_external' => false,
640
+ 'nofollow' => false,
641
+ 'url' => $social_link['link'],
642
+ ),
643
+ '_id' => \Elementor\Utils::generate_random_string(),
644
+ );
645
+
646
+ $new_team['elements'][4]['settings']['social_icon_list'][ $social_index ] = $new_link;
647
+ }
648
+ }
649
+
650
+ $new_team['id'] = \Elementor\Utils::generate_random_string();
651
+ $new_team['settings']['_column_size'] = round( 100 / $widgets_nr );
652
+ $new_team['settings']['_inline_size'] = round( 100 / $widgets_nr );
653
+ $new_widgets[] = $new_team;
654
+ }
655
+
656
+ $data[2]['elements'] = $new_widgets;
657
+ }
658
+
659
+ $this->content[4]['elements'][0]['elements'] = $data;
660
+ }
661
+
662
+ /**
663
+ * Map Testimonials section.
664
+ */
665
+ function map_testimonials_section() {
666
+ if ( isset( $this->previous_theme_content['zerif_testimonials_show'] ) && $this->previous_theme_content['zerif_testimonials_show'] ) {
667
+ unset( $this->content[5] );
668
+
669
+ return;
670
+ }
671
+
672
+ $data = $this->content[5]['elements'][0]['elements'];
673
+
674
+ if ( ! empty( $this->previous_theme_content['zerif_testimonials_background'] ) ) {
675
+ $this->content[5]['settings']['background_color'] = wp_kses_post( $this->previous_theme_content['zerif_testimonials_background'] );
676
+ }
677
+
678
+ if ( ! empty( $this->previous_theme_content['zerif_testimonials_title'] ) ) {
679
+ $data[0]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_testimonials_title'] );
680
+
681
+ if ( ! empty( $this->previous_theme_content['zerif_testimonials_header'] ) ) {
682
+ $data[0]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_testimonials_header'] );
683
+ }
684
+ }
685
+
686
+ if ( ! empty( $this->previous_theme_content['zerif_testimonials_subtitle'] ) ) {
687
+ $data[1]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_testimonials_subtitle'] );
688
+ }
689
+
690
+ $widget_ids = $this->previous_theme_content['sidebars_widgets']['data']['sidebar-testimonials'];
691
+ if ( empty( $widget_ids ) ) {
692
+ return;
693
+ }
694
+ $content = $this->get_sidebar_content( $widget_ids, 'zerif_testim' );
695
+
696
+ $old_data = json_decode( $content, true );
697
+
698
+ if ( ! empty( $old_data ) ) {
699
+ $default_widget = $data[2]['elements'][0];
700
+ $new_widgets = array();
701
+
702
+ $widgets_nr = count( $old_data );
703
+
704
+ foreach ( $old_data as $testimonial_index => $testimonial ) {
705
+ $this_widget = $default_widget;
706
+
707
+ // testimonial content.
708
+ if ( ! empty( $testimonial['text'] ) ) {
709
+ $this_widget['elements'][0]['settings']['editor'] = wp_kses_post( $testimonial['text'] );
710
+ }
711
+
712
+ // name
713
+ if ( ! empty( $testimonial['title'] ) ) {
714
+ $this_widget['elements'][2]['settings']['editor'] = wp_kses_post( '<p>' . $testimonial['title'] . '</p>' );
715
+ }
716
+
717
+ if ( ! empty( $testimonial['image_url'] ) ) {
718
+ $this_widget['elements'][3]['settings'] = $this->map_widget_image( $this_widget['elements'][3]['settings'], $testimonial['image_url'] );
719
+ $this_widget['elements'][3]['settings']['width']['size'] = 100;
720
+ }
721
+
722
+ // a job title?
723
+ // $this_widget['elements'][4]['settings']['icon'];
724
+ $this_widget['settings']['_column_size'] = round( 100 / $widgets_nr );
725
+
726
+ $new_widgets[] = $this_widget;
727
+ }
728
+
729
+ $data[2]['elements'] = $new_widgets;
730
+ }
731
+
732
+ $this->content[5]['elements'][0]['elements'] = $data;
733
+ }
734
+
735
+ /**
736
+ * Map Ribbons section.
737
+ */
738
+ function map_ribbon_section() {
739
+ if ( ! empty( $this->previous_theme_content['zerif_ribbon_background'] ) ) {
740
+ $this->content[2]['settings']['background_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbon_background'] );
741
+ }
742
+
743
+ if ( ! empty( $this->previous_theme_content['zerif_ribbonright_background'] ) ) {
744
+ $this->content[6]['settings']['background_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbonright_background'] );
745
+ }
746
+
747
+ // plain ribbon
748
+ $ribbon = $this->content[2]['elements'][0]['elements'];
749
+
750
+ if ( ! empty( $this->previous_theme_content['zerif_bottomribbon_text'] ) ) {
751
+ $ribbon[0]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_bottomribbon_text'] );
752
+ }
753
+ if ( ! empty( $this->previous_theme_content['zerif_ribbon_text_color'] ) ) {
754
+ $ribbon[0]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbon_text_color'] );
755
+ }
756
+ if ( ! empty( $this->previous_theme_content['zerif_ribbon_text_color'] ) ) {
757
+ $ribbon[0]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbon_text_color'] );
758
+ }
759
+
760
+ if ( ! empty( $this->previous_theme_content['zerif_bottomribbon_buttonlabel'] ) ) {
761
+ $ribbon[1]['settings']['text'] = wp_kses_post( $this->previous_theme_content['zerif_bottomribbon_buttonlabel'] );
762
+ }
763
+ if ( ! empty( $this->previous_theme_content['zerif_bottomribbon_buttonlink'] ) ) {
764
+ $ribbon[1]['settings']['url'] = wp_kses_post( $this->previous_theme_content['zerif_bottomribbon_buttonlink'] );
765
+ }
766
+ if ( ! empty( $this->previous_theme_content['zerif_ribbon_button_background'] ) ) {
767
+ $ribbon[1]['settings']['background_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbon_button_background'] );
768
+ }
769
+ if ( ! empty( $this->previous_theme_content['zerif_ribbon_button_background_hover'] ) ) {
770
+ $ribbon[1]['settings']['button_background_hover_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbon_button_background_hover'] );
771
+ }
772
+ if ( ! empty( $this->previous_theme_content['zerif_ribbon_button_button_color'] ) ) {
773
+ $ribbon[1]['settings']['button_text_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbon_button_button_color'] );
774
+ }
775
+
776
+ $this->content[2]['elements'][0]['elements'] = $ribbon;
777
+
778
+ // right ribbon.
779
+ $right_ribbon = $this->content[6]['elements'];
780
+
781
+ if ( ! empty( $this->previous_theme_content['zerif_ribbonright_text'] ) ) {
782
+ $right_ribbon[0]['elements'][0]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_ribbonright_text'] );
783
+ }
784
+ if ( ! empty( $this->previous_theme_content['zerif_ribbonright_text_color'] ) ) {
785
+ $right_ribbon[0]['elements'][0]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbonright_text_color'] );
786
+ }
787
+
788
+ if ( ! empty( $this->previous_theme_content['zerif_ribbonright_buttonlabel'] ) ) {
789
+ $right_ribbon[1]['elements'][0]['settings']['text'] = wp_kses_post( $this->previous_theme_content['zerif_ribbonright_buttonlabel'] );
790
+ }
791
+ if ( ! empty( $this->previous_theme_content['zerif_ribbonright_buttonlink'] ) ) {
792
+ $right_ribbon[1]['elements'][0]['settings']['url'] = wp_kses_post( $this->previous_theme_content['zerif_ribbonright_buttonlink'] );
793
+ }
794
+ if ( ! empty( $this->previous_theme_content['zerif_ribbonright_button_background'] ) ) {
795
+ $right_ribbon[1]['elements'][0]['settings']['background_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbonright_button_background'] );
796
+ }
797
+ if ( ! empty( $this->previous_theme_content['zerif_ribbonright_button_background_hover'] ) ) {
798
+ $right_ribbon[1]['elements'][0]['settings']['button_background_hover_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbonright_button_background_hover'] );
799
+ }
800
+ if ( ! empty( $this->previous_theme_content['zerif_ribbonright_button_background_hover'] ) ) {
801
+ $right_ribbon[1]['elements'][0]['settings']['button_background_hover_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbonright_button_background_hover'] );
802
+ }
803
+ if ( ! empty( $this->previous_theme_content['zerif_ribbonright_button_button_color'] ) ) {
804
+ $right_ribbon[1]['elements'][0]['settings']['button_text_color'] = wp_kses_post( $this->previous_theme_content['zerif_ribbonright_button_button_color'] );
805
+ }
806
+
807
+ $this->content[6]['elements'] = $right_ribbon;
808
+ }
809
+
810
+ /**
811
+ * Map latest news.
812
+ */
813
+ function map_latest_news_section() {
814
+ if ( ! isset( $this->previous_theme_content['zerif_latest_news_show'] ) || ! $this->previous_theme_content['zerif_latest_news_show'] ) {
815
+ unset( $this->content[7] );
816
+
817
+ return;
818
+ }
819
+
820
+ if ( ! empty( $this->previous_theme_content['zerif_latestnews_background'] ) ) {
821
+ $this->content[7]['settings']['background_color'] = wp_kses_post( $this->previous_theme_content['zerif_latestnews_background'] );
822
+ }
823
+
824
+ $data = $this->content[7]['elements'][0]['elements'];
825
+
826
+ // title
827
+ if ( ! empty( $this->previous_theme_content['zerif_latestnews_title'] ) ) {
828
+ $data[0]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_latestnews_title'] );
829
+
830
+ if ( ! empty( $this->previous_theme_content['zerif_latestnews_header_title_color'] ) ) {
831
+ $data[0]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_latestnews_header_title_color'] );
832
+ }
833
+ }
834
+
835
+ // subtitle
836
+ if ( ! empty( $this->previous_theme_content['zerif_latestnews_subtitle'] ) ) {
837
+ $data[1]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_latestnews_subtitle'] );
838
+
839
+ if ( ! empty( $this->previous_theme_content['zerif_latestnews_header_subtitle_color'] ) ) {
840
+ $data[1]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_latestnews_header_subtitle_color'] );
841
+ }
842
+ }
843
+
844
+ // latest posts widget
845
+ if ( ! empty( $this->previous_theme_content['zerif_latestnews_post_title_color'] ) ) {
846
+ $data[2]['settings']['grid_title_style_color'] = wp_kses_post( $this->previous_theme_content['zerif_latestnews_post_title_color'] );
847
+ }
848
+ if ( ! empty( $this->previous_theme_content['zerif_latestnews_post_text_color'] ) ) {
849
+ $data[2]['settings']['grid_content_style_color'] = wp_kses_post( $this->previous_theme_content['zerif_latestnews_post_text_color'] );
850
+ }
851
+
852
+ $this->content[7]['elements'][0]['elements'] = $data;
853
+ }
854
+
855
+ /**
856
+ * Map Contact us section.
857
+ */
858
+ function map_contact_us_section() {
859
+ if ( isset( $this->previous_theme_content['zerif_contactus_show'] ) && $this->previous_theme_content['zerif_contactus_show'] ) {
860
+ unset( $this->content[0] );
861
+
862
+ return;
863
+ }
864
+ $data = $this->content[8]['elements'][0]['elements'];
865
+
866
+ if ( ! empty( $this->previous_theme_content['zerif_contactus_title'] ) ) {
867
+ $data[0]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_contactus_title'] );
868
+ if ( ! empty( $this->previous_theme_content['zerif_contacus_header'] ) ) {
869
+ $data[0]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_contacus_header'] );
870
+ }
871
+ }
872
+
873
+ if ( ! empty( $this->previous_theme_content['zerif_contactus_subtitle'] ) ) {
874
+ $data[1]['settings']['title'] = wp_kses_post( $this->previous_theme_content['zerif_contactus_subtitle'] );
875
+ if ( ! empty( $this->previous_theme_content['zerif_contacus_header'] ) ) {
876
+ $data[0]['settings']['title_color'] = wp_kses_post( $this->previous_theme_content['zerif_contacus_header'] );
877
+ }
878
+ }
879
+
880
+ if ( ! empty( $this->previous_theme_content['zerif_contactus_email'] ) ) {
881
+ $data[2]['settings']['to_send_email'] = wp_kses_post( $this->previous_theme_content['zerif_contactus_email'] );
882
+ }
883
+
884
+ if ( ! empty( $this->previous_theme_content['zerif_contactus_button_label'] ) ) {
885
+ $data[2]['settings']['submit_label'] = wp_kses_post( $this->previous_theme_content['zerif_contactus_button_label'] );
886
+ }
887
+
888
+ if ( ! empty( $this->previous_theme_content['zerif_contactus_name_placeholder'] ) ) {
889
+ $data[2]['settings']['form_fields'][0]['placeholder'] = wp_kses_post( $this->previous_theme_content['zerif_contactus_name_placeholder'] );
890
+ }
891
+ if ( ! empty( $this->previous_theme_content['zerif_contactus_email_placeholder'] ) ) {
892
+ $data[2]['settings']['form_fields'][1]['placeholder'] = wp_kses_post( $this->previous_theme_content['zerif_contactus_email_placeholder'] );
893
+ }
894
+ if ( ! empty( $this->previous_theme_content['zerif_contactus_subject_placeholder'] ) ) {
895
+ $data[2]['settings']['form_fields'][2]['placeholder'] = wp_kses_post( $this->previous_theme_content['zerif_contactus_message_placeholder'] );
896
+ $data[2]['settings']['form_fields'][2]['key'] = 'subject';
897
+ $data[2]['settings']['form_fields'][2]['type'] = 'text';
898
+ }
899
+ if ( ! empty( $this->previous_theme_content['zerif_contactus_message_placeholder'] ) ) {
900
+ $data[2]['settings']['form_fields'][3]['placeholder'] = wp_kses_post( $this->previous_theme_content['zerif_contactus_message_placeholder'] );
901
+ }
902
+
903
+ $this->content[8]['elements'][0]['elements'] = $data;
904
+ }
905
+
906
+ /**
907
+ * This function maps a image id and url to an Elementor widget array and it returns the mapped array.
908
+ *
909
+ * @param array $widget The element array.
910
+ * @param string $url The image url to import.
911
+ *
912
+ * @return array
913
+ */
914
+ function map_widget_image( $widget, $url ) {
915
+ $widget['image']['url'] = $url;
916
+ $widget['image']['id'] = $this->get_image_id_by_url( $url );
917
+ $widget['image_size'] = 'thumbnail';
918
+
919
+ return $widget;
920
+ }
921
+
922
+ /**
923
+ * Returns the attachment id for an certain attachment url.
924
+ *
925
+ * @param string $attachment_url The attachment url for which we search the id.
926
+ *
927
+ * @return bool|null|string|void
928
+ */
929
+ function get_image_id_by_url( $attachment_url = '' ) {
930
+ global $wpdb;
931
+ $attachment_id = false;
932
+
933
+ // If there is no url, return.
934
+ if ( '' == $attachment_url ) {
935
+ return;
936
+ }
937
+
938
+ // Get the upload directory paths
939
+ $upload_dir_paths = wp_upload_dir();
940
+
941
+ // Make sure the upload path base directory exists in the attachment URL, to verify that we're working with a media library image
942
+ if ( false !== strpos( $attachment_url, $upload_dir_paths['baseurl'] ) ) {
943
+
944
+ // If this is the URL of an auto-generated thumbnail, get the URL of the original image
945
+ $attachment_url = preg_replace( '/-\d+x\d+(?=\.(jpg|jpeg|png|gif)$)/i', '', $attachment_url );
946
+
947
+ // Remove the upload path base directory from the attachment URL
948
+ $attachment_url = str_replace( $upload_dir_paths['baseurl'] . '/', '', $attachment_url );
949
+
950
+ // Finally, run a custom database query to get the attachment ID from the modified attachment URL
951
+ $attachment_id = $wpdb->get_var( $wpdb->prepare( "SELECT wposts.ID FROM $wpdb->posts wposts, $wpdb->postmeta wpostmeta WHERE wposts.ID = wpostmeta.post_id AND wpostmeta.meta_key = '_wp_attached_file' AND wpostmeta.meta_value = %s AND wposts.post_type = 'attachment'", $attachment_url ) );
952
+
953
+ }
954
+
955
+ return $attachment_id;
956
+ }
957
+
958
+ /**
959
+ * This method seeks for the imported Elementor template and creates a page based on it's content.
960
+ *
961
+ * @param number $id The Elementor template id.
962
+ *
963
+ * @return bool|int
964
+ */
965
+ private function insert_page( $id ) {
966
+ $args = array(
967
+ 'post_type' => 'elementor_library',
968
+ 'nopaging' => true,
969
+ 'posts_per_page' => '1',
970
+ 'suppress_filters' => true,
971
+ 'post__in' => array( $id ),
972
+ );
973
+
974
+ $query = new \WP_Query( $args );
975
+
976
+ $last_template_added = $query->posts[0];
977
+ // get template id
978
+ $template_id = $last_template_added->ID;
979
+
980
+ wp_reset_query();
981
+ wp_reset_postdata();
982
+
983
+ // page content
984
+ $page_content = $last_template_added->post_content;
985
+ // meta fields
986
+ $elementor_data_meta = get_post_meta( $template_id, '_elementor_data' );
987
+ $elementor_ver_meta = get_post_meta( $template_id, '_elementor_version' );
988
+ $elementor_edit_mode_meta = get_post_meta( $template_id, '_elementor_edit_mode' );
989
+ $elementor_css_meta = get_post_meta( $template_id, '_elementor_css' );
990
+ $elementor_metas = array(
991
+ '_elementor_data' => ! empty( $elementor_data_meta[0] ) ? wp_slash( $elementor_data_meta[0] ) : '',
992
+ '_elementor_version' => ! empty( $elementor_ver_meta[0] ) ? $elementor_ver_meta[0] : '',
993
+ '_elementor_edit_mode' => ! empty( $elementor_edit_mode_meta[0] ) ? $elementor_edit_mode_meta[0] : '',
994
+ '_elementor_css' => $elementor_css_meta,
995
+ );
996
+
997
+ // Create post object
998
+ $new_template_page = array(
999
+ 'post_type' => 'page',
1000
+ 'post_title' => $this->name,
1001
+ 'post_status' => 'publish',
1002
+ 'post_content' => $page_content,
1003
+ 'meta_input' => $elementor_metas,
1004
+ 'page_template' => apply_filters( 'template_directory_default_template', 'page-templates/template-pagebuilder-full-width.php' ),
1005
+ );
1006
+
1007
+ // * Insert a new page.
1008
+ $post_id = wp_insert_post( $new_template_page );
1009
+
1010
+ if ( is_wp_error( $post_id ) ) {
1011
+ return false;
1012
+ }
1013
+
1014
+ return $post_id;
1015
+ }
1016
+ }
includes/Logger.php ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Onboarding Logger.
4
+ *
5
+ * @package templates-patterns-collection
6
+ */
7
+
8
+ namespace TIOB;
9
+
10
+ /**
11
+ * Class Logger
12
+ */
13
+ class Logger {
14
+
15
+ /**
16
+ * Emojis mapped for each case.
17
+ *
18
+ * @var array
19
+ */
20
+ private $icon_map = array(
21
+ 'success' => 'S',
22
+ 'warning' => 'W',
23
+ 'progress' => 'P',
24
+ 'error' => 'E',
25
+ 'generic' => '-',
26
+ 'info' => 'I',
27
+ );
28
+
29
+ /**
30
+ * Log file path.
31
+ *
32
+ * @var string
33
+ */
34
+ private $log_file_path;
35
+
36
+ /**
37
+ * Log file path url.
38
+ *
39
+ * @var string
40
+ */
41
+ private $log_file_path_url;
42
+
43
+ /**
44
+ * Log file name
45
+ *
46
+ * @var string
47
+ */
48
+ private $log_file_name = 'ti_theme_onboarding.log';
49
+
50
+ /**
51
+ * @var string
52
+ */
53
+ private $log_string = '';
54
+
55
+ /**
56
+ * @var Logger
57
+ */
58
+ private static $_instance;
59
+
60
+ /**
61
+ * Logger constructor.
62
+ */
63
+ public function __construct() {
64
+ if ( ! defined( 'TI_OB_DEBUG_LOG' ) ) {
65
+ define( 'TI_OB_DEBUG_LOG', true );
66
+ }
67
+
68
+ if ( TI_OB_DEBUG_LOG !== true ) {
69
+ return;
70
+ }
71
+ require_once( ABSPATH . 'wp-admin/includes/file.php' ); // you have to load this file
72
+ add_action( 'shutdown', array( $this, 'log_to_file' ) );
73
+ $this->set_log_path();
74
+ $this->clear_log();
75
+ $this->log_client_info();
76
+ }
77
+
78
+ /**
79
+ * Log info.
80
+ *
81
+ * @param string $label log label.
82
+ * @param string $value log value.
83
+ */
84
+ public function log_info( $label, $value = null ) {
85
+ if ( $value === null ) {
86
+ $this->log( "{$label}", 'info' );
87
+
88
+ return;
89
+ }
90
+ $this->log( "{$label} : {$value}", 'info' );
91
+ }
92
+
93
+ /**
94
+ * Log client info for debug purposes.
95
+ */
96
+ private function log_client_info() {
97
+ $this->log_info( "WordPress Instance Info:\n" );
98
+ $this->log_info( 'Home URL', home_url() );
99
+ $this->log_info( 'Site URL', site_url() );
100
+ $this->log_info( 'WordPress Version', get_bloginfo( 'version' ) );
101
+ $this->log_info( 'Onboarding Version', Main::VERSION );
102
+ $this->log_info( 'Multisite', is_multisite() ? 'Yes' : 'No' );
103
+ $this->log_info( 'Server Info', isset( $_SERVER['SERVER_SOFTWARE'] ) ? wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) : '' );
104
+ $this->log_info( 'PHP Version', phpversion() );
105
+ $this->log_info( 'HTTPS', is_ssl() ? 'Yes' : 'No' );
106
+ $this->log_info( 'PHP Max Execution Time', ini_get( 'max_execution_time' ) );
107
+ $this->log_info( 'PHP Max Input Vars', ini_get( 'max_input_vars' ) );
108
+ $this->log_info( 'Max Upload Size', wp_max_upload_size() );
109
+ $this->log_info( 'Plugins:' );
110
+ foreach ( $this->get_plugins() as $plugin ) {
111
+ $author = strip_tags( $plugin['Author'] );
112
+ $this->log_info( '[PLUGIN] ' . $plugin['Name'], 'v' . $plugin['Version'] . " ({$author}) " );
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Get active plugins.
118
+ *
119
+ * @return array
120
+ */
121
+ private function get_plugins() {
122
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
123
+ $active_plugins = (array) get_option( 'active_plugins', array() );
124
+ if ( is_multisite() ) {
125
+ $network_activated_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
126
+ $active_plugins = array_merge( $active_plugins, $network_activated_plugins );
127
+ }
128
+
129
+ $active_plugins_data = array();
130
+ foreach ( $active_plugins as $plugin ) {
131
+ $data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
132
+ $active_plugins_data[] = $data;
133
+ }
134
+
135
+ return $active_plugins_data;
136
+ }
137
+
138
+ /**
139
+ * Returns the instance of the class.
140
+ *
141
+ * @return Logger
142
+ */
143
+ public static function get_instance() {
144
+ if ( null === self::$_instance ) {
145
+ self::$_instance = new self();
146
+ }
147
+
148
+ return self::$_instance;
149
+ }
150
+
151
+ /**
152
+ * Set the log path.
153
+ */
154
+ private function set_log_path() {
155
+ $wp_upload_dir = wp_upload_dir( null, false );
156
+ $this->log_file_path = $wp_upload_dir['basedir'] . DIRECTORY_SEPARATOR;
157
+
158
+ if ( ! is_dir( $this->log_file_path ) ) {
159
+ wp_mkdir_p( $this->log_file_path );
160
+ }
161
+
162
+ $this->log_file_path_url = $wp_upload_dir['baseurl'] . DIRECTORY_SEPARATOR;
163
+ }
164
+
165
+ /**
166
+ * Clear the log file.
167
+ */
168
+ private function clear_log() {
169
+ if ( is_writable( $this->log_file_path . $this->log_file_name ) ) {
170
+ unlink( $this->log_file_path . $this->log_file_name );
171
+ }
172
+ global $wp_filesystem;
173
+ WP_Filesystem();
174
+ $wp_filesystem->put_contents( $this->log_file_path . $this->log_file_name, '', 0644 );
175
+ }
176
+
177
+ /**
178
+ * Log entry.
179
+ *
180
+ * @param string $message log message.
181
+ * @param string $type log type.
182
+ */
183
+ public function log( $message = 'No message provided.', $type = 'error' ) {
184
+ $log_entry = array(
185
+ 'message' => $message,
186
+ 'type' => array_key_exists( $type, $this->icon_map ) ? $this->icon_map[ $type ] : $this->icon_map['generic'],
187
+ 'time' => gmdate( '[d/M/Y:H:i:s]' ),
188
+ );
189
+ $this->log_string .= $this->get_log_entry( $log_entry );
190
+ }
191
+
192
+ /**
193
+ * Log to file.
194
+ */
195
+ public function log_to_file() {
196
+ $log_file = $this->log_file_path . $this->log_file_name;
197
+ global $wp_filesystem;
198
+ WP_Filesystem();
199
+ $content = file_exists( $log_file ) ? $wp_filesystem->get_contents( $log_file ) : '';
200
+ $content .= $this->log_string;
201
+ $wp_filesystem->put_contents( $log_file, $content, 0644 );
202
+ }
203
+
204
+ /**
205
+ * Get the formatted log entry.
206
+ *
207
+ * @return string
208
+ */
209
+ private function get_log_entry( $log_entry ) {
210
+ if ( ! is_string( $log_entry['message'] ) ) {
211
+ $log_entry['message'] = json_encode( $log_entry['message'] );
212
+ }
213
+
214
+ return trim( preg_replace( '/\s\s+/', ' ', "{$log_entry['time']} ({$log_entry['type']}): {$log_entry['message']}" ) ) . PHP_EOL;
215
+ }
216
+
217
+ /**
218
+ * Get the log URL.
219
+ */
220
+ public function get_log_url() {
221
+ return $this->log_file_path_url . $this->log_file_name;
222
+ }
223
+ }
includes/Main.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Theme Onboarding
4
+ *
5
+ * @package templates-patterns-collection
6
+ */
7
+
8
+ namespace TIOB;
9
+
10
+ /**
11
+ * Class Main
12
+ */
13
+ class Main {
14
+ /**
15
+ * The version of this library
16
+ *
17
+ * @var string Version string.
18
+ */
19
+ const VERSION = '1.0.7';
20
+ /**
21
+ * Sites Library API URL.
22
+ *
23
+ * @var string API root string.
24
+ */
25
+ const API_ROOT = 'ti-sites-lib/v1';
26
+ /**
27
+ * Storage for the remote fetched info.
28
+ *
29
+ * @var string Transient slug.
30
+ */
31
+ const STORAGE_TRANSIENT = 'themeisle_sites_library_data';
32
+ /**
33
+ * Onboarding Path Relative to theme dir.
34
+ *
35
+ * @var string Onboarding root path.
36
+ */
37
+ const OBOARDING_PATH = '/vendor/codeinwp/themeisle-onboarding';
38
+ /**
39
+ * Main
40
+ *
41
+ * @var Main
42
+ */
43
+ protected static $instance = null;
44
+ /**
45
+ * Admin
46
+ *
47
+ * @var Admin
48
+ */
49
+ public $admin = null;
50
+
51
+ /**
52
+ * Sites listing
53
+ *
54
+ * @var Sites_Listing
55
+ */
56
+ private $sites_listing = null;
57
+
58
+ /**
59
+ * Method to return path to child class in a Reflective Way.
60
+ *
61
+ * @return string
62
+ * @since 1.0.0
63
+ * @access public
64
+ */
65
+ static public function get_dir() {
66
+ return apply_filters( 'themeisle_site_import_uri', trailingslashit( get_template_directory_uri() ) . self::OBOARDING_PATH );
67
+ }
68
+
69
+ /**
70
+ * Instantiate the class.
71
+ *
72
+ * @static
73
+ * @return Main
74
+ * @since 1.0.0
75
+ * @access public
76
+ */
77
+ public static function instance() {
78
+ if ( is_null( self::$instance ) ) {
79
+ self::$instance = new self();
80
+ self::$instance->init();
81
+ }
82
+
83
+ return self::$instance;
84
+ }
85
+
86
+ /**
87
+ * Holds the sites data.
88
+ *
89
+ * @var null
90
+ */
91
+ private function init() {
92
+ $this->setup_sites_listing();
93
+
94
+ if ( ! $this->should_load() ) {
95
+ return;
96
+ }
97
+ $this->setup_admin();
98
+ $this->setup_api();
99
+ }
100
+
101
+ /**
102
+ * Utility to check if sites library should be loaded.
103
+ *
104
+ * @return bool
105
+ */
106
+ private function should_load() {
107
+ if ( ! current_user_can( 'manage_options' ) ) {
108
+ return false;
109
+ }
110
+
111
+ return true;
112
+ }
113
+
114
+ /**
115
+ * Setup sites listing.
116
+ *
117
+ * @return void
118
+ */
119
+ private function setup_sites_listing() {
120
+ if ( ! defined( 'NEVE_VERSION' ) ) {
121
+ return;
122
+ }
123
+ $this->sites_listing = new Sites_Listing();
124
+ $this->sites_listing->init();
125
+ }
126
+
127
+ /**
128
+ * Setup admin functionality.
129
+ *
130
+ * @return void
131
+ */
132
+ private function setup_admin() {
133
+ $this->admin = new Admin();
134
+ $this->admin->init();
135
+ }
136
+
137
+ /**
138
+ * Setup the restful functionality.
139
+ *
140
+ *
141
+ * @return void
142
+ */
143
+ private function setup_api() {
144
+ $api = new Rest_Server();
145
+ $api->init();
146
+ }
147
+
148
+ /**
149
+ * Disallow object clone
150
+ *
151
+ * @access public
152
+ * @return void
153
+ * @since 1.0.0
154
+ */
155
+ public function __clone() {
156
+ }
157
+
158
+ /**
159
+ * Disable un-serializing
160
+ *
161
+ * @access public
162
+ * @return void
163
+ * @since 1.0.0
164
+ */
165
+ public function __wakeup() {
166
+ }
167
+ }
includes/Rest_Server.php ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Rest Endpoints Handler.
4
+ *
5
+ * @package templates-patterns-collection
6
+ */
7
+
8
+ namespace TIOB;
9
+
10
+ use TIOB\Importers\Content_Importer;
11
+ use TIOB\Importers\Plugin_Importer;
12
+ use TIOB\Importers\Theme_Mods_Importer;
13
+ use TIOB\Importers\Widgets_Importer;
14
+ use TIOB\Importers\Zelle_Importer;
15
+ use WP_REST_Request;
16
+ use WP_REST_Response;
17
+ use WP_REST_Server;
18
+
19
+ /**
20
+ * Class Rest_Server
21
+ */
22
+ class Rest_Server {
23
+ /**
24
+ * Initialize the rest functionality.
25
+ */
26
+ public function init() {
27
+ add_action( 'rest_api_init', array( $this, 'register_endpoints' ) );
28
+ }
29
+
30
+ /**
31
+ * Register endpoints.
32
+ */
33
+ public function register_endpoints() {
34
+ register_rest_route(
35
+ Main::API_ROOT,
36
+ '/refresh_sites_data',
37
+ array(
38
+ 'methods' => WP_REST_Server::READABLE,
39
+ 'callback' => array( $this, 'get_sites_data' ),
40
+ 'permission_callback' => function () {
41
+ return current_user_can( 'manage_options' );
42
+ },
43
+ )
44
+ );
45
+
46
+ register_rest_route(
47
+ Main::API_ROOT,
48
+ '/install_plugins',
49
+ array(
50
+ 'methods' => WP_REST_Server::EDITABLE,
51
+ 'callback' => array( $this, 'run_plugin_importer' ),
52
+ 'permission_callback' => function () {
53
+ return current_user_can( 'manage_options' );
54
+ },
55
+ )
56
+ );
57
+
58
+ register_rest_route(
59
+ Main::API_ROOT,
60
+ '/import_content',
61
+ array(
62
+ 'methods' => WP_REST_Server::EDITABLE,
63
+ 'callback' => array( $this, 'run_xml_importer' ),
64
+ 'permission_callback' => function () {
65
+ return current_user_can( 'manage_options' );
66
+ },
67
+ )
68
+ );
69
+ register_rest_route(
70
+ Main::API_ROOT,
71
+ '/import_theme_mods',
72
+ array(
73
+ 'methods' => WP_REST_Server::EDITABLE,
74
+ 'callback' => array( $this, 'run_theme_mods_importer' ),
75
+ 'permission_callback' => function () {
76
+ return current_user_can( 'manage_options' );
77
+ },
78
+ )
79
+ );
80
+ register_rest_route(
81
+ Main::API_ROOT,
82
+ '/import_widgets',
83
+ array(
84
+ 'methods' => WP_REST_Server::EDITABLE,
85
+ 'callback' => array( $this, 'run_widgets_importer' ),
86
+ 'permission_callback' => function () {
87
+ return current_user_can( 'manage_options' );
88
+ },
89
+ )
90
+ );
91
+ register_rest_route(
92
+ Main::API_ROOT,
93
+ '/migrate_frontpage',
94
+ array(
95
+ 'methods' => WP_REST_Server::EDITABLE,
96
+ 'callback' => array( $this, 'run_front_page_migration' ),
97
+ 'permission_callback' => function () {
98
+ return current_user_can( 'manage_options' );
99
+ },
100
+ )
101
+ );
102
+ register_rest_route(
103
+ Main::API_ROOT,
104
+ '/dismiss_migration',
105
+ array(
106
+ 'methods' => WP_REST_Server::EDITABLE,
107
+ 'callback' => array( $this, 'dismiss_migration' ),
108
+ 'permission_callback' => function () {
109
+ return current_user_can( 'manage_options' );
110
+ },
111
+ )
112
+ );
113
+ }
114
+
115
+ /**
116
+ * Refreshes the sites data.
117
+ */
118
+ public function get_sites_data() {
119
+ return new WP_REST_Response(
120
+ array(
121
+ 'success' => true,
122
+ 'data' => Main::instance()->admin->get_sites_data(),
123
+ )
124
+ );
125
+ }
126
+
127
+ /**
128
+ * Run the plugin importer.
129
+ *
130
+ * @param WP_REST_Request $request the async request.
131
+ *
132
+ * @return WP_REST_Response
133
+ */
134
+ public function run_plugin_importer( WP_REST_Request $request ) {
135
+ $plugin_importer = new Plugin_Importer();
136
+ return $plugin_importer->install_plugins( $request );
137
+ }
138
+
139
+ /**
140
+ * Run the XML importer.
141
+ *
142
+ * @param WP_REST_Request $request the async request.
143
+ *
144
+ * @return WP_REST_Response
145
+ */
146
+ public function run_xml_importer( WP_REST_Request $request ) {
147
+ $content_importer = new Content_Importer();
148
+ return $content_importer->import_remote_xml( $request );
149
+ }
150
+
151
+ /**
152
+ * Run the theme mods importer.
153
+ *
154
+ * @param WP_REST_Request $request the async request.
155
+ *
156
+ * @return WP_REST_Response
157
+ */
158
+ public function run_theme_mods_importer( WP_REST_Request $request ) {
159
+ $customizer_importer = new Theme_Mods_Importer();
160
+ return $customizer_importer->import_theme_mods( $request );
161
+ }
162
+
163
+ /**
164
+ * Run the widgets importer.
165
+ *
166
+ * @param WP_REST_Request $request the async request.
167
+ *
168
+ * @return WP_REST_Response
169
+ */
170
+ public function run_widgets_importer( WP_REST_Request $request ) {
171
+ $widgets_importer = new Widgets_Importer();
172
+ $import = $widgets_importer->import_widgets( $request );
173
+
174
+ set_theme_mod( 'ti_content_imported', 'yes' );
175
+
176
+ return $import;
177
+ }
178
+
179
+ /**
180
+ * Run front page migration.
181
+ *
182
+ * @param WP_REST_Request $request
183
+ *
184
+ * @return WP_REST_Response
185
+ */
186
+ public function run_front_page_migration( WP_REST_Request $request ) {
187
+ $params = $request->get_json_params();
188
+
189
+ if ( ! isset( $params['template'] ) || ! isset( $params['template_name'] ) ) {
190
+ return new WP_REST_Response(
191
+ array(
192
+ 'data' => 'ti__ob_rest_err_5',
193
+ 'success' => false,
194
+ )
195
+ );
196
+ }
197
+
198
+ $migrator = new Zelle_Importer();
199
+ $old_theme = get_theme_mod( 'ti_prev_theme', 'ti_onboarding_undefined' );
200
+ $import = $migrator->import_zelle_frontpage( $params['template'], $old_theme );
201
+
202
+ if ( is_wp_error( $import ) ) {
203
+ return new WP_REST_Response(
204
+ array(
205
+ 'data' => $import->get_error_code(),
206
+ 'success' => false,
207
+ )
208
+ );
209
+ }
210
+
211
+ return new WP_REST_Response(
212
+ array(
213
+ 'success' => true,
214
+ 'data' => $import,
215
+ )
216
+ );
217
+ }
218
+
219
+ /**
220
+ * Dismiss the front page migration notice.
221
+ *
222
+ * @param WP_REST_Request $request
223
+ *
224
+ * @return WP_REST_Response
225
+ */
226
+ public function dismiss_migration( WP_REST_Request $request ) {
227
+ $params = $request->get_json_params();
228
+ if ( ! isset( $params['theme_mod'] ) ) {
229
+ return new WP_REST_Response(
230
+ array(
231
+ 'data' => 'ti__ob_rest_err_8',
232
+ 'success' => false,
233
+ )
234
+ );
235
+ }
236
+ set_theme_mod( $params['theme_mod'], 'yes' );
237
+
238
+ return new WP_REST_Response( array( 'success' => true ) );
239
+ }
240
+ }
includes/Sites_Listing.php ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Theme Onboarding Sites_Listing
4
+ *
5
+ * @package templates-patterns-collection
6
+ */
7
+
8
+ namespace TIOB;
9
+
10
+ /**
11
+ * Class Sites_Listing
12
+ */
13
+ class Sites_Listing {
14
+
15
+ /**
16
+ * Sites Listing API URL
17
+ */
18
+ const API = 'https://demosites.io/wp-json/demosites-api/sites';
19
+
20
+ /**
21
+ * Key of transient where we save the sites list.
22
+ *
23
+ * @var string
24
+ */
25
+ private $transient_key = 'tiob_sites';
26
+
27
+ /**
28
+ * The onboarding config.
29
+ *
30
+ * @var array
31
+ */
32
+ private $onboarding_config = array();
33
+
34
+ /**
35
+ * Initialize the Class.
36
+ */
37
+ public function init() {
38
+ $this->onboarding_config = array(
39
+ 'remote' => $this->get_sites(),
40
+ 'upsell' => array(),
41
+ 'can_migrate' => array(
42
+ 'zerif-pro' => array(
43
+ 'theme_name' => 'Zelle Pro',
44
+ 'theme_mod_check' => 'zelle_frontpage_was_imported',
45
+ 'template' => 'zelle',
46
+ 'heading' => __( 'Want to keep using Zelle\'s homepage?', 'neve' ),
47
+ 'description' => __( 'Hi! We\'ve noticed you were using Zelle before. To make your transition easier, we can help you keep the same beautiful homepage you had before, by converting it into an Elementor template. This option will also import your homepage content.', 'neve' ),
48
+ 'mandatory_plugins' => array(
49
+ 'elementor' => 'Elementor Page Builder',
50
+ ),
51
+ ),
52
+ 'zerif-lite' => array(
53
+ 'theme_name' => 'Zelle Lite',
54
+ 'theme_mod_check' => 'zelle_frontpage_was_imported',
55
+ 'template' => 'zelle',
56
+ 'heading' => __( 'Want to keep using Zelle\'s homepage?', 'neve' ),
57
+ 'description' => __( 'Hi! We\'ve noticed you were using Zelle before. To make your transition easier, we can help you keep the same beautiful homepage you had before, by converting it into an Elementor template. This option will also import your homepage content.', 'neve' ),
58
+ 'mandatory_plugins' => array(
59
+ 'elementor' => 'Elementor Page Builder',
60
+ ),
61
+ ),
62
+ ),
63
+ 'pro_link' => 'https://themeisle.com/themes/neve/upgrade/',
64
+ );
65
+ $this->add_sites_library_support();
66
+ }
67
+
68
+ /**
69
+ *
70
+ */
71
+ public function add_sites_library_support() {
72
+ add_theme_support( 'themeisle-demo-import', $this->get_ti_demo_content_support_data() );
73
+ }
74
+
75
+ private function get_sites() {
76
+ $cache = get_transient( $this->transient_key );
77
+
78
+ if ( $cache !== false ) {
79
+ $response = $cache;
80
+ } else {
81
+ $response = wp_remote_get( esc_url( self::API ) );
82
+
83
+ if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
84
+ return array();
85
+ }
86
+
87
+ $response = wp_remote_retrieve_body( $response );
88
+
89
+ $response = json_decode( $response, true );
90
+
91
+ if ( ! is_array( $response ) || empty( $response ) ) {
92
+ return array();
93
+ }
94
+ }
95
+
96
+ require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
97
+ $upsell_status = $this->get_upsell_status();
98
+
99
+ $divi = array(
100
+ array(
101
+ 'name' => 'Divi Builder',
102
+ 'active' => is_plugin_active( 'divi-builder/divi-builder.php' ),
103
+ 'author_url' => esc_url( 'https://www.elegantthemes.com/gallery/divi/' ),
104
+ ),
105
+ );
106
+ $thive = array(
107
+ array(
108
+ 'name' => 'Thrive Architect',
109
+ 'active' => is_plugin_active( 'thrive-visual-editor/thrive-visual-editor.php' ),
110
+ 'author_url' => esc_url( 'https://thrivethemes.com/architect/' ),
111
+ ),
112
+ );
113
+
114
+ foreach ( $response as $editor => $sites ) {
115
+ foreach ( $sites as $slug => $site_data ) {
116
+ if ( $editor === 'divi builder' ) {
117
+ $response[ $editor ][ $slug ]['external_plugins'] = $divi;
118
+ }
119
+ if ( $editor === 'thrive architect' ) {
120
+ $response[ $editor ][ $slug ]['external_plugins'] = $thive;
121
+ }
122
+ if ( isset( $site_data['upsell'] ) ) {
123
+ $response[ $editor ][ $slug ]['upsell'] = $upsell_status;
124
+ }
125
+ }
126
+ }
127
+
128
+ $response = $this->shuffle_sites_array( $response );
129
+
130
+ set_transient( $this->transient_key, $response, 12 * HOUR_IN_SECONDS );
131
+
132
+ return $response;
133
+ }
134
+
135
+ /**
136
+ * Get the themeisle demo content support data.
137
+ *
138
+ * @return array
139
+ */
140
+ private function get_ti_demo_content_support_data() {
141
+ $this->reorder_starter_sites();
142
+ return apply_filters( 'neve_filter_onboarding_sites', $this->onboarding_config );
143
+ }
144
+
145
+ /**
146
+ * Shuffle available sites to change display order.
147
+ *
148
+ * @param array $sites sites array.
149
+ *
150
+ * @return array
151
+ */
152
+ private function shuffle_sites_array( $sites ) {
153
+ $fixed = array(
154
+ 'elementor' => array(
155
+ 'neve-web-agency' => true,
156
+ 'neve-main' => true,
157
+ ),
158
+ 'beaver builder' => array(
159
+ 'neve-beaver-web-agency' => true,
160
+ 'neve-beaver-onboarding' => true,
161
+ ),
162
+ 'gutenberg' => array(
163
+ 'neve-web-agency-gutenberg' => true,
164
+ 'neve-main-gutenberg' => true,
165
+ ),
166
+ 'brizy' => array( 'neve-brizy-main' => true ),
167
+ );
168
+ $normalized = array();
169
+ foreach ( $sites as $editor => $sites_for_editor ) {
170
+ $normalized[ $editor ] = isset( $fixed[ $editor ] ) ? $fixed[ $editor ] : array();
171
+ $sites_for_editor = $this->shuffle_associative_array( $sites_for_editor );
172
+ foreach ( $sites_for_editor as $site_slug => $site_data ) {
173
+ if ( isset( $normalized[ $editor ][ $site_slug ] ) ) {
174
+ $normalized[ $editor ][ $site_slug ] = $site_data;
175
+ unset( $sites_for_editor[ $site_slug ] );
176
+ }
177
+ }
178
+ $normalized[ $editor ] = array_merge( $normalized[ $editor ], $sites_for_editor );
179
+ }
180
+
181
+ return $normalized;
182
+ }
183
+
184
+ /**
185
+ * Shuffle associative array.
186
+ *
187
+ * @param array $array associative array.
188
+ *
189
+ * @return array
190
+ */
191
+ private function shuffle_associative_array( $array ) {
192
+ $keys = array_keys( $array );
193
+ $shuffled = array();
194
+
195
+ shuffle( $keys );
196
+ foreach ( $keys as $key ) {
197
+ $shuffled[ $key ] = $array[ $key ];
198
+ }
199
+
200
+ return $shuffled;
201
+ }
202
+
203
+ /**
204
+ * Reorder starter sites based on previous theme
205
+ *
206
+ * @return bool
207
+ */
208
+ private function reorder_starter_sites() {
209
+ $previous_theme = get_theme_mod( 'ti_prev_theme' );
210
+ if ( empty( $previous_theme ) ) {
211
+ return false;
212
+ }
213
+
214
+ $slug_association = array(
215
+ 'zerif-pro' => 'neve-zelle',
216
+ 'zerif-lite' => 'neve-zelle',
217
+ 'themotion' => 'neve-themotion',
218
+ 'themotion-lite' => 'neve-themotion',
219
+ 'amadeus' => 'neve-amadeus',
220
+ 'rokophoto-lite' => 'neve-rokophoto',
221
+ 'rokophoto' => 'neve-rokophoto',
222
+ 'oblique' => 'neve-oblique',
223
+ 'shop-isle' => 'neve-shop',
224
+ 'shop-isle-pro' => 'neve-shop',
225
+ 'lawyeria-lite' => 'neve-lawyer',
226
+ 'lawyeria' => 'neve-lawyer',
227
+ );
228
+ if ( ! array_key_exists( $previous_theme, $slug_association ) ) {
229
+ return false;
230
+ }
231
+ if ( ! isset( $this->onboarding_config['local']['elementor'][ $slug_association[ $previous_theme ] ] ) ) {
232
+ return false;
233
+ }
234
+ $starter_site = $this->onboarding_config['local']['elementor'][ $slug_association[ $previous_theme ] ];
235
+ unset( $this->onboarding_config['local']['elementor'][ $slug_association[ $previous_theme ] ] );
236
+ $this->onboarding_config['local']['elementor'] = array( $slug_association[ $previous_theme ] => $starter_site ) + $this->onboarding_config['local']['elementor'];
237
+
238
+ return true;
239
+ }
240
+
241
+ /**
242
+ * Get upsell status.
243
+ *
244
+ * @return bool
245
+ */
246
+ private function get_upsell_status() {
247
+ $category = apply_filters( 'product_neve_license_plan', -1 );
248
+ $category_mapping = array(
249
+ 1 => 1,
250
+ 2 => 1,
251
+ 3 => 2,
252
+ 4 => 2,
253
+ 5 => 3,
254
+ 6 => 3,
255
+ 7 => 1,
256
+ 8 => 2,
257
+ 9 => 3,
258
+ );
259
+ return ! isset( $category_mapping[ $category ] ) || $category_mapping[ $category ] < 2;
260
+ }
261
+
262
+ }
includes/WP_Cli.php ADDED
@@ -0,0 +1,447 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WP CLI commands.
4
+ *
5
+ * Author: Andrei Baicus <andrei@themeisle.com>
6
+ * Created on: 26/06/2019
7
+ *
8
+ * @package templates-patterns-collection
9
+ */
10
+
11
+ namespace TIOB;
12
+
13
+ use TIOB\Importers\Content_Importer;
14
+ use TIOB\Importers\Helpers\Helper;
15
+ use TIOB\Importers\Plugin_Importer;
16
+ use TIOB\Importers\Theme_Mods_Importer;
17
+ use TIOB\Importers\Widgets_Importer;
18
+
19
+ /**
20
+ * Class WP_Cli
21
+ */
22
+ class WP_Cli {
23
+ use Helper;
24
+
25
+ /**
26
+ * Command namespace version.
27
+ *
28
+ * @var string Version string.
29
+ */
30
+ const CLI_NAMESPACE = 'themeisle-si';
31
+ /**
32
+ * List of commands.
33
+ *
34
+ * @var array List of REST controllers.
35
+ */
36
+ private $commands = array(
37
+ 'import' => 'import',
38
+ 'list_sites' => 'list',
39
+ );
40
+
41
+ /**
42
+ * All sites data.
43
+ *
44
+ * @var array
45
+ */
46
+ private $data = array();
47
+
48
+ private $locations = array( 'local', 'remote' );
49
+
50
+ /**
51
+ * Theme mods importer.
52
+ *
53
+ * @var Theme_Mods_Importer
54
+ */
55
+ private $theme_mods_importer;
56
+
57
+ /**
58
+ * Content importer.
59
+ *
60
+ * @var Content_Importer
61
+ */
62
+ private $content_importer;
63
+
64
+ /**
65
+ * Widgets importer.
66
+ *
67
+ * @var Widgets_Importer
68
+ */
69
+ private $widgets_importer;
70
+
71
+ /**
72
+ * Plugins importer.
73
+ *
74
+ * @var Plugin_Importer
75
+ */
76
+ private $plugin_importer;
77
+
78
+ /**
79
+ * Setup class props.
80
+ */
81
+ private function setup_props() {
82
+ $theme_support = get_theme_support( 'themeisle-demo-import' );
83
+ $this->data = $theme_support[0];
84
+ $this->theme_mods_importer = new Theme_Mods_Importer();
85
+ $this->content_importer = new Content_Importer();
86
+ $this->widgets_importer = new Widgets_Importer();
87
+ $this->plugin_importer = new Plugin_Importer();
88
+ }
89
+
90
+ /**
91
+ * Load the WP CLI commands.
92
+ */
93
+ public function load_commands() {
94
+ foreach ( $this->commands as $callback => $command ) {
95
+ try {
96
+ \WP_CLI::add_command( self::CLI_NAMESPACE . ' ' . $command, array( $this, $callback ) );
97
+ } catch ( \Exception $e ) {
98
+ error_log( 'Error loading cli commnands' . $e->getMessage() );
99
+ }
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Get all sites as (string) $slug => (array) $args
105
+ *
106
+ * @param string $source the source [local/remote/all].
107
+ *
108
+ * @return array
109
+ */
110
+ private function get_all_sites( $source = 'all' ) {
111
+ $this->setup_props();
112
+
113
+ if ( $source !== 'all' ) {
114
+ $this->locations = array( $source );
115
+ }
116
+
117
+ $defaults = array(
118
+ 'editors' => array(),
119
+ 'local' => array(),
120
+ 'remote' => array(),
121
+ );
122
+
123
+ $this->data = wp_parse_args( $this->data, $defaults );
124
+ $editors = $this->data['editors'];
125
+ $all_sites = array();
126
+ foreach ( $this->locations as $site_source ) {
127
+ if ( ! isset( $this->data[ $site_source ] ) || empty( $this->data[ $site_source ] ) ) {
128
+ continue;
129
+ }
130
+ foreach ( $editors as $editor ) {
131
+ if ( ! isset( $this->data[ $site_source ][ $editor ] ) ) {
132
+ continue;
133
+ }
134
+ foreach ( $this->data[ $site_source ][ $editor ] as $site_slug => $data ) {
135
+ $this->data[ $site_source ][ $editor ][ $site_slug ]['slug'] = $site_slug;
136
+ $this->data[ $site_source ][ $editor ][ $site_slug ]['editor'] = $editor;
137
+ $this->data[ $site_source ][ $editor ][ $site_slug ]['source'] = $site_source;
138
+ if ( isset( $data['local_json'] ) ) {
139
+ $this->data[ $site_source ][ $editor ][ $site_slug ]['local_json'] = $data['local_json'];
140
+ }
141
+ if ( isset( $data['remote_json'] ) ) {
142
+ $this->data[ $site_source ][ $editor ][ $site_slug ]['remote_json'] = $data['remote_json'];
143
+ }
144
+ $all_sites[ $site_slug ] = $this->data[ $site_source ][ $editor ][ $site_slug ];
145
+ }
146
+ }
147
+ }
148
+
149
+ return $all_sites;
150
+ }
151
+
152
+ /**
153
+ * Import single starter site.
154
+ *
155
+ * ## OPTIONS
156
+ *
157
+ * <slug>
158
+ * : The slug of the starter site to import. T
159
+ *
160
+ *
161
+ * ## EXAMPLES
162
+ *
163
+ * wp themeisle-si import neve-restaurant
164
+ *
165
+ * @param array $args inline args.
166
+ * @param array $assoc_args associative args.
167
+ *
168
+ */
169
+ public function import( $args, $assoc_args ) {
170
+
171
+ $this->setup_props();
172
+ $sites = $this->get_all_sites();
173
+ $site_slug = $args[0];
174
+ if ( ! array_key_exists( $site_slug, $sites ) ) {
175
+ \WP_CLI::warning( "No site to import with the slug ${site_slug}." );
176
+
177
+ return;
178
+ }
179
+
180
+ $site = $sites[ $site_slug ];
181
+
182
+ $json_array = $this->get_starter_site_json( $site );
183
+ $this->import_plugins_for_starter_site( $json_array );
184
+ $xml = $this->get_starter_site_xml( $site, $json_array );
185
+ \WP_CLI::line( 'Importing content file...' );
186
+ $this->import_xml_file( $xml, array_merge( array( 'demoSlug' => $site_slug ), $json_array ), $site['editor'] );
187
+ \WP_CLI::line( 'Done!' );
188
+ $this->import_theme_mods( $json_array );
189
+ $this->setup_pages( $json_array, $args[0] );
190
+ $this->import_widgets( $json_array );
191
+ }
192
+
193
+ /**
194
+ * Import widgets
195
+ *
196
+ * @param array $json site json data.
197
+ */
198
+ private function import_widgets( $json ) {
199
+ if ( ! isset( $json['widgets'] ) || empty( $json['widgets'] ) ) {
200
+ return;
201
+ }
202
+ $this->widgets_importer->actually_import( $json['widgets'] );
203
+ }
204
+
205
+ /**
206
+ * Setup pages
207
+ *
208
+ * @param array $json site json data.
209
+ * @param string $demo_slug the demo slug.
210
+ */
211
+ private function setup_pages( $json, $demo_slug ) {
212
+ if ( isset( $json['front_page'] ) ) {
213
+ $this->content_importer->setup_front_page( $json['front_page'], $demo_slug );
214
+ } else {
215
+ \WP_CLI::warning( 'Incorrect front page arguments.' );
216
+ }
217
+
218
+ if ( isset( $json['shop_pages'] ) ) {
219
+ $this->content_importer->setup_shop_pages( $json['shop_pages'], $demo_slug );
220
+ } else {
221
+ \WP_CLI::warning( 'No shop page arguments.' );
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Import theme mods
227
+ *
228
+ * @param array $json site json data.
229
+ */
230
+ private function import_theme_mods( $json ) {
231
+
232
+ if ( isset( $json['theme_mods'] ) && ! empty( $json['theme_mods'] ) ) {
233
+ array_walk(
234
+ $json['theme_mods'],
235
+ function ( &$item ) {
236
+ $item = $this->replace_image_urls( $item );
237
+ }
238
+ );
239
+
240
+ foreach ( $json['theme_mods'] as $key => $value ) {
241
+ if ( $key === '__ti_import_menus_location' ) {
242
+ continue;
243
+ }
244
+ if ( $value === 'true' ) {
245
+ $value = true;
246
+ }
247
+
248
+ if ( $value === 'false' ) {
249
+ $value = false;
250
+ }
251
+
252
+ set_theme_mod( $key, $value );
253
+ }
254
+ }
255
+
256
+ if ( isset( $json['wp_options'] ) && ! empty( $json['wp_options'] ) ) {
257
+ foreach ( $json['wp_options'] as $key => $value ) {
258
+ if ( $value === 'true' ) {
259
+ $value = true;
260
+ }
261
+
262
+ if ( $value === 'false' ) {
263
+ $value = false;
264
+ }
265
+ update_option( $key, $value );
266
+ }
267
+ }
268
+
269
+ // Set nav menu locations.
270
+ if ( isset( $json['theme_mods']['__ti_import_menus_location'] ) ) {
271
+ $this->theme_mods_importer->setup_nav_menus( $json['theme_mods']['__ti_import_menus_location'] );
272
+ }
273
+ \WP_CLI::success( 'Theme mods imported.' );
274
+ }
275
+
276
+ /**
277
+ * Import XML file
278
+ *
279
+ * @param string $path XML file path.
280
+ * @param array $json json data for site.
281
+ * @param string $editor page builder.
282
+ */
283
+ private function import_xml_file( $path, $json, $editor ) {
284
+ if ( ! file_exists( $path ) || ! is_readable( $path ) ) {
285
+ \WP_CLI::warning( "Cannot import XML file. Either the file is not readable or it does not exist (${path})" );
286
+ }
287
+ $this->content_importer->import_file( $path, $json, $editor );
288
+ \WP_CLI::success( 'Content imported.' );
289
+ }
290
+
291
+ /**
292
+ * Installs and activates all mandatory and recommended plugins.
293
+ *
294
+ * @param array $json_data site json data.
295
+ */
296
+ private function import_plugins_for_starter_site( $json_data ) {
297
+ $all_plugins = array();
298
+
299
+ if ( isset( $json_data['recommended_plugins'] ) ) {
300
+ $all_plugins = array_merge( $all_plugins, array_keys( $json_data['recommended_plugins'] ) );
301
+ }
302
+
303
+ if ( isset( $json_data['mandatory_plugins'] ) ) {
304
+ $all_plugins = array_merge( $all_plugins, array_keys( $json_data['mandatory_plugins'] ) );
305
+ }
306
+
307
+ $all_plugins = array_combine( $all_plugins, $all_plugins );
308
+ $all_plugins = array_fill_keys( $all_plugins, true );
309
+
310
+ \WP_CLI::line( 'Installing...' );
311
+ \WP_CLI::print_value( $all_plugins );
312
+
313
+ $this->plugin_importer->run_plugins_install( $all_plugins );
314
+
315
+ \WP_CLI::success( 'Plugins installed and activated' );
316
+ }
317
+
318
+ /**
319
+ * Lists starter sites.
320
+ *
321
+ * ## OPTIONS
322
+ *
323
+ * [--source=<type>]
324
+ * : Which source to list ( local or remote ).
325
+ * ---
326
+ * default: all
327
+ * options:
328
+ * - local
329
+ * - remote
330
+ * - all
331
+ * ---
332
+ *
333
+ * [--field=<field>]
334
+ * : Which field to list.
335
+ * ---
336
+ * default: null
337
+ * options:
338
+ * - slug
339
+ * - editor
340
+ * - source
341
+ * - title
342
+ * ---
343
+ *
344
+ * [--show-url=<bool>]
345
+ * : Should display URLs (true / false).
346
+ * ---
347
+ * default: false
348
+ * options:
349
+ * - true
350
+ * - false
351
+ * ---
352
+ *
353
+ * ## EXAMPLES
354
+ *
355
+ * wp ti-starter-sites list --source=local --show-url=false
356
+ *
357
+ * @param array $args inline args.
358
+ * @param array $assoc_args associative args.
359
+ *
360
+ */
361
+ public function list_sites( $args, $assoc_args ) {
362
+ $fields = array(
363
+ 'slug',
364
+ 'editor',
365
+ 'source',
366
+ 'title',
367
+ );
368
+
369
+ if ( $assoc_args['field'] ) {
370
+ if ( in_array( $assoc_args['field'], $fields, true ) ) {
371
+ $formatter = new \WP_CLI\Formatter( $assoc_args, null );
372
+ $formatter->display_items( $this->get_all_sites(), array( $assoc_args['field'] ) );
373
+ } else {
374
+ \WP_CLI::error( 'Error' );
375
+ }
376
+
377
+ return;
378
+ }
379
+
380
+ if ( $assoc_args['show-url'] === 'true' ) {
381
+ $fields[] = 'url';
382
+ }
383
+
384
+ \WP_CLI\Utils\format_items( 'table', $this->get_all_sites( $assoc_args['source'] ), $fields );
385
+ }
386
+
387
+ /**
388
+ * Get the starter site XML.
389
+ *
390
+ * @param array $site site data array.
391
+ * @param array $json site json data.
392
+ *
393
+ * @return string
394
+ */
395
+ private function get_starter_site_xml( $site, $json ) {
396
+ $source = $site['source'];
397
+ $slug = $site['slug'];
398
+
399
+ if ( $source === 'local' ) {
400
+ return get_template_directory() . '/onboarding/' . $slug . '/export.xml';
401
+ }
402
+ set_time_limit( 0 );
403
+ \WP_CLI::line( 'Saving... ' . $json['content_file'] );
404
+
405
+ $response_file = wp_remote_get( $json['content_file'] );
406
+ $content_file_path = $this->content_importer->save_xhr_return_path( wp_remote_retrieve_body( $response_file ) );
407
+ \WP_CLI::line( 'Saved content file in ' . $content_file_path );
408
+
409
+ return $content_file_path;
410
+ }
411
+
412
+ /**
413
+ * Get starter site JSON.
414
+ *
415
+ * @param array $site site data array.
416
+ *
417
+ * @return array
418
+ */
419
+ private function get_starter_site_json( $site ) {
420
+ $slug = $site['slug'];
421
+ $editor = $site['editor'];
422
+ $source = $site['source'];
423
+
424
+ global $wp_filesystem;
425
+ WP_Filesystem();
426
+ if ( $source === 'local' ) {
427
+ return json_decode( $wp_filesystem->get_contents( get_template_directory() . '/onboarding/' . $slug . '/data.json' ), true );
428
+ }
429
+ if ( isset( $site['local_json'] ) ) {
430
+ return json_decode( $wp_filesystem->get_contents( $site['local_json'] ), true );
431
+ }
432
+ $site_url = isset( $site['remote_json'] ) ? $site['remote_json'] : $this->data[ $source ][ $editor ][ $slug ]['url'];
433
+ $request = wp_remote_get( $site_url . 'wp-json/ti-demo-data/data' );
434
+ $response_code = wp_remote_retrieve_response_code( $request );
435
+ if ( $response_code !== 200 || empty( $request['body'] ) || ! isset( $request['body'] ) ) {
436
+ \WP_CLI::warning( 'Cannot get site json data.' );
437
+ }
438
+
439
+ $json = json_decode( $request['body'], true );
440
+
441
+ return $json;
442
+ }
443
+ }
444
+
445
+ $ti_ob_cli = new WP_Cli();
446
+ $ti_ob_cli->load_commands();
447
+
migration/zelle/zelle.json ADDED
@@ -0,0 +1 @@
 
1
+ {"version":"0.4","title":"Zelle Template","type":"page","content":[{"id":"10b0761f","settings":{"layout":"full_width","content_position":"middle","background_background":"classic","background_image":{"id":3942,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-header.jpg"},"background_position":"top center","background_attachment":"fixed","background_overlay_background":"classic","background_overlay_color":"#000000","margin":{"unit":"px","top":"0","right":0,"bottom":"0","left":0,"isLinked":true},"padding":{"unit":"px","top":"175","right":"0","bottom":"200","left":"0","isLinked":false},"background_size":"auto","padding_mobile":{"unit":"px","top":"90","right":"0","bottom":"100","left":"0","isLinked":false}},"elements":[{"id":"74b49ca0","settings":{"_column_size":100},"elements":[{"id":"6bddd647","settings":{"title":"make the best of your wordpress experience with Zelle lite","title_color":"#ffffff","typography_typography":"custom","typography_font_size":{"unit":"px","size":55},"typography_text_transform":"uppercase","_css_classes":"intro-text","align":"center","header_size":"h1","typography_font_family":"Montserrat","typography_font_weight":"700","typography_line_height":{"unit":"px","size":65},"_padding":{"unit":"px","top":"0","right":"180","bottom":"0","left":"180","isLinked":false},"typography_font_size_mobile":{"unit":"px","size":32},"typography_line_height_mobile":{"unit":"px","size":37},"_margin_tablet":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"_margin_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"_padding_tablet":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"_padding_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"228467cc","settings":{"structure":"20","margin":{"unit":"px","top":"0","right":0,"bottom":"0","left":0,"isLinked":true},"padding":{"unit":"px","top":"30","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[{"id":"3b971e50","settings":{"_column_size":50,"_inline_size":47.018},"elements":[{"id":"7a11580","settings":{"text":"FEATURES","align":"right","size":"md","typography_typography":"custom","typography_font_size":{"unit":"px","size":14},"typography_text_transform":"uppercase","background_color":"#e96656","button_background_hover_color":"#cb4332","align_mobile":"center","typography_font_weight":"300","button_text_color":"#ffffff","hover_color":"#ffffff"},"elements":[],"isInner":false,"widgetType":"button","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"b7f4970","settings":{"_column_size":50,"_inline_size":52.982},"elements":[{"id":"6d33aa28","settings":{"text":"DOWNLOAD ZELLE LITE","align":"left","size":"md","typography_typography":"custom","typography_font_size":{"unit":"px","size":14},"typography_text_transform":"uppercase","background_color":"#1e9e6b","button_background_hover_color":"#069059","align_mobile":"center","typography_font_weight":"300","button_text_color":"#ffffff","hover_color":"#ffffff"},"elements":[],"isInner":false,"widgetType":"button","elType":"widget"}],"isInner":true,"elType":"column"}],"isInner":true,"elType":"section"}],"isInner":false,"elType":"column"}],"isInner":false,"elType":"section"},{"id":"395483b0","settings":{"margin":{"unit":"px","top":"","right":0,"bottom":"","left":0,"isLinked":true},"_element_id":"focus","background_background":"classic","padding":{"unit":"px","top":"100","right":"0","bottom":"100","left":"0","isLinked":false},"background_color":"#ffffff","margin_mobile":{"unit":"px","top":"","right":0,"bottom":"","left":0,"isLinked":true},"padding_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true}},"elements":[{"id":"153e52a8","settings":{"_column_size":100},"elements":[{"id":"12a409ea","settings":{"title":"features","title_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":45},"typography_text_transform":"uppercase","align":"center","typography_font_family":"Montserrat","typography_font_weight":"700","typography_line_height":{"unit":"px","size":""},"typography_font_size_mobile":{"unit":"px","size":22},"typography_line_height_mobile":{"unit":"px","size":40},"_margin_tablet":{"unit":"px","top":"50","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"5b36d28b","settings":{"title":"What makes the single-page WordPress theme unique.","header_size":"h4","title_color":"#000000","typography_typography":"custom","typography_font_size":{"unit":"px","size":16},"_margin":{"unit":"px","top":"0","right":"0","bottom":"50","left":"0","isLinked":false},"align":"center","typography_font_family":"Lato","typography_font_weight":"400","typography_font_size_mobile":{"unit":"px","size":16},"typography_line_height_mobile":{"unit":"px","size":24}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"74f8bb0b","settings":{"structure":"40","animation":"fadeInLeft","animation_duration":"slow","gap":"extended"},"elements":[{"id":"4cff1711","settings":{"_column_size":25,"_inline_size":null},"elements":[{"id":"5d94ecda","settings":{"image":{"id":3948,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-parallax1.png"},"image_size":"full","image_border_width":{"unit":"px","top":"10","right":"10","bottom":"10","left":"10","isLinked":true},"image_border_color":"#e96656","image_border_radius":{"unit":"%","top":"100","right":"100","bottom":"100","left":"100","isLinked":true},"_border_radius":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"image_custom_dimension":{"width":"145","height":"145"},"link_to":"custom","image_border_radius_mobile":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_radius_hover":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"width":{"unit":"px","size":135},"image_border_border":"solid"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"},{"id":"1008421f","settings":{"title":"PARALLAX EFFECT","header_size":"h3","title_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":17},"typography_font_weight":"bold","typography_text_transform":"uppercase","_margin":{"unit":"px","top":"0","right":"0","bottom":"-5","left":"0","isLinked":false},"align":"center"},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"7e2a29af","settings":{"weight":{"unit":"px","size":2},"color":"#e96656","width":{"unit":"px","size":110},"gap":{"unit":"px","size":2},"align":"center","_margin_tablet":{"unit":"px","top":"037","right":"0","bottom":"0","left":"0","isLinked":false},"_margin_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true}},"elements":[],"isInner":false,"widgetType":"divider","elType":"widget"},{"id":"35181f80","settings":{"editor":"<p style=\"text-align: center;\"><span>Create memorable pages with smooth parallax effects that everyone loves. Also, use our lightweight content slider offering you smooth and great-looking animations.<\/span><\/p>","text_color":"#808080","typography_typography":"custom","typography_font_size":{"unit":"px","size":14},"align":"left"},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"7b3f845f","settings":{"_column_size":25,"_inline_size":null},"elements":[{"id":"5d50a65a","settings":{"image":{"id":3947,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-woo1.png"},"image_size":"full","image_border_width":{"unit":"px","top":"10","right":"10","bottom":"10","left":"10","isLinked":true},"image_border_color":"#34d293","image_border_radius":{"unit":"%","top":"100","right":"100","bottom":"100","left":"100","isLinked":true},"_border_radius":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"image_custom_dimension":{"width":"145","height":"145"},"link_to":"custom","image_border_radius_mobile":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_radius_hover":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"width":{"unit":"px","size":135},"image_border_border":"solid"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"},{"id":"796db0be","settings":{"title":"WOOCOMMERCE","header_size":"h3","title_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":17},"typography_font_weight":"bold","typography_text_transform":"uppercase","_margin":{"unit":"px","top":"0","right":"0","bottom":"-5","left":"0","isLinked":false},"align":"center"},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"4a8de546","settings":{"weight":{"unit":"px","size":2},"color":"#34d293","width":{"unit":"px","size":100},"gap":{"unit":"px","size":2},"align":"center","_margin_tablet":{"unit":"px","top":"37","right":"0","bottom":"0","left":"0","isLinked":false},"_margin_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true}},"elements":[],"isInner":false,"widgetType":"divider","elType":"widget"},{"id":"12d9e8b","settings":{"editor":"<p style=\"text-align: center;\"><span>Build a front page for your WooCommerce store in a matter of minutes. The neat and clean presentation will help your sales and make your store accessible to everyone.<\/span><\/p>","text_color":"#808080","typography_typography":"custom","typography_font_size":{"unit":"px","size":14}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"64d0de3","settings":{"_column_size":25,"_inline_size":null},"elements":[{"id":"160cead7","settings":{"image":{"id":3945,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-ccc.png"},"image_size":"full","image_border_width":{"unit":"px","top":"10","right":"10","bottom":"10","left":"10","isLinked":true},"image_border_color":"#3ab0e2","image_border_radius":{"unit":"%","top":"100","right":"100","bottom":"100","left":"100","isLinked":true},"_border_radius":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"image_custom_dimension":{"width":"145","height":"145"},"link_to":"custom","image_border_radius_mobile":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_radius_hover":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"width":{"unit":"px","size":135},"image_border_border":"solid"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"},{"id":"27d689b2","settings":{"title":"CUSTOM CONTENT BLOCKS","header_size":"h3","title_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":17},"typography_font_weight":"bold","typography_text_transform":"uppercase","_margin":{"unit":"px","top":"0","right":"0","bottom":"-5","left":"0","isLinked":false},"align":"center"},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"47505683","settings":{"weight":{"unit":"px","size":2},"color":"#3ab0e2","width":{"unit":"px","size":165},"gap":{"unit":"px","size":2},"align":"center","width_tablet":{"unit":"px","size":100},"_margin_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true}},"elements":[],"isInner":false,"widgetType":"divider","elType":"widget"},{"id":"6a1c654f","settings":{"editor":"<p style=\"text-align: center;\"><span>Showcase your team, products, clients, about info, testimonials, latest posts from the blog, contact form, additional calls to action. Everything translation ready.<\/span><\/p>","text_color":"#808080","typography_typography":"custom","typography_font_size":{"unit":"px","size":14}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"7dbd355a","settings":{"_column_size":25,"_inline_size":null},"elements":[{"id":"4849bec3","settings":{"image":{"id":3946,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-themeisle.png"},"image_size":"full","image_border_width":{"unit":"px","top":"10","right":"10","bottom":"10","left":"10","isLinked":true},"image_border_color":"#f7d861","image_border_radius":{"unit":"%","top":"100","right":"100","bottom":"100","left":"100","isLinked":true},"_border_radius":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"image_custom_dimension":{"width":"145","height":"145"},"link_to":"custom","image_border_radius_mobile":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_radius_hover":{"unit":"%","top":"","right":"","bottom":"","left":"","isLinked":true},"width":{"unit":"px","size":135},"image_border_border":"solid"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"},{"id":"3739a1ae","settings":{"title":"GO PRO FOR MORE FEATURES","header_size":"h3","title_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":17},"typography_font_weight":"bold","typography_text_transform":"uppercase","_margin":{"unit":"px","top":"0","right":"0","bottom":"-5","left":"0","isLinked":false},"align":"center"},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"1741d5f3","settings":{"weight":{"unit":"px","size":2},"color":"#f7d861","width":{"unit":"px","size":180},"gap":{"unit":"px","size":2},"align":"center","width_tablet":{"unit":"px","size":110},"_margin_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true}},"elements":[],"isInner":false,"widgetType":"divider","elType":"widget"},{"id":"3f80ce84","settings":{"editor":"<p style=\"text-align: center;\">Get new content blocks: pricing table, Google Maps, and more. Change the sections order, display each block exactly where you need it, customize the blocks with whatever colors you wish.<\/p>","text_color":"#808080","typography_typography":"custom","typography_font_size":{"unit":"px","size":14}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"}],"isInner":true,"elType":"column"}],"isInner":true,"elType":"section"}],"isInner":false,"elType":"column"}],"isInner":false,"elType":"section"},{"id":"2c3702f7","settings":{"background_background":"classic","background_image":{"id":3942,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-header.jpg"},"background_position":"top center","background_attachment":"fixed","background_repeat":"no-repeat","background_overlay_background":"classic","background_overlay_color":"#34d293","background_overlay_opacity":{"unit":"px","size":0.8},"padding":{"unit":"px","top":"150","right":"0","bottom":"150","left":"0","isLinked":false},"shape_divider_top_width":{"unit":"%","size":170},"shape_divider_bottom_flip":"yes","padding_mobile":{"unit":"px","top":"50","right":"0","bottom":"50","left":"0","isLinked":false},"content_width":{"unit":"px","size":750}},"elements":[{"id":"f7199ce","settings":{"_column_size":100},"elements":[{"id":"6b25a000","settings":{"title":"Check out this cool parallax scrolling effect. Plus, you can change the background image.","header_size":"h3","title_color":"#ffffff","typography_typography":"custom","typography_font_size":{"unit":"px","size":24},"typography_line_height":{"unit":"px","size":34},"align":"center","typography_font_family":"Lato","typography_font_weight":"400","_margin":{"unit":"px","top":"0","right":"0","bottom":"30","left":"0","isLinked":false},"_animation":"fadeInLeft"},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"2992f551","settings":{"text":"Button","size":"md","typography_typography":"custom","typography_font_size":{"unit":"px","size":14},"typography_text_transform":"uppercase","background_color":"#1e9e6b","button_background_hover_color":"#069059","align":"center","_animation":"fadeInRight","typography_font_weight":"300","button_text_color":"#ffffff"},"elements":[],"isInner":false,"widgetType":"button","elType":"widget"}],"isInner":false,"elType":"column"}],"isInner":false,"elType":"section"},{"id":"5c3de28f","settings":{"layout":"full_width","background_background":"classic","background_color":"#272727","padding":{"unit":"px","top":"80","right":"0","bottom":"70","left":"0","isLinked":false},"margin_mobile":{"unit":"px","top":"","right":0,"bottom":"","left":0,"isLinked":true},"padding_mobile":{"unit":"px","top":"40","right":"0","bottom":"35","left":"0","isLinked":false}},"elements":[{"id":"56efed49","settings":{"_column_size":100},"elements":[{"id":"7f2055ff","settings":{"margin_mobile":{"unit":"px","top":"","right":0,"bottom":"","left":0,"isLinked":true}},"elements":[{"id":"7e62322a","settings":{"_column_size":100,"_inline_size":null},"elements":[{"id":"178fa183","settings":{"title":"about","title_color":"#ffffff","typography_typography":"custom","typography_font_size":{"unit":"px","size":45},"typography_text_transform":"uppercase","align":"center","typography_font_family":"Montserrat","typography_font_weight":"700","typography_line_height":{"unit":"px","size":""},"typography_font_size_mobile":{"unit":"px","size":22}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"501bacb1","settings":{"title":"Use this section to showcase important details about your business.","header_size":"h4","title_color":"#ffffff","typography_typography":"custom","typography_font_size":{"unit":"px","size":16},"_margin":{"unit":"px","top":"0","right":"0","bottom":"50","left":"0","isLinked":false},"align":"center","typography_font_family":"Lato","typography_font_weight":"400","typography_line_height":{"unit":"px","size":24},"_margin_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"}],"isInner":true,"elType":"column"}],"isInner":true,"elType":"section"},{"id":"50b83be1","settings":{"structure":"30"},"elements":[{"id":"2627ff3d","settings":{"_column_size":33,"_inline_size":null},"elements":[{"id":"60e399e5","settings":{"title":"Everything you see here is responsive and mobile-friendly.","header_size":"div","align":"right","title_color":"#ffffff","typography_typography":"custom","typography_font_size":{"unit":"px","size":60},"typography_font_weight":"300","align_mobile":"center","_animation":"fadeInLeft","typography_font_size_tablet":{"unit":"px","size":45},"typography_font_family":"Lato","typography_font_size_mobile":{"unit":"px","size":27},"typography_line_height_mobile":{"unit":"px","size":35}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"6eab4fa","settings":{"_column_size":33,"_inline_size":null},"elements":[{"id":"1a09fdc","settings":{"editor":"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec massa enim. Aliquam viverra at est ullamcorper sollicitudin. Proin a leo sit amet nunc malesuada imperdiet pharetra ut eros.<\/p><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec massa enim. Aliquam viverra at est ullamcorper sollicitudin. Proin a leo sit amet nunc malesuada imperdiet pharetra ut eros.\u00a0<\/p><p>Mauris vel nunc at ipsum fermentum pellentesque quis ut massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas non adipiscing massa. Sed ut fringilla sapien. Cras sollicitudin, lectus sed tincidunt cursus, magna lectus vehicula augue, a lobortis dui orci et est.<\/p>","align":"left","text_color":"#939393","typography_typography":"custom","typography_font_size":{"unit":"px","size":14},"typography_line_height":{"unit":"px","size":25},"align_mobile":"center","_animation":"fadeInUp","typography_font_size_tablet":{"unit":"px","size":13},"typography_font_family":"Lato","typography_font_weight":"400","typography_font_size_mobile":{"unit":"px","size":14}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"1ab95b65","settings":{"_column_size":33,"_inline_size":null,"animation":"fadeInRight","content_position":"top"},"elements":[{"id":"585e5377","settings":{"icon":"fa fa-check","title_text":"YOUR SKILL #1","description_text":"","position":"left","primary_color":"#e96656","icon_space":{"unit":"px","size":5},"icon_size":{"unit":"px","size":30},"content_vertical_alignment":"bottom","title_color":"#ffffff","title_typography_typography":"custom","title_typography_font_size":{"unit":"px","size":16},"title_typography_font_weight":"bold","title_typography_text_transform":"uppercase","view":"framed","icon_padding":{"unit":"px","size":10},"text_align":"left","text_align_mobile":"center"},"elements":[],"isInner":false,"widgetType":"icon-box","elType":"widget"},{"id":"2ce9459","settings":{"icon":"fa fa-check","title_text":"YOUR SKILL #2","description_text":"","position":"left","primary_color":"#34d293","icon_space":{"unit":"px","size":5},"icon_size":{"unit":"px","size":30},"content_vertical_alignment":"bottom","title_color":"#ffffff","title_typography_typography":"custom","title_typography_font_size":{"unit":"px","size":16},"title_typography_font_weight":"bold","title_typography_text_transform":"uppercase","view":"framed","icon_padding":{"unit":"px","size":10},"text_align_mobile":"center"},"elements":[],"isInner":false,"widgetType":"icon-box","elType":"widget"},{"id":"899047c","settings":{"icon":"fa fa-check","title_text":"YOUR SKILL #3","description_text":"","position":"left","primary_color":"#3ab0e2","icon_space":{"unit":"px","size":5},"icon_size":{"unit":"px","size":30},"content_vertical_alignment":"bottom","title_color":"#ffffff","title_typography_typography":"custom","title_typography_font_size":{"unit":"px","size":16},"title_typography_font_weight":"bold","title_typography_text_transform":"uppercase","view":"framed","icon_padding":{"unit":"px","size":10},"text_align_mobile":"center"},"elements":[],"isInner":false,"widgetType":"icon-box","elType":"widget"},{"id":"54e9eba6","settings":{"icon":"fa fa-check","title_text":"YOUR SKILL #4","description_text":"","position":"left","primary_color":"#f7d861","icon_space":{"unit":"px","size":5},"icon_size":{"unit":"px","size":30},"content_vertical_alignment":"bottom","title_color":"#ffffff","title_typography_typography":"custom","title_typography_font_size":{"unit":"px","size":16},"title_typography_font_weight":"bold","title_typography_text_transform":"uppercase","view":"framed","icon_padding":{"unit":"px","size":10},"text_align_mobile":"center"},"elements":[],"isInner":false,"widgetType":"icon-box","elType":"widget"}],"isInner":true,"elType":"column"}],"isInner":true,"elType":"section"},{"id":"9a29448","settings":{"structure":"30","margin":{"unit":"px","top":"70","right":0,"bottom":"30","left":0,"isLinked":false},"margin_mobile":{"unit":"px","top":"35","right":0,"bottom":"15","left":0,"isLinked":false}},"elements":[{"id":"2259c257","settings":{"_column_size":33,"_inline_size":40.965},"elements":[{"id":"6fd11a07","settings":{"style":"double","weight":{"unit":"px","size":4},"gap":{"unit":"px","size":8}},"elements":[],"isInner":false,"widgetType":"divider","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"35a9ee3b","settings":{"_column_size":33,"_inline_size":17.982},"elements":[{"id":"7b0a5096","settings":{"title":"OUR HAPPY CLIENTS","header_size":"h5","title_color":"#ffffff","typography_typography":"custom","typography_font_size":{"unit":"px","size":16},"_border_color":"#4c4c4c","align":"center","typography_font_family":"Lato","typography_font_weight":"400","typography_line_height":{"unit":"px","size":""}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"2f89f8d4","settings":{"_column_size":33,"_inline_size":41.049},"elements":[{"id":"251fb022","settings":{"style":"double","weight":{"unit":"px","size":4},"gap":{"unit":"px","size":8}},"elements":[],"isInner":false,"widgetType":"divider","elType":"widget"}],"isInner":true,"elType":"column"}],"isInner":true,"elType":"section"},{"id":"20832b6d","settings":{"structure":"60","content_width":{"unit":"px","size":1000},"animation":"fadeInRight","animation_duration":"slow"},"elements":[{"id":"4f7e97d0","settings":{"_column_size":16,"_inline_size":null,"content_position":"center"},"elements":[{"id":"cd93c56","settings":{"image":{"id":3949,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-vogue.png"},"image_size":"full","link_to":"custom","link":{"url":"#","is_external":"","nofollow":""}},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"7a4bd22f","settings":{"_column_size":16,"_inline_size":null,"content_position":"center"},"elements":[{"id":"3a36958b","settings":{"image":{"id":3950,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-mashable.png"},"link_to":"custom","link":{"url":"#","is_external":"","nofollow":""},"image_size":"full"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"460d1bbe","settings":{"_column_size":16,"_inline_size":null,"content_position":"center"},"elements":[{"id":"f380aa4","settings":{"image":{"id":3951,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-tnw.png"},"link_to":"custom","link":{"url":"#","is_external":"","nofollow":""},"image_size":"full"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"805ad9c","settings":{"_column_size":16,"_inline_size":null,"content_position":"center"},"elements":[{"id":"207152e9","settings":{"image":{"id":3953,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-ng.png"},"link_to":"custom","link":{"url":"#","is_external":"","nofollow":""},"image_size":"full"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"10e2c96f","settings":{"_column_size":16,"_inline_size":null,"content_position":"center"},"elements":[{"id":"14679f61","settings":{"image":{"id":3954,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-tc.png"},"link_to":"custom","link":{"url":"#","is_external":"","nofollow":""},"image_size":"full"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"35d8fd40","settings":{"_column_size":16,"_inline_size":null,"content_position":"center"},"elements":[{"id":"197bd76e","settings":{"image":{"id":3955,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-lucky.png"},"link_to":"custom","link":{"url":"#","is_external":"","nofollow":""},"image_size":"full"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"}],"isInner":true,"elType":"column"}],"isInner":true,"elType":"section"}],"isInner":false,"elType":"column"}],"isInner":false,"elType":"section"},{"id":"719b8882","settings":{"margin":{"unit":"px","top":"0","right":0,"bottom":"0","left":0,"isLinked":false},"_element_id":"team","background_hover_transition":{"unit":"px","size":""},"padding":{"unit":"px","top":"100","right":"0","bottom":"120","left":"0","isLinked":false},"margin_mobile":{"unit":"px","top":"0","right":0,"bottom":"0","left":0,"isLinked":false},"padding_mobile":{"unit":"px","top":"50","right":"0","bottom":"60","left":"0","isLinked":false},"background_background":"classic","background_color":"#ffffff"},"elements":[{"id":"4f69cb49","settings":{"_column_size":100,"padding_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true}},"elements":[{"id":"64318bfe","settings":{"title":"YOUR TEAM","title_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":45},"typography_text_transform":"uppercase","_margin":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false},"align":"center","typography_font_family":"Montserrat","typography_font_weight":"700","typography_font_size_mobile":{"unit":"px","size":22}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"20843842","settings":{"title":"Prove that you have real people working for you, with some nice looking profile pictures and links to social media.","header_size":"h4","title_color":"#000000","typography_typography":"custom","typography_font_size":{"unit":"px","size":16},"_margin":{"unit":"px","top":"0","right":"0","bottom":"50","left":"0","isLinked":false},"align":"center","typography_font_family":"Lato","typography_font_weight":"400","typography_line_height_mobile":{"unit":"px","size":24}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"1fc1a29","settings":{"structure":"40","animation":"slideInLeft","animation_duration":"fast","text_align":"center","margin_mobile":{"unit":"px","top":"","right":0,"bottom":"","left":0,"isLinked":true}},"elements":[{"id":"7db2fdcc","settings":{"_column_size":25,"_inline_size":null,"text_align":"center"},"elements":[{"id":"6dcf084f","settings":{"image":{"id":3956,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-team1.png"},"image_size":"full","image_border_width":{"unit":"px","top":"10","right":"10","bottom":"10","left":"10","isLinked":true},"image_border_color":"#ececec","image_border_radius":{"unit":"%","top":"50","right":"50","bottom":"50","left":"50","isLinked":true},"_margin":{"unit":"px","top":"0","right":"40","bottom":"30","left":"40","isLinked":false},"_border_hover_color":"#e96656","_margin_tablet":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"_margin_mobile":{"unit":"px","top":"0","right":"60","bottom":"0","left":"60","isLinked":false},"_border_color":"#ececec","align":"left","align_tablet":"center","align_mobile":"center"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"},{"id":"1d755f99","settings":{"title":"Ashley Simmons","header_size":"h3","title_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":17},"typography_font_weight":"700","typography_text_transform":"uppercase","_margin":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false},"typography_font_family":"Lato","typography_line_height":{"unit":"px","size":26}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"753fbacd","settings":{"weight":{"unit":"px","size":2},"color":"#e96656","width":{"unit":"px","size":105},"gap":{"unit":"px","size":0},"_margin":{"unit":"px","top":"-15","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[],"isInner":false,"widgetType":"divider","elType":"widget"},{"id":"42f830d","settings":{"editor":"<p style=\"text-align: center;\">Project manger<\/p>","text_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":13},"_margin":{"unit":"px","top":"-20","right":"0","bottom":"0","left":"0","isLinked":false},"_padding":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"typography_font_family":"Lato","typography_font_weight":"400","typography_line_height":{"unit":"px","size":""}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"},{"id":"6cb8dd30","settings":{"social_icon_list":[{"social":"fa fa-facebook","_id":"723f275","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-twitter","_id":"efd3ea7","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-behance","_id":"96985ec","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-dribbble","link":{"url":"","is_external":"true","nofollow":""},"_id":"08d04f2"}],"icon_color":"custom","icon_primary_color":"rgba(255,255,255,0)","icon_secondary_color":"#808080","icon_size":{"unit":"px","size":16},"icon_padding":{"unit":"em","size":0.2},"image_border_width":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"hover_secondary_color":"#e96656","icon_size_mobile":{"unit":"px","size":30}},"elements":[],"isInner":false,"widgetType":"social-icons","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"10a2dcf0","settings":{"_column_size":25,"_inline_size":null,"text_align":"center"},"elements":[{"id":"5d70b859","settings":{"image":{"id":3957,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-team2.png"},"image_size":"full","image_border_width":{"unit":"px","top":"10","right":"10","bottom":"10","left":"10","isLinked":true},"image_border_color":"#ececec","image_border_radius":{"unit":"%","top":"100","right":"100","bottom":"100","left":"100","isLinked":true},"_margin":{"unit":"px","top":"0","right":"40","bottom":"30","left":"40","isLinked":false},"_border_hover_color":"#e96656","_margin_tablet":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"_margin_mobile":{"unit":"px","top":"0","right":"60","bottom":"0","left":"60","isLinked":false},"_border_color":"#ececec","align":"left","align_tablet":"center","align_mobile":"center"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"},{"id":"6eb2ec50","settings":{"title":"Timothy Spray","header_size":"h3","title_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":17},"typography_font_weight":"700","typography_text_transform":"uppercase","_margin":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false},"typography_font_family":"Lato","typography_line_height":{"unit":"px","size":26}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"756f9871","settings":{"weight":{"unit":"px","size":2},"color":"#34d293","width":{"unit":"px","size":100},"gap":{"unit":"px","size":0},"_margin":{"unit":"px","top":"-15","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[],"isInner":false,"widgetType":"divider","elType":"widget"},{"id":"63afcfee","settings":{"editor":"<p style=\"text-align: center;\">Art Director<\/p>","text_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":13},"_margin":{"unit":"px","top":"-20","right":"0","bottom":"0","left":"0","isLinked":false},"_padding":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"typography_font_family":"Lato","typography_font_weight":"400","typography_line_height":{"unit":"px","size":""}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"},{"id":"75723f52","settings":{"social_icon_list":[{"social":"fa fa-facebook","_id":"723f275","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-twitter","_id":"efd3ea7","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-dribbble","_id":"96985ec","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-linkedin","link":{"url":"","is_external":"true","nofollow":""},"_id":"bf46544"}],"icon_color":"custom","icon_primary_color":"rgba(255,255,255,0)","icon_secondary_color":"#808080","icon_size":{"unit":"px","size":16},"icon_padding":{"unit":"em","size":0.2},"image_border_width":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"hover_secondary_color":"#e96656","icon_size_mobile":{"unit":"px","size":30}},"elements":[],"isInner":false,"widgetType":"social-icons","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"400818e6","settings":{"_column_size":25,"_inline_size":null,"text_align":"center"},"elements":[{"id":"55d952d9","settings":{"image":{"id":3958,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-team3.png"},"image_size":"full","image_border_width":{"unit":"px","top":"10","right":"10","bottom":"10","left":"10","isLinked":true},"image_border_color":"#ececec","image_border_radius":{"unit":"%","top":"100","right":"100","bottom":"100","left":"100","isLinked":true},"_margin":{"unit":"px","top":"0","right":"40","bottom":"30","left":"40","isLinked":false},"_border_hover_color":"#e96656","_margin_tablet":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"_margin_mobile":{"unit":"px","top":"0","right":"60","bottom":"0","left":"60","isLinked":false},"_border_color":"#ececec","align":"left","align_tablet":"center","align_mobile":"center"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"},{"id":"731bacda","settings":{"title":"Tonya garcia","header_size":"h3","title_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":17},"typography_font_weight":"700","typography_text_transform":"uppercase","_margin":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false},"typography_font_family":"Lato","typography_line_height":{"unit":"px","size":26}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"191e62ee","settings":{"weight":{"unit":"px","size":2},"color":"#3ab0e2","width":{"unit":"px","size":95},"gap":{"unit":"px","size":0},"_margin":{"unit":"px","top":"-15","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[],"isInner":false,"widgetType":"divider","elType":"widget"},{"id":"530448e5","settings":{"editor":"<p style=\"text-align: center;\">Account Manager<\/p>","text_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":13},"_margin":{"unit":"px","top":"-20","right":"0","bottom":"0","left":"0","isLinked":false},"_padding":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"typography_font_family":"Lato","typography_font_weight":"400","typography_line_height":{"unit":"px","size":""}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"},{"id":"6ba907c6","settings":{"social_icon_list":[{"social":"fa fa-facebook","_id":"723f275","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-behance","_id":"efd3ea7","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-dribbble","_id":"96985ec","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-linkedin","link":{"url":"","is_external":"true","nofollow":""},"_id":"b83a426"}],"icon_color":"custom","icon_primary_color":"rgba(255,255,255,0)","icon_secondary_color":"#808080","icon_size":{"unit":"px","size":16},"icon_padding":{"unit":"em","size":0.2},"image_border_width":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"hover_secondary_color":"#e96656","icon_size_mobile":{"unit":"px","size":30}},"elements":[],"isInner":false,"widgetType":"social-icons","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"8d2ff16","settings":{"_column_size":25,"_inline_size":null,"text_align":"center"},"elements":[{"id":"533a2e15","settings":{"image":{"id":3959,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-team4.png"},"image_size":"full","image_border_width":{"unit":"px","top":"10","right":"10","bottom":"10","left":"10","isLinked":true},"image_border_color":"#ececec","image_border_radius":{"unit":"%","top":"100","right":"100","bottom":"100","left":"100","isLinked":true},"_margin":{"unit":"px","top":"0","right":"40","bottom":"30","left":"40","isLinked":false},"_border_hover_color":"#e96656","_margin_tablet":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"_margin_mobile":{"unit":"px","top":"0","right":"60","bottom":"0","left":"60","isLinked":false},"_border_color":"#ececec","align":"left","align_tablet":"center","align_mobile":"center"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"},{"id":"5bf96a68","settings":{"title":"Jason Lane","header_size":"h3","title_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":17},"typography_font_weight":"700","typography_text_transform":"uppercase","_margin":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false},"typography_font_family":"Lato","typography_line_height":{"unit":"px","size":26}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"220a2475","settings":{"weight":{"unit":"px","size":2},"color":"#f7d861","width":{"unit":"px","size":95},"gap":{"unit":"px","size":0},"_margin":{"unit":"px","top":"-15","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[],"isInner":false,"widgetType":"divider","elType":"widget"},{"id":"2779715d","settings":{"editor":"<p style=\"text-align: center;\">Business Development<\/p>","text_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":13},"_margin":{"unit":"px","top":"-20","right":"0","bottom":"0","left":"0","isLinked":false},"_padding":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"typography_font_family":"Lato","typography_font_weight":"400","typography_line_height":{"unit":"px","size":""}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"},{"id":"7e7fce1a","settings":{"social_icon_list":[{"social":"fa fa-twitter","_id":"8a8b00c","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-behance","_id":"723f275","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-dribbble","_id":"96985ec","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-linkedin","link":{"url":"","is_external":"true","nofollow":""},"_id":"67700c8"}],"icon_color":"custom","icon_primary_color":"rgba(255,255,255,0)","icon_secondary_color":"#808080","icon_size":{"unit":"px","size":16},"icon_padding":{"unit":"em","size":0.2},"image_border_width":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"hover_secondary_color":"#e96656","icon_size_mobile":{"unit":"px","size":30}},"elements":[],"isInner":false,"widgetType":"social-icons","elType":"widget"}],"isInner":true,"elType":"column"}],"isInner":true,"elType":"section"}],"isInner":false,"elType":"column"}],"isInner":false,"elType":"section"},{"id":"468da859","settings":{"background_background":"classic","background_color":"#8c7620","margin":{"unit":"px","top":"0","right":0,"bottom":"0","left":0,"isLinked":false},"padding":{"unit":"px","top":"100","right":"0","bottom":"100","left":"0","isLinked":false},"_element_id":"testimonials","margin_mobile":{"unit":"px","top":"","right":0,"bottom":"","left":0,"isLinked":true},"padding_mobile":{"unit":"px","top":"50","right":"0","bottom":"45","left":"0","isLinked":false}},"elements":[{"id":"1d6bbaf3","settings":{"_column_size":100,"_inline_size":null,"animation_duration":"slow","animation_delay":700,"margin_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"padding_mobile":{"unit":"px","top":"0","right":"30","bottom":"0","left":"30","isLinked":false}},"elements":[{"id":"3a587d1c","settings":{"title":"Testimonials","title_color":"#ffffff","typography_typography":"custom","typography_font_size":{"unit":"px","size":45},"typography_text_transform":"uppercase","_margin":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false},"align":"center","typography_font_family":"Montserrat","typography_font_weight":"700","typography_font_size_mobile":{"unit":"px","size":22}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"7335cfa","settings":{"title":"Get testimonials from your clients and then display them here.","header_size":"h4","title_color":"#ffffff","typography_typography":"custom","typography_font_size":{"unit":"px","size":16},"_margin":{"unit":"px","top":"0","right":"0","bottom":"75","left":"0","isLinked":false},"align":"center","typography_font_family":"Lato","typography_font_weight":"400","typography_line_height":{"unit":"px","size":""},"typography_line_height_mobile":{"unit":"px","size":24}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"382e7771","settings":{"structure":"30","animation":"fadeInRight","gap":"no"},"elements":[{"id":"38b66b7f","settings":{"_column_size":33,"_inline_size":null,"background_background":"classic","background_color":"#ffffff","border_radius":{"unit":"px","top":"4","right":"4","bottom":"4","left":"4","isLinked":true},"margin":{"unit":"px","top":"0","right":"13","bottom":"0","left":"13","isLinked":false},"margin_mobile":{"unit":"px","top":"0","right":"0","bottom":"15","left":"0","isLinked":false},"padding":{"unit":"px","top":"25","right":"25","bottom":"25","left":"25","isLinked":true}},"elements":[{"id":"1bf4690c","settings":{"editor":"<p style=\"text-align: left;\"><span id=\"zerif_testim-widget-1\" class=\"feedback-box\">Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur nec sem vel sapien venenatis mattis non vitae augue. Nullam congue commodo lorem vitae facilisis. Suspendisse malesuada id turpis interdum dictum.<\/span><\/p>","text_color":"#000000","typography_typography":"custom","typography_font_size":{"unit":"px","size":15},"typography_line_height":{"unit":"em","size":1.5},"_padding":{"unit":"px","top":"0","right":"0","bottom":"30","left":"0","isLinked":false},"_background_background":"classic","typography_font_family":"Lato","typography_font_weight":"400"},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"},{"id":"27b03b7f","settings":{"icon":"fa fa-quote-left","align":"left","align_tablet":"center","primary_color":"#e96656","_margin":{"unit":"px","top":"0","right":"0","bottom":"-80","left":"0","isLinked":false},"_margin_tablet":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[],"isInner":false,"widgetType":"icon","elType":"widget"},{"id":"78719b71","settings":{"editor":"<p>Dana Lorem<\/p>","align":"center","text_color":"#404040","typography_typography":"custom","typography_font_family":"Homemade Apple","typography_font_size":{"unit":"px","size":16},"typography_font_weight":"400"},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"},{"id":"1d9bd3dd","settings":{"image":{"id":3960,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zeriftestimonial1.jpg"},"align":"right","width":{"unit":"px","size":""},"image_border_border":"solid","image_border_width":{"unit":"px","top":"3","right":"3","bottom":"3","left":"3","isLinked":true},"image_border_color":"#f6f6f6","image_border_radius":{"unit":"%","top":"100","right":"100","bottom":"100","left":"100","isLinked":true},"_margin":{"unit":"px","top":"-0","right":"0","bottom":"0","left":"0","isLinked":false},"image_size":"full"},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"4ecffdf0","settings":{"_column_size":33,"_inline_size":null,"background_background":"classic","background_color":"#ffffff","border_radius":{"unit":"px","top":"4","right":"4","bottom":"4","left":"4","isLinked":true},"margin":{"unit":"px","top":"0","right":"13","bottom":"0","left":"13","isLinked":false},"margin_mobile":{"unit":"px","top":"0","right":"0","bottom":"15","left":"0","isLinked":false},"padding":{"unit":"px","top":"25","right":"25","bottom":"25","left":"25","isLinked":true}},"elements":[{"id":"5dc31139","settings":{"editor":"<p style=\"text-align: left;\"><span id=\"zerif_testim-widget-1\" class=\"feedback-box\">Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur nec sem vel sapien venenatis mattis non vitae augue. Nullam congue commodo lorem vitae facilisis. Suspendisse malesuada id turpis interdum dictum.<\/span><\/p>","text_color":"#000000","typography_typography":"custom","typography_font_size":{"unit":"px","size":15},"typography_line_height":{"unit":"em","size":1.5},"_padding":{"unit":"px","top":"0","right":"0","bottom":"30","left":"0","isLinked":false},"_background_background":"classic","typography_font_family":"Lato","typography_font_weight":"400"},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"},{"id":"10b596b1","settings":{"icon":"fa fa-quote-left","align":"left","align_tablet":"center","primary_color":"#e96656","_margin":{"unit":"px","top":"0","right":"0","bottom":"-80","left":"0","isLinked":false},"_margin_tablet":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[],"isInner":false,"widgetType":"icon","elType":"widget"},{"id":"35111f88","settings":{"editor":"<p>Linda Guthrie<\/p>","align":"center","text_color":"#404040","typography_typography":"custom","typography_font_family":"Homemade Apple","typography_font_size":{"unit":"px","size":16},"typography_font_weight":"400"},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"},{"id":"66192d16","settings":{"image":{"id":3961,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-testimonial2.jpg"},"align":"right","width":{"unit":"px","size":""},"image_border_border":"solid","image_border_width":{"unit":"px","top":"3","right":"3","bottom":"3","left":"3","isLinked":true},"image_border_color":"#f6f6f6","image_border_radius":{"unit":"%","top":"50","right":"50","bottom":"50","left":"50","isLinked":true},"_margin":{"unit":"px","top":"-60","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"}],"isInner":true,"elType":"column"},{"id":"57cea26","settings":{"_column_size":33,"_inline_size":null,"background_background":"classic","background_color":"#ffffff","border_radius":{"unit":"px","top":"4","right":"4","bottom":"4","left":"4","isLinked":true},"margin":{"unit":"px","top":"0","right":"13","bottom":"0","left":"13","isLinked":false},"margin_mobile":{"unit":"px","top":"0","right":"0","bottom":"15","left":"0","isLinked":false},"padding":{"unit":"px","top":"25","right":"25","bottom":"25","left":"25","isLinked":true}},"elements":[{"id":"6ec14415","settings":{"editor":"<p style=\"text-align: left;\"><span id=\"zerif_testim-widget-1\" class=\"feedback-box\">Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur nec sem vel sapien venenatis mattis non vitae augue. Nullam congue commodo lorem vitae facilisis. Suspendisse malesuada id turpis interdum dictum.<\/span><\/p>","text_color":"#000000","typography_typography":"custom","typography_font_size":{"unit":"px","size":15},"typography_line_height":{"unit":"em","size":1.5},"_padding":{"unit":"px","top":"0","right":"0","bottom":"30","left":"0","isLinked":false},"_background_background":"classic","typography_font_family":"Lato","typography_font_weight":"400"},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"},{"id":"23be07b2","settings":{"icon":"fa fa-quote-left","align":"left","align_tablet":"center","primary_color":"#e96656","_margin":{"unit":"px","top":"0","right":"0","bottom":"-80","left":"0","isLinked":false},"_margin_tablet":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[],"isInner":false,"widgetType":"icon","elType":"widget"},{"id":"756527c","settings":{"editor":"<p><span>Cynthia Henry<\/span><\/p>","align":"center","text_color":"#404040","typography_typography":"custom","typography_font_family":"Homemade Apple","typography_font_size":{"unit":"px","size":16},"typography_font_weight":"400"},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"},{"id":"70820584","settings":{"image":{"id":3962,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-testimonial3.jpg"},"align":"right","width":{"unit":"px","size":""},"image_border_border":"solid","image_border_width":{"unit":"px","top":"3","right":"3","bottom":"3","left":"3","isLinked":true},"image_border_color":"#f6f6f6","image_border_radius":{"unit":"%","top":"50","right":"50","bottom":"50","left":"50","isLinked":true},"_margin":{"unit":"px","top":"-60","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[],"isInner":false,"widgetType":"image","elType":"widget"}],"isInner":true,"elType":"column"}],"isInner":true,"elType":"section"}],"isInner":false,"elType":"column"}],"isInner":false,"elType":"section"},{"id":"6ce8ebfa","settings":{"structure":"20","background_background":"classic","background_color":"#e96656","padding":{"unit":"px","top":"70","right":"0","bottom":"70","left":"0","isLinked":false},"padding_mobile":{"unit":"px","top":"45","right":"0","bottom":"45","left":"0","isLinked":false}},"elements":[{"id":"57144328","settings":{"_column_size":50,"_inline_size":80,"content_position":"center"},"elements":[{"id":"698ab33f","settings":{"title":"Use these ribbons to display calls to action mid-page.","header_size":"h3","align":"left","align_mobile":"center","title_color":"#ffffff","typography_typography":"custom","typography_font_family":"Lato","typography_font_size":{"unit":"px","size":24},"typography_font_weight":"400","_animation":"fadeInLeft","typography_font_size_mobile":{"unit":"px","size":22}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"}],"isInner":false,"elType":"column"},{"id":"3385800b","settings":{"_column_size":50,"_inline_size":20,"content_position":"center"},"elements":[{"id":"6a18bceb","settings":{"text":"View article","size":"md","typography_typography":"custom","typography_text_transform":"uppercase","background_color":"#db5a4a","button_background_hover_color":"#cb4332","align":"right","typography_font_family":"Lato","typography_font_size":{"unit":"px","size":14},"typography_font_weight":"400","typography_line_height":{"unit":"em","size":1.42857143},"button_text_color":"#ffffff","_animation":"fadeInRight","align_mobile":"center","hover_color":"#ffffff"},"elements":[],"isInner":false,"widgetType":"button","elType":"widget"}],"isInner":false,"elType":"column"}],"isInner":false,"elType":"section"},{"id":"79095792","settings":{"margin":{"unit":"px","top":"","right":0,"bottom":"","left":0,"isLinked":true},"_element_id":"latestnews","background_background":"classic","padding":{"unit":"px","top":"100","right":"0","bottom":"66","left":"0","isLinked":false},"padding_mobile":{"unit":"px","top":"50","right":"0","bottom":"33","left":"0","isLinked":false},"background_color":"#ffffff"},"elements":[{"id":"192f0a03","settings":{"_column_size":100},"elements":[{"id":"7d2f419b","settings":{"title":"BLOG \/ LATEST NEWS","title_color":"#404040","typography_typography":"custom","typography_font_size":{"unit":"px","size":45},"typography_text_transform":"uppercase","_margin":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false},"align":"center","typography_font_family":"Montserrat","typography_font_weight":"700"},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"37fcda6","settings":{"title":"Your latest posts displayed inside a nice slider. You can customize what the slider looks like.","header_size":"h4","title_color":"#000000","typography_typography":"custom","typography_font_size":{"unit":"px","size":16},"_margin":{"unit":"px","top":"0","right":"0","bottom":"50","left":"0","isLinked":false},"align":"center","typography_font_family":"Lato","typography_font_weight":"400"},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"28ee52bc","settings":{"grid_post_categories":"uncategorized","grid_items":4,"grid_columns":"4","grid_image_height":{"unit":"px","size":138},"grid_title_tag":"h3","grid_meta_hide":"yes","grid_content_default_btn_text":"Leer m\u00e1s","grid_content_alignment":"center","grid_style_columns_margin":{"unit":"px","size":""},"grid_style_rows_margin":{"unit":"px","size":20},"grid_image_style_box_shadow_box_shadow_type":"yes","grid_image_style_box_shadow_box_shadow":{"horizontal":0,"vertical":0,"blur":0,"spread":0,"color":"rgba(255,255,255,0)"},"grid_title_style_typography_typography":"custom","grid_title_style_typography_font_size":{"unit":"px","size":16},"grid_title_style_typography_font_weight":"700","grid_title_style_typography_text_transform":"uppercase","grid_title_style_typography_line_height":{"unit":"px","size":""},"grid_title_style_color":"#404040","grid_content_style_typography_typography":"custom","grid_content_style_typography_font_size":{"unit":"px","size":14},"grid_content_style_typography_font_weight":"400","grid_content_style_color":"#777","grid_button_style_typography_typography":"custom","grid_button_style_typography_font_weight":"normal","grid_button_style_normal_text_color":"#e96656","grid_button_style_normal_bg_color":"rgba(255,255,255,0)","_animation":"fadeInLeft","animation_duration":"slow","grid_items_style_background_background":"classic","grid_title_style_margin":{"unit":"px","top":"0","right":"0","bottom":"30","left":"0","isLinked":false},"grid_content_style_margin":{"unit":"px","top":"10","right":"0","bottom":"10","left":"0","isLinked":false},"grid_pagination_alignment":"left","grid_content_default_btn":"","grid_title_style_typography_font_family":"Lato","grid_content_style_typography_font_family":"Lato","grid_content_style_typography_line_height":{"unit":"px","size":18}},"elements":[],"isInner":false,"widgetType":"obfx-posts-grid","elType":"widget"}],"isInner":false,"elType":"column"}],"isInner":false,"elType":"section"},{"id":"379b997","settings":{"background_background":"classic","background_image":{"id":3942,"url":"https:\/\/demo.themeisle.com\/hestia-pro-demo-content\/wp-content\/uploads\/sites\/105\/2018\/06\/zerif-header.jpg"},"background_position":"top center","background_attachment":"fixed","background_repeat":"no-repeat","background_size":"auto","background_overlay_background":"classic","background_overlay_color":"#000000","margin":{"unit":"px","top":"","right":0,"bottom":"","left":0,"isLinked":true},"padding":{"unit":"px","top":"100","right":"0","bottom":"95","left":"0","isLinked":false},"_element_id":"contact","padding_mobile":{"unit":"px","top":"50","right":"0","bottom":"45","left":"0","isLinked":false}},"elements":[{"id":"5c410c0f","settings":{"_column_size":100,"_inline_size":null,"animation_duration":"slow","animation_delay":700,"padding":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false},"margin":{"unit":"px","top":"0","right":"50","bottom":"0","left":"50","isLinked":false},"margin_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true}},"elements":[{"id":"5ff46321","settings":{"title":"get in touch","title_color":"#ffffff","typography_typography":"custom","typography_font_size":{"unit":"px","size":45},"typography_text_transform":"uppercase","align":"center","typography_font_family":"Montserrat","typography_font_weight":"700","typography_font_size_mobile":{"unit":"px","size":22}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"4846ecb4","settings":{"title":"Big and mobile-optimized contact form integrated. All fields are customizable.","header_size":"h4","title_color":"#ffffff","typography_typography":"custom","typography_font_size":{"unit":"px","size":16},"_margin":{"unit":"px","top":"0","right":"0","bottom":"50","left":"0","isLinked":false},"align":"center","typography_font_family":"Lato","typography_font_weight":"400","typography_line_height":{"unit":"px","size":2},"typography_line_height_mobile":{"unit":"px","size":24}},"elements":[],"isInner":false,"widgetType":"heading","elType":"widget"},{"id":"246c7690","settings":{"form_fields":[{"key":"name","type":"text","label":"","requirement":"","placeholder":"Your Name","width":"100","_id":"d62c7cd","field_width":"33","field_width_tablet":"","field_width_mobile":""},{"key":"email","type":"email","label":"","requirement":"","placeholder":"Email address","width":"100","_id":"0c70b95","field_width":"33","field_width_tablet":"","field_width_mobile":""},{"key":"phone","type":"number","label":"","requirement":"","placeholder":"Phone Nr","width":"100","_id":"b13a638","field_width":"33","field_width_tablet":"","field_width_mobile":""},{"key":"message","type":"textarea","label":"","requirement":"","placeholder":"Your message","width":"100","_id":"f19d07f","field_width":"100","field_width_tablet":"","field_width_mobile":""}],"to_send_email":"friends@themeisle.com","submit_label":"Send message","align_submit":"right","column_gap":{"unit":"px","size":30},"row_gap":{"unit":"px","size":15},"field_typography_typography":"custom","field_background_color":"#fefefe","field_focus_background_color":"#fefefe","field_focus_border_color":"#66afe9","field_focus_border_style":"solid","field_focus_border_width":{"unit":"px","top":"1","right":"1","bottom":"1","left":"1","isLinked":true},"button_background_color":"#e96656","button_background_hover_color":"cb4332","_margin":{"unit":"px","top":"0","right":"50","bottom":"0","left":"50","isLinked":false},"align_submit_mobile":"center","field-text-padding":{"unit":"px","top":"9","right":"15","bottom":"9","left":"15","isLinked":false},"field_border_radius":{"unit":"px","top":"3","right":"3","bottom":"3","left":"3","isLinked":true}},"elements":[],"isInner":false,"widgetType":"content_form_contact","elType":"widget"}],"isInner":false,"elType":"column"}],"isInner":false,"elType":"section"},{"id":"22e51571","settings":{"structure":"40","background_background":"classic","background_color":"#272727","margin_mobile":{"unit":"px","top":"0","right":0,"bottom":"0","left":0,"isLinked":true},"padding_mobile":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":true},"padding":{"unit":"px","top":"0","right":"270","bottom":"0","left":"270","isLinked":false},"gap":"no","padding_tablet":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[{"id":"5ebd333e","settings":{"_column_size":25,"_inline_size":25.964,"space_between_widgets":0,"padding":{"unit":"px","top":"67","right":"0","bottom":"30","left":"0","isLinked":false},"padding_mobile":{"unit":"px","top":"30","right":"0","bottom":"15","left":"0","isLinked":false}},"elements":[{"id":"d1dd796","settings":{"icon":"fa fa-map-marker","size":{"unit":"px","size":26},"primary_color":"#e96656"},"elements":[],"isInner":false,"widgetType":"icon","elType":"widget"},{"id":"71aab119","settings":{"editor":"<p>San Francisco - Adress - 18 California Street 1100.<\/p>","align":"center","text_color":"#939393","typography_typography":"custom","typography_font_family":"Lato","typography_font_size":{"unit":"px","size":14},"typography_font_weight":"400","typography_line_height":{"unit":"px","size":20},"_padding":{"unit":"px","top":"0","right":"20","bottom":"0","left":"20","isLinked":false}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"}],"isInner":false,"elType":"column"},{"id":"22d7d043","settings":{"_column_size":25,"_inline_size":23.989,"space_between_widgets":0,"padding":{"unit":"px","top":"67","right":"0","bottom":"30","left":"0","isLinked":false},"padding_mobile":{"unit":"px","top":"30","right":"0","bottom":"15","left":"0","isLinked":false}},"elements":[{"id":"363a22f0","settings":{"icon":"fa fa-envelope","size":{"unit":"px","size":26},"primary_color":"#34cd8c"},"elements":[],"isInner":false,"widgetType":"icon","elType":"widget"},{"id":"48005469","settings":{"editor":"<p>friends@themeisle.com<\/p>","align":"center","text_color":"#939393","typography_typography":"custom","typography_font_family":"Lato","typography_font_size":{"unit":"px","size":14},"typography_font_weight":"400","typography_line_height":{"unit":"px","size":20},"_padding":{"unit":"px","top":"0","right":"20","bottom":"0","left":"20","isLinked":false},"_padding_tablet":{"unit":"px","top":"0","right":"0","bottom":"0","left":"0","isLinked":false}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"}],"isInner":false,"elType":"column"},{"id":"799dd49","settings":{"_column_size":25,"_inline_size":22.154,"space_between_widgets":0,"padding":{"unit":"px","top":"67","right":"0","bottom":"30","left":"0","isLinked":false},"padding_mobile":{"unit":"px","top":"30","right":"0","bottom":"15","left":"0","isLinked":false}},"elements":[{"id":"c5692f1","settings":{"icon":"fa fa-phone-square","primary_color":"#3ca8dc","size":{"unit":"px","size":26}},"elements":[],"isInner":false,"widgetType":"icon","elType":"widget"},{"id":"2edc3e78","settings":{"editor":"<p>0 332 548 987<\/p>","align":"center","text_color":"#939393","typography_typography":"custom","typography_font_family":"Lato","typography_font_size":{"unit":"px","size":14},"typography_font_weight":"400","typography_line_height":{"unit":"px","size":20},"_padding":{"unit":"px","top":"0","right":"20","bottom":"0","left":"20","isLinked":false}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"}],"isInner":false,"elType":"column"},{"id":"582b9111","settings":{"_column_size":25,"_inline_size":27.893,"content_position":"center","background_background":"classic","background_color":"#171717","padding_mobile":{"unit":"px","top":"30","right":"0","bottom":"15","left":"0","isLinked":false}},"elements":[{"id":"46dc43fc","settings":{"social_icon_list":[{"social":"fa fa-facebook","_id":"5e5d300","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-twitter","_id":"e053ebc","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-linkedin","_id":"5026287","link":{"url":"","is_external":"true","nofollow":""}},{"social":"fa fa-behance","link":{"url":"","is_external":"true","nofollow":""},"_id":"01bb77a"},{"social":"fa fa-dribbble","link":{"url":"","is_external":"true","nofollow":""},"_id":"97496cc"},{"social":"fa fa-instagram","link":{"url":"","is_external":"true","nofollow":""},"_id":"0586fe1"}],"icon_color":"custom","icon_primary_color":"rgba(147,147,147,0.02)","icon_secondary_color":"#939393","icon_size":{"unit":"px","size":18},"icon_padding":{"unit":"em","size":0.2},"icon_spacing":{"unit":"px","size":0},"hover_secondary_color":"#e96656"},"elements":[],"isInner":false,"widgetType":"social-icons","elType":"widget"},{"id":"6700100c","settings":{"editor":"<p style=\"text-align: center;\"><span>\u00a9<\/span>Themeisle<br \/>Zelle Lite <span style=\"color: #666666;\">developed by<\/span> <a href=\"https:\/\/themeisle.com\/\"><span style=\"color: #939393;\">ThemeIsle<\/span><\/a><\/p>","text_color":"#939393","typography_typography":"custom","typography_font_family":"Lato","typography_font_size":{"unit":"px","size":14},"typography_font_weight":"400","typography_line_height":{"unit":"px","size":20}},"elements":[],"isInner":false,"widgetType":"text-editor","elType":"widget"}],"isInner":false,"elType":"column"}],"isInner":false,"elType":"section"}]}
migration/zelle/zelle.png ADDED
Binary file
readme.txt ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Cloud Templates & Patterns collection ===
2
+ Contributors: themeisle
3
+ Tags: neve, templates, patterns, blocks, starter, sites, demo, content, import
4
+ Requires at least: 4.7
5
+ Tested up to: 5.4
6
+ Requires PHP: 5.6
7
+ Stable tag: trunk
8
+ License: GPLv3
9
+ License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
10
+
11
+ A cloud based service with 100+ templates and starter sites for Neve theme.
12
+
13
+ == Description ==
14
+
15
+ = TEMPLATE SERVICE FOR ELEMENTOR, BEAVER BUILDER, BRIZY AND GUTENBERG, DIVI and THRIVE =
16
+
17
+
18
+ A cloud based templates library which enables you to create ready-made website in no time.
19
+
20
+ All templates can be previewed on [demosites.io](https://demosites.io/), their import into your site is facilitated by this plugin.
21
+
22
+ The plugin is relying on the service behind api.themeisle.com for accessing the template collection list and their individual structure on import.
23
+
24
+ No account is required to access the service template collection and the privacy policy can be found [here](https://themeisle.com/privacy-policy/).
25
+
26
+ == Frequently Asked Questions ==
27
+
28
+ == Changelog ==
29
+
30
+ ##### [Version 1.0.7](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.6...v1.0.7) (2020-07-29)
31
+
32
+ chore: adds SVN deployment workflow
33
+
34
+
35
+
36
+
37
+ ##### [Version 1.0.6](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.5...v1.0.6) (2020-07-27)
38
+
39
+ > Things are getting better every day. 🚀
40
+
41
+
42
+
43
+
44
+ ##### [Version 1.0.5](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.4...v1.0.5) (2020-07-27)
45
+
46
+ > Things are getting better every day. 🚀
47
+
48
+
49
+
50
+
51
+ ##### [Version 1.0.4](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.3...v1.0.4) (2020-07-24)
52
+
53
+ Fetch starter sites remotely
54
+
55
+
56
+
57
+
58
+ ##### [Version 1.0.3](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.2...v1.0.3) (2020-07-23)
59
+
60
+ > Things are getting better every day. 🚀
61
+
62
+
63
+
64
+
65
+ ##### [Version 1.0.2](https://github.com/Codeinwp/templates-patterns-collection/compare/v1.0.1...v1.0.2) (2020-07-23)
66
+
67
+ > Things are getting better every day. 🚀
68
+
69
+
70
+
71
+
72
+
73
+
templates-patterns-collection.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin Name: Templates Patterns Collection
4
+ * Description: This plugin is an add-on to Neve WordPress theme which offers access to Templates and Block Patterns library service to be used with the theme.
5
+ * Version: 1.0.7
6
+ * Author: ThemeIsle
7
+ * Author URI: https://themeisle.com
8
+ * License: GPLv3
9
+ * License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
10
+ * Text Domain: templates-patterns-collection
11
+ * Domain Path: /languages
12
+ * WordPress Available: yes
13
+ * Requires License: no
14
+ *
15
+ * @package templates-patterns-collection
16
+ */
17
+
18
+ add_action( 'admin_notices', 'ti_tpc_plugins_page_notice' );
19
+ add_action( 'init', 'ti_tpc_load_textdomain' );
20
+
21
+ /**
22
+ * Plugins page notice if we don't have neve activated.
23
+ */
24
+ function ti_tpc_plugins_page_notice() {
25
+ if ( defined( 'NEVE_VERSION' ) ) {
26
+ return;
27
+ }
28
+
29
+ $screen = get_current_screen();
30
+ if ( ! isset( $screen->id ) ) {
31
+ return;
32
+ }
33
+
34
+ if ( $screen->id !== 'plugins' ) {
35
+ return;
36
+ }
37
+
38
+ $notice = '<div class="notice notice-warning">';
39
+ $notice .= '<p>';
40
+ $notice .= sprintf(
41
+ __( 'You need to have %1$s installed and activated to use %2$s.' ),
42
+ '<strong>' . __( 'Neve Theme' ) . '</strong>',
43
+ '<strong>' . __( 'Templates Patterns Collection' ) . '</strong>'
44
+ );
45
+ $notice .= '</p>';
46
+ $notice .= '<p class="actions">';
47
+ $notice .= '<a class="button button-primary" href="' . esc_url( admin_url( 'theme-install.php?theme=neve' ) ) . '">';
48
+ $notice .= __( 'Install and Activate Neve' );
49
+ $notice .= '</a>';
50
+ $notice .= '</p>';
51
+ $notice .= '</div>';
52
+
53
+ echo wp_kses_post( $notice );
54
+ }
55
+
56
+ /**
57
+ * Load the localisation file.
58
+ */
59
+ function ti_tpc_load_textdomain() {
60
+ load_plugin_textdomain( 'templates-patterns-collection', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
61
+ }
62
+
63
+ add_action( 'init', 'ti_tpc_run' );
64
+
65
+ function ti_tpc_run() {
66
+ if ( ! defined( 'NEVE_VERSION' ) ) {
67
+ return;
68
+ }
69
+
70
+ if ( ! defined( 'TI_ONBOARDING_DISABLED' ) ) {
71
+ define( 'TI_ONBOARDING_DISABLED', false );
72
+ }
73
+
74
+ $autoload_path = __DIR__ . '/vendor/autoload.php';
75
+ if ( is_file( $autoload_path ) ) {
76
+ require_once $autoload_path;
77
+ }
78
+
79
+ if ( class_exists( 'WP_CLI' ) ) {
80
+ require_once 'includes/WP_Cli.php';
81
+ }
82
+ }
83
+
84
+
85
+
vendor/autoload.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload.php @generated by Composer
4
+
5
+ require_once __DIR__ . '/composer/autoload_real.php';
6
+
7
+ return ComposerAutoloaderInit861fe897ba6144e34238b47311eb75bf::getLoader();
vendor/composer/ClassLoader.php ADDED
@@ -0,0 +1,445 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Composer.
5
+ *
6
+ * (c) Nils Adermann <naderman@naderman.de>
7
+ * Jordi Boggiano <j.boggiano@seld.be>
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ namespace Composer\Autoload;
14
+
15
+ /**
16
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
17
+ *
18
+ * $loader = new \Composer\Autoload\ClassLoader();
19
+ *
20
+ * // register classes with namespaces
21
+ * $loader->add('Symfony\Component', __DIR__.'/component');
22
+ * $loader->add('Symfony', __DIR__.'/framework');
23
+ *
24
+ * // activate the autoloader
25
+ * $loader->register();
26
+ *
27
+ * // to enable searching the include path (eg. for PEAR packages)
28
+ * $loader->setUseIncludePath(true);
29
+ *
30
+ * In this example, if you try to use a class in the Symfony\Component
31
+ * namespace or one of its children (Symfony\Component\Console for instance),
32
+ * the autoloader will first look for the class under the component/
33
+ * directory, and it will then fallback to the framework/ directory if not
34
+ * found before giving up.
35
+ *
36
+ * This class is loosely based on the Symfony UniversalClassLoader.
37
+ *
38
+ * @author Fabien Potencier <fabien@symfony.com>
39
+ * @author Jordi Boggiano <j.boggiano@seld.be>
40
+ * @see http://www.php-fig.org/psr/psr-0/
41
+ * @see http://www.php-fig.org/psr/psr-4/
42
+ */
43
+ class ClassLoader
44
+ {
45
+ // PSR-4
46
+ private $prefixLengthsPsr4 = array();
47
+ private $prefixDirsPsr4 = array();
48
+ private $fallbackDirsPsr4 = array();
49
+
50
+ // PSR-0
51
+ private $prefixesPsr0 = array();
52
+ private $fallbackDirsPsr0 = array();
53
+
54
+ private $useIncludePath = false;
55
+ private $classMap = array();
56
+ private $classMapAuthoritative = false;
57
+ private $missingClasses = array();
58
+ private $apcuPrefix;
59
+
60
+ public function getPrefixes()
61
+ {
62
+ if (!empty($this->prefixesPsr0)) {
63
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
64
+ }
65
+
66
+ return array();
67
+ }
68
+
69
+ public function getPrefixesPsr4()
70
+ {
71
+ return $this->prefixDirsPsr4;
72
+ }
73
+
74
+ public function getFallbackDirs()
75
+ {
76
+ return $this->fallbackDirsPsr0;
77
+ }
78
+
79
+ public function getFallbackDirsPsr4()
80
+ {
81
+ return $this->fallbackDirsPsr4;
82
+ }
83
+
84
+ public function getClassMap()
85
+ {
86
+ return $this->classMap;
87
+ }
88
+
89
+ /**
90
+ * @param array $classMap Class to filename map
91
+ */
92
+ public function addClassMap(array $classMap)
93
+ {
94
+ if ($this->classMap) {
95
+ $this->classMap = array_merge($this->classMap, $classMap);
96
+ } else {
97
+ $this->classMap = $classMap;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Registers a set of PSR-0 directories for a given prefix, either
103
+ * appending or prepending to the ones previously set for this prefix.
104
+ *
105
+ * @param string $prefix The prefix
106
+ * @param array|string $paths The PSR-0 root directories
107
+ * @param bool $prepend Whether to prepend the directories
108
+ */
109
+ public function add($prefix, $paths, $prepend = false)
110
+ {
111
+ if (!$prefix) {
112
+ if ($prepend) {
113
+ $this->fallbackDirsPsr0 = array_merge(
114
+ (array) $paths,
115
+ $this->fallbackDirsPsr0
116
+ );
117
+ } else {
118
+ $this->fallbackDirsPsr0 = array_merge(
119
+ $this->fallbackDirsPsr0,
120
+ (array) $paths
121
+ );
122
+ }
123
+
124
+ return;
125
+ }
126
+
127
+ $first = $prefix[0];
128
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
129
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
130
+
131
+ return;
132
+ }
133
+ if ($prepend) {
134
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
135
+ (array) $paths,
136
+ $this->prefixesPsr0[$first][$prefix]
137
+ );
138
+ } else {
139
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
140
+ $this->prefixesPsr0[$first][$prefix],
141
+ (array) $paths
142
+ );
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Registers a set of PSR-4 directories for a given namespace, either
148
+ * appending or prepending to the ones previously set for this namespace.
149
+ *
150
+ * @param string $prefix The prefix/namespace, with trailing '\\'
151
+ * @param array|string $paths The PSR-4 base directories
152
+ * @param bool $prepend Whether to prepend the directories
153
+ *
154
+ * @throws \InvalidArgumentException
155
+ */
156
+ public function addPsr4($prefix, $paths, $prepend = false)
157
+ {
158
+ if (!$prefix) {
159
+ // Register directories for the root namespace.
160
+ if ($prepend) {
161
+ $this->fallbackDirsPsr4 = array_merge(
162
+ (array) $paths,
163
+ $this->fallbackDirsPsr4
164
+ );
165
+ } else {
166
+ $this->fallbackDirsPsr4 = array_merge(
167
+ $this->fallbackDirsPsr4,
168
+ (array) $paths
169
+ );
170
+ }
171
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
172
+ // Register directories for a new namespace.
173
+ $length = strlen($prefix);
174
+ if ('\\' !== $prefix[$length - 1]) {
175
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
176
+ }
177
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
178
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
179
+ } elseif ($prepend) {
180
+ // Prepend directories for an already registered namespace.
181
+ $this->prefixDirsPsr4[$prefix] = array_merge(
182
+ (array) $paths,
183
+ $this->prefixDirsPsr4[$prefix]
184
+ );
185
+ } else {
186
+ // Append directories for an already registered namespace.
187
+ $this->prefixDirsPsr4[$prefix] = array_merge(
188
+ $this->prefixDirsPsr4[$prefix],
189
+ (array) $paths
190
+ );
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Registers a set of PSR-0 directories for a given prefix,
196
+ * replacing any others previously set for this prefix.
197
+ *
198
+ * @param string $prefix The prefix
199
+ * @param array|string $paths The PSR-0 base directories
200
+ */
201
+ public function set($prefix, $paths)
202
+ {
203
+ if (!$prefix) {
204
+ $this->fallbackDirsPsr0 = (array) $paths;
205
+ } else {
206
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Registers a set of PSR-4 directories for a given namespace,
212
+ * replacing any others previously set for this namespace.
213
+ *
214
+ * @param string $prefix The prefix/namespace, with trailing '\\'
215
+ * @param array|string $paths The PSR-4 base directories
216
+ *
217
+ * @throws \InvalidArgumentException
218
+ */
219
+ public function setPsr4($prefix, $paths)
220
+ {
221
+ if (!$prefix) {
222
+ $this->fallbackDirsPsr4 = (array) $paths;
223
+ } else {
224
+ $length = strlen($prefix);
225
+ if ('\\' !== $prefix[$length - 1]) {
226
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
227
+ }
228
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
229
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Turns on searching the include path for class files.
235
+ *
236
+ * @param bool $useIncludePath
237
+ */
238
+ public function setUseIncludePath($useIncludePath)
239
+ {
240
+ $this->useIncludePath = $useIncludePath;
241
+ }
242
+
243
+ /**
244
+ * Can be used to check if the autoloader uses the include path to check
245
+ * for classes.
246
+ *
247
+ * @return bool
248
+ */
249
+ public function getUseIncludePath()
250
+ {
251
+ return $this->useIncludePath;
252
+ }
253
+
254
+ /**
255
+ * Turns off searching the prefix and fallback directories for classes
256
+ * that have not been registered with the class map.
257
+ *
258
+ * @param bool $classMapAuthoritative
259
+ */
260
+ public function setClassMapAuthoritative($classMapAuthoritative)
261
+ {
262
+ $this->classMapAuthoritative = $classMapAuthoritative;
263
+ }
264
+
265
+ /**
266
+ * Should class lookup fail if not found in the current class map?
267
+ *
268
+ * @return bool
269
+ */
270
+ public function isClassMapAuthoritative()
271
+ {
272
+ return $this->classMapAuthoritative;
273
+ }
274
+
275
+ /**
276
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
277
+ *
278
+ * @param string|null $apcuPrefix
279
+ */
280
+ public function setApcuPrefix($apcuPrefix)
281
+ {
282
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
283
+ }
284
+
285
+ /**
286
+ * The APCu prefix in use, or null if APCu caching is not enabled.
287
+ *
288
+ * @return string|null
289
+ */
290
+ public function getApcuPrefix()
291
+ {
292
+ return $this->apcuPrefix;
293
+ }
294
+
295
+ /**
296
+ * Registers this instance as an autoloader.
297
+ *
298
+ * @param bool $prepend Whether to prepend the autoloader or not
299
+ */
300
+ public function register($prepend = false)
301
+ {
302
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
303
+ }
304
+
305
+ /**
306
+ * Unregisters this instance as an autoloader.
307
+ */
308
+ public function unregister()
309
+ {
310
+ spl_autoload_unregister(array($this, 'loadClass'));
311
+ }
312
+
313
+ /**
314
+ * Loads the given class or interface.
315
+ *
316
+ * @param string $class The name of the class
317
+ * @return bool|null True if loaded, null otherwise
318
+ */
319
+ public function loadClass($class)
320
+ {
321
+ if ($file = $this->findFile($class)) {
322
+ includeFile($file);
323
+
324
+ return true;
325
+ }
326
+ }
327
+
328
+ /**
329
+ * Finds the path to the file where the class is defined.
330
+ *
331
+ * @param string $class The name of the class
332
+ *
333
+ * @return string|false The path if found, false otherwise
334
+ */
335
+ public function findFile($class)
336
+ {
337
+ // class map lookup
338
+ if (isset($this->classMap[$class])) {
339
+ return $this->classMap[$class];
340
+ }
341
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
342
+ return false;
343
+ }
344
+ if (null !== $this->apcuPrefix) {
345
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
346
+ if ($hit) {
347
+ return $file;
348
+ }
349
+ }
350
+
351
+ $file = $this->findFileWithExtension($class, '.php');
352
+
353
+ // Search for Hack files if we are running on HHVM
354
+ if (false === $file && defined('HHVM_VERSION')) {
355
+ $file = $this->findFileWithExtension($class, '.hh');
356
+ }
357
+
358
+ if (null !== $this->apcuPrefix) {
359
+ apcu_add($this->apcuPrefix.$class, $file);
360
+ }
361
+
362
+ if (false === $file) {
363
+ // Remember that this class does not exist.
364
+ $this->missingClasses[$class] = true;
365
+ }
366
+
367
+ return $file;
368
+ }
369
+
370
+ private function findFileWithExtension($class, $ext)
371
+ {
372
+ // PSR-4 lookup
373
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
374
+
375
+ $first = $class[0];
376
+ if (isset($this->prefixLengthsPsr4[$first])) {
377
+ $subPath = $class;
378
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
379
+ $subPath = substr($subPath, 0, $lastPos);
380
+ $search = $subPath . '\\';
381
+ if (isset($this->prefixDirsPsr4[$search])) {
382
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
383
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
384
+ if (file_exists($file = $dir . $pathEnd)) {
385
+ return $file;
386
+ }
387
+ }
388
+ }
389
+ }
390
+ }
391
+
392
+ // PSR-4 fallback dirs
393
+ foreach ($this->fallbackDirsPsr4 as $dir) {
394
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
395
+ return $file;
396
+ }
397
+ }
398
+
399
+ // PSR-0 lookup
400
+ if (false !== $pos = strrpos($class, '\\')) {
401
+ // namespaced class name
402
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
403
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
404
+ } else {
405
+ // PEAR-like class name
406
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
407
+ }
408
+
409
+ if (isset($this->prefixesPsr0[$first])) {
410
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
411
+ if (0 === strpos($class, $prefix)) {
412
+ foreach ($dirs as $dir) {
413
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
414
+ return $file;
415
+ }
416
+ }
417
+ }
418
+ }
419
+ }
420
+
421
+ // PSR-0 fallback dirs
422
+ foreach ($this->fallbackDirsPsr0 as $dir) {
423
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
424
+ return $file;
425
+ }
426
+ }
427
+
428
+ // PSR-0 include paths.
429
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
430
+ return $file;
431
+ }
432
+
433
+ return false;
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Scope isolated include.
439
+ *
440
+ * Prevents access to $this/self from included files.
441
+ */
442
+ function includeFile($file)
443
+ {
444
+ include $file;
445
+ }
vendor/composer/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Copyright (c) Nils Adermann, Jordi Boggiano
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished
9
+ to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
vendor/composer/autoload_classmap.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_classmap.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'TIOB\\Admin' => $baseDir . '/includes/Admin.php',
10
+ 'TIOB\\Importers\\Content_Importer' => $baseDir . '/includes/Importers/Content_Importer.php',
11
+ 'TIOB\\Importers\\Helpers\\Helper' => $baseDir . '/includes/Importers/Helpers/Helper.php',
12
+ 'TIOB\\Importers\\Helpers\\Importer_Alterator' => $baseDir . '/includes/Importers/Helpers/Importer_Alterator.php',
13
+ 'TIOB\\Importers\\Helpers\\Quiet_Skin' => $baseDir . '/includes/Importers/Helpers/Quiet_Skin.php',
14
+ 'TIOB\\Importers\\Helpers\\Quiet_Skin_Legacy' => $baseDir . '/includes/Importers/Helpers/Quiet_Skin_Legacy.php',
15
+ 'TIOB\\Importers\\Plugin_Importer' => $baseDir . '/includes/Importers/Plugin_Importer.php',
16
+ 'TIOB\\Importers\\Theme_Mods_Importer' => $baseDir . '/includes/Importers/Theme_Mods_Importer.php',
17
+ 'TIOB\\Importers\\WP\\Beaver_Data_Fix' => $baseDir . '/includes/Importers/WP/Beaver_Data_Fix.php',
18
+ 'TIOB\\Importers\\WP\\Beaver_ParserXML' => $baseDir . '/includes/Importers/WP/Beaver_ParserXML.php',
19
+ 'TIOB\\Importers\\WP\\Elementor_Meta_Handler' => $baseDir . '/includes/Importers/WP/Elementor_Meta_Handler.php',
20
+ 'TIOB\\Importers\\WP\\WP_Import' => $baseDir . '/includes/Importers/WP/WP_Import.php',
21
+ 'TIOB\\Importers\\WP\\WXR_Parser' => $baseDir . '/includes/Importers/WP/WXR_Parser.php',
22
+ 'TIOB\\Importers\\WP\\WXR_Parser_SimpleXML' => $baseDir . '/includes/Importers/WP/WXR_Parser_SimpleXML.php',
23
+ 'TIOB\\Importers\\WP\\WXR_Parser_XML' => $baseDir . '/includes/Importers/WP/WXR_Parser_XML.php',
24
+ 'TIOB\\Importers\\Widgets_Importer' => $baseDir . '/includes/Importers/Widgets_Importer.php',
25
+ 'TIOB\\Importers\\Zelle_Importer' => $baseDir . '/includes/Importers/Zelle_Importer.php',
26
+ 'TIOB\\Logger' => $baseDir . '/includes/Logger.php',
27
+ 'TIOB\\Main' => $baseDir . '/includes/Main.php',
28
+ 'TIOB\\Rest_Server' => $baseDir . '/includes/Rest_Server.php',
29
+ 'TIOB\\Sites_Listing' => $baseDir . '/includes/Sites_Listing.php',
30
+ 'TIOB\\WP_Cli' => $baseDir . '/includes/WP_Cli.php',
31
+ );
vendor/composer/autoload_namespaces.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_namespaces.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ );
vendor/composer/autoload_psr4.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_psr4.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'TIOB\\' => array($baseDir . '/includes'),
10
+ );
vendor/composer/autoload_real.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_real.php @generated by Composer
4
+
5
+ class ComposerAutoloaderInit861fe897ba6144e34238b47311eb75bf
6
+ {
7
+ private static $loader;
8
+
9
+ public static function loadClassLoader($class)
10
+ {
11
+ if ('Composer\Autoload\ClassLoader' === $class) {
12
+ require __DIR__ . '/ClassLoader.php';
13
+ }
14
+ }
15
+
16
+ /**
17
+ * @return \Composer\Autoload\ClassLoader
18
+ */
19
+ public static function getLoader()
20
+ {
21
+ if (null !== self::$loader) {
22
+ return self::$loader;
23
+ }
24
+
25
+ spl_autoload_register(array('ComposerAutoloaderInit861fe897ba6144e34238b47311eb75bf', 'loadClassLoader'), true, true);
26
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader();
27
+ spl_autoload_unregister(array('ComposerAutoloaderInit861fe897ba6144e34238b47311eb75bf', 'loadClassLoader'));
28
+
29
+ $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
30
+ if ($useStaticLoader) {
31
+ require_once __DIR__ . '/autoload_static.php';
32
+
33
+ call_user_func(\Composer\Autoload\ComposerStaticInit861fe897ba6144e34238b47311eb75bf::getInitializer($loader));
34
+ } else {
35
+ $map = require __DIR__ . '/autoload_namespaces.php';
36
+ foreach ($map as $namespace => $path) {
37
+ $loader->set($namespace, $path);
38
+ }
39
+
40
+ $map = require __DIR__ . '/autoload_psr4.php';
41
+ foreach ($map as $namespace => $path) {
42
+ $loader->setPsr4($namespace, $path);
43
+ }
44
+
45
+ $classMap = require __DIR__ . '/autoload_classmap.php';
46
+ if ($classMap) {
47
+ $loader->addClassMap($classMap);
48
+ }
49
+ }
50
+
51
+ $loader->register(true);
52
+
53
+ return $loader;
54
+ }
55
+ }
vendor/composer/autoload_static.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_static.php @generated by Composer
4
+
5
+ namespace Composer\Autoload;
6
+
7
+ class ComposerStaticInit861fe897ba6144e34238b47311eb75bf
8
+ {
9
+ public static $prefixLengthsPsr4 = array (
10
+ 'T' =>
11
+ array (
12
+ 'TIOB\\' => 5,
13
+ ),
14
+ );
15
+
16
+ public static $prefixDirsPsr4 = array (
17
+ 'TIOB\\' =>
18
+ array (
19
+ 0 => __DIR__ . '/../..' . '/includes',
20
+ ),
21
+ );
22
+
23
+ public static $classMap = array (
24
+ 'TIOB\\Admin' => __DIR__ . '/../..' . '/includes/Admin.php',
25
+ 'TIOB\\Importers\\Content_Importer' => __DIR__ . '/../..' . '/includes/Importers/Content_Importer.php',
26
+ 'TIOB\\Importers\\Helpers\\Helper' => __DIR__ . '/../..' . '/includes/Importers/Helpers/Helper.php',
27
+ 'TIOB\\Importers\\Helpers\\Importer_Alterator' => __DIR__ . '/../..' . '/includes/Importers/Helpers/Importer_Alterator.php',
28
+ 'TIOB\\Importers\\Helpers\\Quiet_Skin' => __DIR__ . '/../..' . '/includes/Importers/Helpers/Quiet_Skin.php',
29
+ 'TIOB\\Importers\\Helpers\\Quiet_Skin_Legacy' => __DIR__ . '/../..' . '/includes/Importers/Helpers/Quiet_Skin_Legacy.php',
30
+ 'TIOB\\Importers\\Plugin_Importer' => __DIR__ . '/../..' . '/includes/Importers/Plugin_Importer.php',
31
+ 'TIOB\\Importers\\Theme_Mods_Importer' => __DIR__ . '/../..' . '/includes/Importers/Theme_Mods_Importer.php',
32
+ 'TIOB\\Importers\\WP\\Beaver_Data_Fix' => __DIR__ . '/../..' . '/includes/Importers/WP/Beaver_Data_Fix.php',
33
+ 'TIOB\\Importers\\WP\\Beaver_ParserXML' => __DIR__ . '/../..' . '/includes/Importers/WP/Beaver_ParserXML.php',
34
+ 'TIOB\\Importers\\WP\\Elementor_Meta_Handler' => __DIR__ . '/../..' . '/includes/Importers/WP/Elementor_Meta_Handler.php',
35
+ 'TIOB\\Importers\\WP\\WP_Import' => __DIR__ . '/../..' . '/includes/Importers/WP/WP_Import.php',
36
+ 'TIOB\\Importers\\WP\\WXR_Parser' => __DIR__ . '/../..' . '/includes/Importers/WP/WXR_Parser.php',
37
+ 'TIOB\\Importers\\WP\\WXR_Parser_SimpleXML' => __DIR__ . '/../..' . '/includes/Importers/WP/WXR_Parser_SimpleXML.php',
38
+ 'TIOB\\Importers\\WP\\WXR_Parser_XML' => __DIR__ . '/../..' . '/includes/Importers/WP/WXR_Parser_XML.php',
39
+ 'TIOB\\Importers\\Widgets_Importer' => __DIR__ . '/../..' . '/includes/Importers/Widgets_Importer.php',
40
+ 'TIOB\\Importers\\Zelle_Importer' => __DIR__ . '/../..' . '/includes/Importers/Zelle_Importer.php',
41
+ 'TIOB\\Logger' => __DIR__ . '/../..' . '/includes/Logger.php',
42
+ 'TIOB\\Main' => __DIR__ . '/../..' . '/includes/Main.php',
43
+ 'TIOB\\Rest_Server' => __DIR__ . '/../..' . '/includes/Rest_Server.php',
44
+ 'TIOB\\Sites_Listing' => __DIR__ . '/../..' . '/includes/Sites_Listing.php',
45
+ 'TIOB\\WP_Cli' => __DIR__ . '/../..' . '/includes/WP_Cli.php',
46
+ );
47
+
48
+ public static function getInitializer(ClassLoader $loader)
49
+ {
50
+ return \Closure::bind(function () use ($loader) {
51
+ $loader->prefixLengthsPsr4 = ComposerStaticInit861fe897ba6144e34238b47311eb75bf::$prefixLengthsPsr4;
52
+ $loader->prefixDirsPsr4 = ComposerStaticInit861fe897ba6144e34238b47311eb75bf::$prefixDirsPsr4;
53
+ $loader->classMap = ComposerStaticInit861fe897ba6144e34238b47311eb75bf::$classMap;
54
+
55
+ }, null, ClassLoader::class);
56
+ }
57
+ }
vendor/composer/installed.json ADDED
@@ -0,0 +1 @@
 
1
+ []