PluginProbe
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment / 3.1.12
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment v3.1.12
3.1.13 3.1.12 3.1.11 3.1.10 3.1.9 3.1.8 3.1.7 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 All 122 releases
firebox / Inc / Core / Controllers / BoxImport.php

BoxImport.php in FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment 3.1.12, at Inc/Core/Controllers/BoxImport.php

277 lines 7.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package FireBox
4 * @version 3.1.12 Free
5 *
6 * @author FirePlugins <info@fireplugins.com>
7 * @link https://www.fireplugins.com
8 * @copyright Copyright © 2026 FirePlugins All Rights Reserved
9 * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
10 */
11
12 namespace FireBox\Core\Controllers;
13
14 if (!defined('ABSPATH'))
15 {
16 exit; // Exit if accessed directly.
17 }
18
19 use FPFramework\Base\Form;
20
21 class BoxImport extends BaseController
22 {
23 /**
24 * The form settings name
25 *
26 * @var string
27 */
28 const settings_name = 'firebox_import';
29
30 /**
31 * Render the page content
32 *
33 * @return void
34 */
35 public function render()
36 {
37 // page content
38 add_action('firebox/settings_page', [$this, 'settingsPageContent']);
39
40 // render layout
41 firebox()->renderer->admin->render('pages/settings');
42 }
43
44 /**
45 * Import box
46 *
47 * @param array $input
48 *
49 * @return void
50 */
51 public function processBoxesImport($input)
52 {
53 // run a quick security check
54 if (!check_admin_referer('fpf_form_nonce_firebox_import', 'fpf_form_nonce_firebox_import'))
55 {
56 return; // get out if we didn't click the Activate button
57 }
58
59 /**
60 * Importing creates campaigns from a file the user supplies, so it needs an
61 * explicit capability check of its own. Today options.php also enforces
62 * manage_options for this option group, but this method must not depend on
63 * how it happens to be reached.
64 */
65 if (!current_user_can('edit_fireboxes'))
66 {
67 \FPFramework\Libs\AdminNotice::displayError(fpframework()->_('FPF_CANNOT_VERIFY_REQUEST'));
68 return;
69 }
70
71 if (!isset($_FILES['file']))
72 {
73 return;
74 }
75
76 $file = $_FILES['file'];
77
78 // ensure a file was given
79 if (!is_array($file) || !isset($file['name']) || empty($file['name']))
80 {
81 \FPFramework\Libs\AdminNotice::displayError(fpframework()->_('FPF_PLEASE_SELECT_A_FILE_TO_UPLOAD'));
82 return;
83 }
84
85 $ext = explode('.', $file['name']);
86
87 // ensure given file plugin was given
88 if (!in_array($ext[count($ext) - 1], ['fbox']))
89 {
90 \FPFramework\Libs\AdminNotice::displayError(fpframework()->_('FPF_PLEASE_CHOOSE_A_VALID_FILE'));
91 return;
92 }
93
94 $publish_all = isset($input['publish_all']) ? $input['publish_all'] : 0;
95
96 // read file contents
97 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
98 $data = file_get_contents($file['tmp_name']);
99
100 // if empty data file then abort
101 if (empty($data))
102 {
103 \FPFramework\Libs\AdminNotice::displayError(fpframework()->_('FPF_FILE_EMPTY'));
104 return;
105 }
106
107 $items = json_decode($data, true);
108
109 // Scalar JSON (e.g. "123") is valid JSON but not an export payload
110 if (!$items || !is_array($items))
111 {
112 \FPFramework\Libs\AdminNotice::displayError(firebox()->_('FB_CAMPAIGN_IMPORT_CONTENTS_ERROR'));
113 return;
114 }
115
116 if (is_null($items))
117 {
118 $items = [];
119 }
120
121 if (!$items)
122 {
123 return;
124 }
125
126 // import all boxes
127 if (!$new_box_id = $this->importBoxes($items, $publish_all))
128 {
129 \FPFramework\Libs\AdminNotice::displayError(firebox()->_('FB_CAMPAIGN_IMPORT_CONTENTS_ERROR'));
130 return;
131 }
132
133 \FPFramework\Libs\AdminNotice::displaySuccess(fpframework()->_('FPF_ITEMS_SAVED'));
134 return $new_box_id;
135 }
136
137 /**
138 * Imports boxes data
139 *
140 * @param array $items
141 * @param int $publish_all
142 *
143 * @return boolean
144 */
145 protected function importBoxes($items, $publish_all = 0)
146 {
147 $success = true;
148
149 foreach ($items as $item)
150 {
151 // The .fbox contents are user-supplied; validate the shape before
152 // using it or a hand-edited file fatals instead of erroring.
153 if (!is_array($item) || !isset($item['meta']))
154 {
155 $success = false;
156 break;
157 }
158
159 // get meta
160 $meta = $item['meta'];
161
162 // remote meta from item
163 unset($item['meta']);
164
165 // Campaign settings are free-form, but they are always a map — never a scalar.
166 if (!is_array($meta) && !is_object($meta))
167 {
168 $success = false;
169 break;
170 }
171
172 if (!isset($item['box']) || !is_array($item['box']))
173 {
174 $success = false;
175 break;
176 }
177
178 $box = $item['box'];
179
180 /**
181 * The .fbox file carries a full wp_posts row, and every key in it used to be
182 * written straight to the database. Keep only the columns that actually
183 * describe a campaign; everything else (post_type, post_author, guid,
184 * post_parent, ...) is either forced below or dropped.
185 */
186 $box = array_intersect_key($box, array_flip([
187 'post_title',
188 'post_content',
189 'post_excerpt',
190 'post_name',
191 'menu_order'
192 ]));
193
194 if (!isset($box['post_content']) || !is_string($box['post_content']))
195 {
196 $box['post_content'] = '';
197 }
198
199 $box['post_title'] = isset($box['post_title']) && is_string($box['post_title'])
200 ? sanitize_text_field($box['post_title'])
201 : '';
202
203 $box['post_excerpt'] = isset($box['post_excerpt']) && is_string($box['post_excerpt'])
204 ? sanitize_textarea_field($box['post_excerpt'])
205 : '';
206
207 $box['post_name'] = isset($box['post_name']) && is_string($box['post_name'])
208 ? sanitize_title($box['post_name'])
209 : '';
210
211 $box['menu_order'] = isset($box['menu_order']) ? (int) $box['menu_order'] : 0;
212
213 $factory = new \FPFramework\Base\Factory();
214
215 $tz = wp_timezone();
216 $date_without_tz = $factory->getDate();
217 $date_with_tz = $factory->getDate()->setTimezone($tz);
218
219 $box['post_date'] = $date_with_tz->format('Y-m-d H:i:s');
220 $box['post_date_gmt'] = $date_without_tz->format('Y-m-d H:i:s');
221
222 // These are ours to decide, never the file's.
223 $box['post_type'] = 'firebox';
224 $box['post_author'] = get_current_user_id();
225
226 \FireBox\Core\Helpers\Form\Form::ensureUniqueFormIDs($box['post_content']);
227
228 // set publish status
229 if (in_array($publish_all, [0, 1]))
230 {
231 $box['post_status'] = ($publish_all == 0) ? 'draft' : 'publish';
232 }
233 else
234 {
235 $box['post_status'] = 'draft';
236 }
237
238 /**
239 * Insert through wp_insert_post() rather than the raw table layer so that
240 * kses, slug uniqueness and the usual save_post hooks all apply.
241 */
242 $new_box_id = wp_insert_post(wp_slash($box), true);
243
244 if (is_wp_error($new_box_id) || !$new_box_id)
245 {
246 $success = false;
247 break;
248 }
249
250 // add meta options for new box
251 // TODO: In the future, use "firebox_meta". This is a temporary fix for backwards compatibility.
252 $checkMeta = (array) $meta;
253 $meta_key = isset($checkMeta['width']) ? 'firebox_meta' : 'fpframework_meta_settings';
254 update_post_meta($new_box_id, $meta_key, wp_slash($meta));
255 $success = $new_box_id;
256 }
257
258 return $success;
259 }
260
261 /**
262 * What the settings page will contain
263 *
264 * @return void
265 */
266 public function settingsPageContent()
267 {
268 $form = new Form(\FireBox\Core\Admin\Forms\Import::getSettings(), [
269 'fields_name_prefix' => self::settings_name,
270 'section_name' => self::settings_name,
271 'class' => 'settings-ui-inner-fields',
272 'button_label' => 'FPF_IMPORT'
273 ]);
274
275 echo $form->render(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
276 }
277 }