PluginProbe
Page Builder: Pagelayer – Drag and Drop website builder / 2.2.2
Page Builder: Pagelayer – Drag and Drop website builder v2.2.2
2.2.2 2.2.1 2.2.0 2.1.9 2.1.8 2.1.7 2.1.6 2.1.5 2.1.4 2.1.3 trunk 0.9.0 0.9.1 0.9.2 0.9.3 0.9.4 0.9.5 0.9.6 0.9.7 0.9.8 0.9.9 1.0.0 1.0.2 1.0.3 1.0.4 All 130 releases
← All changes | main/ajax.php +1992 -365 1.0.0 → 2.2.2 View file →
@@ -23,13 +23,446 @@
23 23 if(!defined('PAGELAYER_VERSION')) {
24 24 exit('Hacking Attempt !');
25 25 }
26 26
27 +// Recommended Plugins Installation and Activation Action Handlers
28 +// NOTE: These must be registered BEFORE the pagelayer_nonce gate below,
29 +// because install/activate requests do NOT send pagelayer_nonce.
30 +add_action('wp_ajax_pagelayer_install_plugin', 'pagelayer_install_recommended_plugin');
31 +function pagelayer_install_recommended_plugin(){
32 + check_ajax_referer('pagelayer_recommended_plugins', 'security');
33 +
34 + if(!current_user_can('install_plugins')){
35 + wp_send_json_error(array('message' => __('You do not have permission to install plugins.', 'pagelayer')));
36 + }
37 +
38 + $slug = !empty($_REQUEST['plugin']) ? sanitize_text_field(wp_unslash($_REQUEST['plugin'])) : '';
39 + if(empty($slug)){
40 + wp_send_json_error(array('message' => __('Plugin slug is required.', 'pagelayer')));
41 + }
42 +
43 + require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
44 + require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
45 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
46 + require_once ABSPATH . 'wp-admin/includes/file.php';
47 +
48 + // Initialize WP_Filesystem - required before Plugin_Upgrader can write files
49 + $creds = request_filesystem_credentials(site_url() . '/wp-admin/', '', false, false, null);
50 + if(!WP_Filesystem($creds)){
51 + wp_send_json_error(array('message' => __('Could not initialize filesystem. Please check file permissions.', 'pagelayer')));
52 + }
53 +
54 + $api = plugins_api('plugin_information', array('slug' => $slug, 'fields' => array('sections' => false)));
55 +
56 + if(is_wp_error($api)){
57 + wp_send_json_error(array('message' => $api->get_error_message()));
58 + }
59 +
60 + // Use Automatic_Upgrader_Skin (silent); buffer any stray output to keep response clean JSON
61 + $skin = new \Automatic_Upgrader_Skin();
62 + $upgrader = new \Plugin_Upgrader($skin);
63 +
64 + ob_start();
65 + $result = $upgrader->install($api->download_link);
66 + ob_end_clean();
67 +
68 + if(is_wp_error($result)){
69 + wp_send_json_error(array('message' => $result->get_error_message()));
70 + }
71 + if($result === false || $result === null){
72 + $error_msgs = $skin->get_upgrade_messages();
73 + $msg = !empty($error_msgs) ? implode(' ', $error_msgs) : __('Plugin installation failed. Please check file permissions.', 'pagelayer');
74 + wp_send_json_error(array('message' => $msg));
75 + }
76 +
77 + $all_plugins = get_plugins();
78 + $installed_plugin = '';
79 + foreach($all_plugins as $path => $data){
80 + if(strpos($path, $slug . '/') === 0){
81 + $installed_plugin = $path;
82 + break;
83 + }
84 + }
85 +
86 + if(empty($installed_plugin)){
87 + wp_send_json_error(array('message' => __('Plugin installed but could not be located for activation.', 'pagelayer')));
88 + }
89 +
90 + $result = activate_plugin($installed_plugin);
91 + if(is_wp_error($result)){
92 + wp_send_json_error(array('message' => $result->get_error_message()));
93 + }
94 +
95 + wp_send_json_success(array('message' => __('Plugin installed and activated successfully.', 'pagelayer')));
96 +}
97 +
98 +add_action('wp_ajax_pagelayer_activate_plugin', 'pagelayer_activate_recommended_plugin');
99 +function pagelayer_activate_recommended_plugin(){
100 + check_ajax_referer('pagelayer_recommended_plugins', 'security');
101 +
102 + if(!current_user_can('activate_plugins')){
103 + wp_send_json_error(array('message' => __('You do not have permission to activate plugins.', 'pagelayer')));
104 + }
105 +
106 + $slug = !empty($_REQUEST['plugin']) ? sanitize_text_field(wp_unslash($_REQUEST['plugin'])) : '';
107 + if(empty($slug)){
108 + wp_send_json_error(array('message' => __('Plugin slug is required.', 'pagelayer')));
109 + }
110 +
111 + if(!function_exists('get_plugins')){
112 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
113 + }
114 +
115 + $all_plugins = get_plugins();
116 + $plugin_path = '';
117 + foreach($all_plugins as $path => $data){
118 + if(strpos($path, $slug . '/') === 0){
119 + $plugin_path = $path;
120 + break;
121 + }
122 + }
123 +
124 + if(empty($plugin_path)){
125 + wp_send_json_error(array('message' => __('Plugin not found.', 'pagelayer')));
126 + }
127 +
128 + $result = activate_plugin($plugin_path);
129 + if(is_wp_error($result)){
130 + wp_send_json_error(array('message' => $result->get_error_message()));
131 + }
132 +
133 + wp_send_json_success(array('message' => __('Plugin activated successfully.', 'pagelayer')));
134 +}
135 +
136 +// AI Agents Connection AJAX handlers
137 +// NOTE: These must be registered BEFORE the pagelayer_nonce gate below,
138 +// because they use their own nonce (pagelayer_mcp_nonce) or basic auth.
139 +add_action('wp_ajax_pagelayer_mcp_generate_app_password', 'pagelayer_mcp_generate_app_password');
140 +add_action('wp_ajax_pagelayer_mcp_adapter_action', 'pagelayer_mcp_adapter_action');
141 +add_action('wp_ajax_pagelayer_mcp_test_connection', 'pagelayer_mcp_test_connection');
142 +add_action('wp_ajax_pagelayer_mcp_save_test_status', 'pagelayer_mcp_save_test_status');
143 +add_action('wp_ajax_pagelayer_mcp_save_image_api_key', 'pagelayer_mcp_save_image_api_key');
144 +
145 +// Verifies, without any HTTP round trip, the two things a loopback request would
146 +// have proved: that the supplied Application Password authenticates this user,
147 +// and that the Pagelayer abilities are registered. Used when the loopback itself
148 +// fails (cURL timeout etc.) so the panel can still tell the user where they stand.
149 +function pagelayer_mcp_verify_locally($username, $password) {
150 + $result = array('password_ok' => false, 'abilities' => 0, 'message' => '');
151 +
152 + if(!class_exists('WP_Application_Passwords')){
153 + $result['message'] = __('Application Passwords are not supported on this WordPress version.', 'pagelayer');
154 + return $result;
155 + }
156 +
157 + $user = get_user_by('login', $username);
158 + if(!$user && is_email($username)){
159 + $user = get_user_by('email', $username);
160 + }
161 +
162 + if(!$user){
163 + $result['message'] = sprintf(__('No user named "%s" exists on this site.', 'pagelayer'), $username);
164 + return $result;
165 + }
166 +
167 + // Core strips non-alphanumerics before comparing, so the password works with
168 + // or without the readability spaces (see wp_authenticate_application_password).
169 + $stripped = preg_replace('/[^a-z\d]/i', '', $password);
170 +
171 + foreach(\WP_Application_Passwords::get_user_application_passwords($user->ID) as $item){
172 + if(\WP_Application_Passwords::check_password($stripped, $item['password'])){
173 + $result['password_ok'] = true;
174 + break;
175 + }
176 + }
177 +
178 + if(function_exists('wp_get_abilities')){
179 + foreach(wp_get_abilities() as $name => $ability){
180 + $name = is_string($name) ? $name : '';
181 + if(strpos($name, 'pagelayer-') === 0){
182 + $result['abilities']++;
183 + }
184 + }
185 + }
186 +
187 + if($result['password_ok']){
188 + $result['message'] = sprintf(
189 + __('Checked locally instead: your Application Password IS valid for "%1$s", and %2$d Pagelayer abilities are registered.', 'pagelayer'),
190 + $username,
191 + $result['abilities']
192 + );
193 + }else{
194 + $result['message'] = sprintf(
195 + __('Checked locally instead: the supplied Application Password does NOT match any password stored for "%s" — generate a new one below.', 'pagelayer'),
196 + $username
197 + );
198 + }
199 +
200 + return $result;
201 +}
202 +
203 +function pagelayer_mcp_test_connection() {
204 + include_once(PAGELAYER_DIR.'/main/abilities.php');
205 + check_ajax_referer('pagelayer_mcp_nonce', 'nonce');
206 +
207 + if(!current_user_can('manage_options')){
208 + wp_send_json_error(__('You do not have permission to test the connection.', 'pagelayer'));
209 + }
210 +
211 + $start = microtime(true);
212 + $url = trailingslashit(home_url()) . ltrim(Pagelayer_Abilities::$ABILITIES_ENDPOINT, '/');
213 +
214 + $username = isset($_POST['username']) ? sanitize_text_field(wp_unslash($_POST['username'])) : '';
215 + $password = isset($_POST['password']) ? sanitize_text_field(wp_unslash($_POST['password'])) : '';
216 +
217 + // Application Passwords are silently inert unless the site is on HTTPS or the
218 + // environment type is "local" (wp_is_application_passwords_supported()). WP
219 + // still hands out a password string in that state, so the only symptom is a
220 + // 401 on every request — check it up front instead of blaming the password.
221 + if(function_exists('wp_is_application_passwords_available') && !wp_is_application_passwords_available()){
222 + $message = sprintf(
223 + __('Application Passwords are disabled on this site, so every request is treated as anonymous (HTTP 401). WordPress only enables them over HTTPS or when the environment type is "local". This site reports %1$s and environment type "%2$s". Either serve the site over HTTPS, or add define(\'WP_ENVIRONMENT_TYPE\', \'local\'); to wp-config.php for a development site.', 'pagelayer'),
224 + is_ssl() ? 'HTTPS' : 'HTTP',
225 + function_exists('wp_get_environment_type') ? wp_get_environment_type() : 'unknown'
226 + );
227 + Pagelayer_Abilities::save_test_connection_status(false, $message);
228 + wp_send_json_error(['message' => $message]);
229 + }
230 +
231 + $response = wp_remote_get($url, [
232 + // wp_remote_get() defaults to a 5s timeout, which a local dev stack will
233 + // blow through on a loopback request (TLS handshake plus a full second
234 + // WordPress bootstrap, often with WP_DEBUG on).
235 + 'timeout' => 20,
236 + 'headers' => [
237 + 'Accept' => 'application/json',
238 + 'Authorization' => 'Basic ' . base64_encode($username . ':' . $password),
239 + ],
240 + 'sslverify' => false,
241 + ]);
242 +
243 + $elapsed = round((microtime(true) - $start) * 1000);
244 +
245 + if(is_wp_error($response)){
246 + // The loopback never completed, so it told us nothing about the HTTP path.
247 + // Verify in-process what we actually can — that the Application Password
248 + // is valid and the abilities are registered — and say plainly which part
249 + // is still unverified, instead of reporting a flat failure.
250 + $local = pagelayer_mcp_verify_locally($username, $password);
251 +
252 + $message = sprintf(
253 + __('Could not complete the loopback request to %1$s (%2$s). %3$s %4$s', 'pagelayer'),
254 + $url,
255 + $response->get_error_message(),
256 + $local['message'],
257 + __('A loopback failure is usually the local server itself, not your setup: many dev stacks run too few PHP workers to serve a second request while this one is still open, so the site cannot call itself. Your AI client connects from outside and is not affected. Confirm from a terminal with: curl -ik -u "USERNAME:APP PASSWORD" ', 'pagelayer') . $url
258 + );
259 +
260 + Pagelayer_Abilities::save_test_connection_status(false, $message);
261 + wp_send_json_error([
262 + 'message' => $message,
263 + 'local_check' => $local,
264 + 'loopback_failed' => true,
265 + ]);
266 + }
267 +
268 + $code = wp_remote_retrieve_response_code($response);
269 + $body = json_decode(wp_remote_retrieve_body($response), true);
270 +
271 + if($code >= 200 && $code < 300 && is_array($body)){
272 + $pagelayer_abilities = 0;
273 + foreach($body as $ability){
274 + $name = isset($ability['name']) ? $ability['name'] : (isset($ability['id']) ? $ability['id'] : '');
275 + if(is_string($name) && strpos($name, 'pagelayer-') === 0){
276 + $pagelayer_abilities++;
277 + }
278 + }
279 +
280 + $message = sprintf(__('Authenticated with your Application Password and discovered %1$d Pagelayer abilities in %2$dms. Your site is ready to connect.', 'pagelayer'), $pagelayer_abilities, $elapsed);
281 +
282 + Pagelayer_Abilities::save_test_connection_status(true, $message);
283 +
284 + wp_send_json_success([
285 + 'message' => $message,
286 + 'abilities' => $pagelayer_abilities,
287 + 'elapsed_ms' => $elapsed,
288 + ]);
289 + }
290 +
291 + // A 401 means the request arrived with no authenticated user at all; a 403
292 + // means it authenticated but lacked the capability. Those need different fixes.
293 + if($code === 401){
294 + $auth_header_seen = (bool) (function_exists('wp_get_authorization_header') ? wp_get_authorization_header() : (!empty($_SERVER['HTTP_AUTHORIZATION']) || !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])));
295 +
296 + $message = __('The abilities endpoint treated the request as anonymous (HTTP 401), so the Application Password never authenticated. The two usual causes are: (1) the password was revoked or mistyped — generate a new one below; or (2) your web server is stripping the Authorization header before PHP sees it. For Apache, ensure the "RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]" line is present in .htaccess and that AllowOverride permits it. For nginx/FastCGI, ensure the Authorization header is forwarded to PHP-FPM.', 'pagelayer');
297 +
298 + if(!$auth_header_seen){
299 + $message .= ' ' . __('Note: this admin request itself arrived without an Authorization header, which is normal here but means the stripping check is inconclusive — test with curl -u user:app-password against the endpoint to confirm.', 'pagelayer');
300 + }
301 +
302 + Pagelayer_Abilities::save_test_connection_status(false, $message);
303 + wp_send_json_error([
304 + 'message' => $message,
305 + ]);
306 + }
307 +
308 + if($code === 403){
309 + $message = __('The Application Password authenticated, but the account was refused (HTTP 403). Check that this user still has the required capabilities, and that no security plugin is blocking REST API requests.', 'pagelayer');
310 + Pagelayer_Abilities::save_test_connection_status(false, $message);
311 + wp_send_json_error([
312 + 'message' => $message,
313 + ]);
314 + }
315 +
316 + $message = sprintf(__('The abilities endpoint responded with status %1$d. Check the MCP Adapter is active and try again.', 'pagelayer'), $code);
317 + Pagelayer_Abilities::save_test_connection_status(false, $message);
318 + wp_send_json_error([
319 + 'message' => $message,
320 + ]);
321 +}
322 +
323 +function pagelayer_mcp_save_test_status() {
324 + include_once(PAGELAYER_DIR.'/main/abilities.php');
325 + check_ajax_referer('pagelayer_mcp_nonce', 'nonce');
326 +
327 + if(!current_user_can('manage_options')){
328 + wp_send_json_error(__('You do not have permission to do that.', 'pagelayer'));
329 + }
330 +
331 + $ok = !empty($_POST['ok']);
332 + $message = !empty($_POST['message']) ? sanitize_text_field(wp_unslash($_POST['message'])) : '';
333 +
334 + Pagelayer_Abilities::save_test_connection_status($ok, $message);
335 +
336 + wp_send_json_success();
337 +}
338 +
339 +function pagelayer_mcp_save_image_api_key() {
340 + check_ajax_referer('pagelayer_mcp_nonce', 'nonce');
341 +
342 + if(!current_user_can('manage_options')){
343 + wp_send_json_error(array('message' => __('You do not have permission to do that.', 'pagelayer')));
344 + }
345 +
346 + $provider = !empty($_POST['provider']) ? sanitize_key(wp_unslash($_POST['provider'])) : '';
347 + $api_key = !empty($_POST['api_key']) ? sanitize_text_field(wp_unslash($_POST['api_key'])) : '';
348 +
349 + if(empty($api_key)){
350 + wp_send_json_error(array('message' => __('An API key is required.', 'pagelayer')));
351 + }
352 +
353 + if($provider !== 'pexels'){
354 + wp_send_json_error(array('message' => __('Unsupported image provider.', 'pagelayer')));
355 + }
356 +
357 + update_option('pagelayer_pexels_api_key', $api_key, false);
358 +
359 + wp_send_json_success(array('message' => __('Image search API key saved.', 'pagelayer')));
360 +}
361 +
362 +function pagelayer_mcp_generate_app_password() {
363 + include_once(PAGELAYER_DIR.'/main/abilities.php');
364 + check_ajax_referer('pagelayer_mcp_nonce', 'nonce');
365 +
366 + if(!current_user_can('manage_options')){
367 + wp_send_json_error('Unauthorized');
368 + }
369 +
370 + $user_id = get_current_user_id();
371 + if(!class_exists('WP_Application_Passwords')){
372 + wp_send_json_error('Application Passwords not supported in this WP version.');
373 + }
374 +
375 + // WP_Application_Passwords::create_new_application_password() does NOT check
376 + // availability, so without this the UI happily issues a password that
377 + // wp_authenticate_application_password() will always reject — a "Generated"
378 + // checkmark followed by a permanent 401.
379 + if(function_exists('wp_is_application_passwords_available') && !wp_is_application_passwords_available()){
380 + wp_send_json_error(sprintf(
381 + __('Application Passwords are disabled on this site, so a generated password could never authenticate. WordPress enables them only over HTTPS or when the environment type is "local". This site reports %1$s and environment type "%2$s". Serve the site over HTTPS, or add define(\'WP_ENVIRONMENT_TYPE\', \'local\'); to wp-config.php for a development site.', 'pagelayer'),
382 + is_ssl() ? 'HTTPS' : 'HTTP',
383 + function_exists('wp_get_environment_type') ? wp_get_environment_type() : 'unknown'
384 + ));
385 + }
386 +
387 + $passwords = \WP_Application_Passwords::get_user_application_passwords($user_id);
388 + foreach($passwords as $app){
389 + if(!empty($app['app_id']) && $app['app_id'] === Pagelayer_Abilities::$APP_PASSWORD_APP_ID){
390 + \WP_Application_Passwords::delete_application_password($user_id, $app['uuid']);
391 + }
392 + }
393 +
394 + $new_password = \WP_Application_Passwords::create_new_application_password($user_id, array(
395 + 'name' => Pagelayer_Abilities::$APP_PASSWORD_NAME,
396 + 'app_id' => Pagelayer_Abilities::$APP_PASSWORD_APP_ID,
397 + ));
398 +
399 + if(is_wp_error($new_password)){
400 + wp_send_json_error($new_password->get_error_message());
401 + }
402 +
403 + wp_send_json_success(array('password' => $new_password[0]));
404 +}
405 +
406 +function pagelayer_mcp_adapter_action() {
407 + include_once(PAGELAYER_DIR.'/main/abilities.php');
408 + check_ajax_referer('pagelayer_mcp_nonce', 'nonce');
409 +
410 + if(!current_user_can('manage_options')){
411 + wp_send_json_error('Unauthorized');
412 + }
413 +
414 + $type = isset($_POST['type']) ? sanitize_text_field($_POST['type']) : '';
415 +
416 + if(!function_exists('get_plugins')){
417 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
418 + }
419 +
420 + if ($type === 'install') {
421 + include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
422 + include_once ABSPATH . 'wp-admin/includes/file.php';
423 +
424 + // The MCP Adapter is hosted on GitHub, not WordPress.org, so fetch the download URL from the GitHub API
425 + $download_url = Pagelayer_Abilities::get_mcp_adapter_download_url();
426 +
427 + $upgrader = new \Plugin_Upgrader(new \Automatic_Upgrader_Skin());
428 + $installed = $upgrader->install($download_url);
429 +
430 + if(is_wp_error($installed)){
431 + wp_send_json_error($installed->get_error_message());
432 + }elseif(!$installed){
433 + wp_send_json_error('Installation failed. The MCP Adapter plugin is downloaded from GitHub. Please check your server can reach github.com.');
434 + }
435 +
436 + $plugin_file = Pagelayer_Abilities::get_installed_mcp_adapter_file();
437 + if($plugin_file){
438 + activate_plugin($plugin_file);
439 + wp_send_json_success('Installed and activated');
440 + }
441 + wp_send_json_success('Installed but not activated');
442 +
443 + } elseif ($type === 'activate') {
444 + $plugin_file = Pagelayer_Abilities::get_installed_mcp_adapter_file();
445 + if($plugin_file){
446 + $result = activate_plugin($plugin_file);
447 + if(is_wp_error($result)){
448 + wp_send_json_error($result->get_error_message());
449 + }
450 + wp_send_json_success('Activated');
451 + }
452 + wp_send_json_error('Plugin not found');
453 + }
454 +
455 + wp_send_json_error('Invalid action');
456 +}
457 +
27 458 // Is the nonce there ?
28 459 if(empty($_REQUEST['pagelayer_nonce'])){
29 460 return;
30 461 }
31 462
463 +pagelayer_memory_limit(128);
464 +
32 465 // The ajax handler
33 466 add_action('wp_ajax_pagelayer_wp_widget', 'pagelayer_wp_widget_ajax');
34 467 function pagelayer_wp_widget_ajax(){
35 468
@@ -37,8 +470,13 @@
37 470
38 471 // Some AJAX security
39 472 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
40 473
474 + if(!current_user_can('edit_theme_options')){
475 + $ret['error'][] = __pl('no_permission');
476 + pagelayer_json_output($ret);
477 + }
478 +
41 479 pagelayer_load_shortcodes();
42 480
43 481 header('Content-Type: application/json');
44 482
@@ -52,9 +490,11 @@
52 490 pagelayer_json_output($ret);
53 491 }
54 492
55 493 // Include the widgets
56 - include_once(ABSPATH . 'wp-admin/includes/widgets.php');
494 + $widgets = ABSPATH . 'site-admin/includes/widgets.php';
495 + $widgets = file_exists($widgets) ? $widgets : ABSPATH . 'wp-admin/includes/widgets.php';
496 + require_once($widgets);
57 497
58 498 $class = $pagelayer->shortcodes[$tag]['widget'];
59 499
60 500 // Check the widget class exists ?
@@ -82,8 +522,15 @@
82 522 //pagelayer_print($data);die();
83 523
84 524 // Any data ?
85 525 if(!empty($data)){
526 +
527 + // Rss widget checkboxes fix
528 + if(!empty($data['widget-rss'])){
529 + $data['widget-rss']['pagelayer-widget-1234567890']['show_summary'] = empty($data['widget-rss']['pagelayer-widget-1234567890']['show_summary'])? 0 : 1;
530 + $data['widget-rss']['pagelayer-widget-1234567890']['show_author'] = empty($data['widget-rss']['pagelayer-widget-1234567890']['show_author'])? 0 : 1;
531 + $data['widget-rss']['pagelayer-widget-1234567890']['show_date'] = empty($data['widget-rss']['pagelayer-widget-1234567890']['show_date'])? 0 : 1;
532 + }
86 533
87 534 // First key is useless
88 535 $data = current($data);
89 536
@@ -96,8 +543,14 @@
96 543 }
97 544 }
98 545 }
99 546
547 + // Settings instance For Text widget
548 + if($widget->id_base == 'text'){
549 + $instance['visual'] = false;
550 + $instance['legacy'] = false;
551 + }
552 +
100 553 // Get the form
101 554 ob_start();
102 555 $widget->form($instance);
103 556 $ret['form'] = ob_get_contents();
@@ -113,12 +566,107 @@
113 566 if(!empty($instance)){
114 567 $ret['widget_data'] = $instance;
115 568 }
116 569
570 + // Custom html widget form elements
571 + if(!empty($widget) && $widget->name=='Custom HTML'){
572 + $custom_html = explode('>', $ret['form']);
573 +
574 + $custom_html[0] = '<label for="widget-custom_html-pagelayer-widget-1234567890-title">Title:</label>'.$custom_html[0];
575 + $custom_html[0] = str_replace('type="hidden"', 'type="text"',$custom_html[0]);
576 +
577 + $custom_html[1] = '<label for="widget-custom_html-pagelayer-widget-1234567890-content">Content:</label>'.$custom_html[1];
578 + $custom_html[1] = str_replace('hidden', '', $custom_html[1]);
579 +
580 + $ret['form'] = implode('>', $custom_html);
581 + }
582 +
117 583 pagelayer_json_output($ret);
118 584
119 585 }
120 586
587 +// Build with AI — wrappers; generation/settings logic lives in Pagelayer_AI_Controller
588 +add_action('wp_ajax_pagelayer_ai_generate', 'pagelayer_ai_generate');
589 +function pagelayer_ai_generate(){
590 +
591 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
592 +
593 + $done = [];
594 +
595 + if(!current_user_can('edit_posts')){
596 + $done['error'][] = __pl('no_permission');
597 + pagelayer_json_output($done);
598 + }
599 +
600 + $ctrl = Pagelayer_AI_Controller::get_instance();
601 + $res = $ctrl->process_generate();
602 +
603 + if(is_wp_error($res)){
604 + $done['error'] = $res->get_error_message();
605 + pagelayer_json_output($done);
606 + }
607 +
608 + $done = is_array($res) ? $res : [];
609 + if(!isset($done['success'])){
610 + $done['success'] = true;
611 + }
612 + pagelayer_json_output($done);
613 +}
614 +
615 +add_action('wp_ajax_pagelayer_ai_settings', 'pagelayer_ai_settings');
616 +function pagelayer_ai_settings(){
617 +
618 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
619 +
620 + $done = [];
621 +
622 + if(!current_user_can('edit_posts')){
623 + $done['error'][] = __pl('no_permission');
624 + pagelayer_json_output($done);
625 + }
626 +
627 + $ctrl = Pagelayer_AI_Controller::get_instance();
628 + $res = $ctrl->process_get_settings();
629 +
630 + if(is_wp_error($res)){
631 + $done['error'] = $res->get_error_message();
632 + pagelayer_json_output($done);
633 + }
634 +
635 + $done = is_array($res) ? $res : [];
636 + if(!isset($done['success'])){
637 + $done['success'] = true;
638 + }
639 + pagelayer_json_output($done);
640 +}
641 +
642 +add_action('wp_ajax_pagelayer_ai_save_settings', 'pagelayer_ai_save_settings');
643 +function pagelayer_ai_save_settings(){
644 +
645 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
646 +
647 + $done = [];
648 +
649 + if(!current_user_can('edit_posts')){
650 + $done['error'][] = __pl('no_permission');
651 + pagelayer_json_output($done);
652 + }
653 +
654 + $ctrl = Pagelayer_AI_Controller::get_instance();
655 + $res = $ctrl->process_save_settings();
656 +
657 + if(is_wp_error($res)){
658 + $done['error'] = $res->get_error_message();
659 + pagelayer_json_output($done);
660 + }
661 +
662 + $done = is_array($res) ? $res : [];
663 + if(!isset($done['success'])){
664 + $done['success'] = true;
665 + }
666 + pagelayer_json_output($done);
667 +}
668 +
121 669 // Update Post content
122 670 add_action('wp_ajax_pagelayer_save_content', 'pagelayer_save_content');
123 671 function pagelayer_save_content(){
124 672
@@ -127,39 +675,387 @@
127 675
128 676 $content = $_POST['pagelayer_update_content'];
129 677
130 678 $postID = (int) $_GET['postID'];
131 -
679 +
132 680 if(empty($postID)){
133 - $msg['error'] = __pl('invalid_post_id');
681 + $msg['error'] = __pl('invalid_post_id');
682 + pagelayer_json_output($msg);
134 683 }
135 684
136 - // Check if the post exists
685 + $_post = get_post($postID);
137 686
138 - if(!empty($postID) && !empty($content)){
687 + // Post found ?
688 + if(empty($_post)){
689 + $msg['error'] = __pl('invalid_post_id');
690 + pagelayer_json_output($msg);
691 + }
692 +
693 + // Get the post type and its capabilities
694 + $post_type = $_post->post_type;
695 + $post_type_obj = get_post_type_object($post_type);
696 +
697 + // Are you allowed to edit ?
698 + if(!pagelayer_user_can_edit($postID)){
699 + $msg['error'][] = __pl('no_permission');
700 + pagelayer_json_output($msg);
701 + }
702 +
703 + // Check if the post exists
704 + if(!empty($postID)){
139 705
706 + $content = base64_decode($content);
707 +
708 + /*if(!pagelayer_is_utf8($content)){
709 + $content = utf8_encode($content);
710 + }*/
711 +
712 + $is_xss = pagelayer_xss_content($content);
713 +
714 + if(!pagelayer_user_can_add_js_content() && strlen($is_xss) > 0){
715 + $msg['error'][] = __pl('xss_found').' - '.$is_xss;
716 + pagelayer_json_output($msg);
717 + }
718 +
719 + // Is comment mode?
720 + if(pagelayer_is_comment_mode()){
721 + global $pagelayer_comment_errors, $pagelayer_comment_alerts;
722 + $content = pagelayer_extract_comment_atts($postID, $content);
723 + }
724 +
725 + // Add slash to save data in post
726 + $content = wp_slash($content);
727 +
140 728 $post = array(
141 - 'ID' => $postID,
142 - 'post_content' => $content,
143 - );
729 + 'ID' => $postID,
730 + 'post_content' => $content,
731 + );
732 +
733 + // Any properties ?
734 + $allowed = ['post_title', 'post_name', 'post_excerpt', 'post_status', 'post_password', 'post_date', 'post_parent', 'menu_order'];
144 735
736 + foreach($allowed as $k){
737 + if(isset($_REQUEST[$k])){
738 + $post[$k] = sanitize_text_field($_REQUEST[$k]);
739 + }
740 + }
741 +
742 + // Restrict contributors from setting 'publish' or modifying unauthorized fields
743 + $current_user_can_publish = current_user_can($post_type_obj->cap->publish_posts);
744 + if(!$current_user_can_publish){
745 + if(!in_array($post['post_status'], ['draft', 'pending'])){
746 + $post['post_status'] = 'pending'; // Force pending status
747 + }
748 + }
749 +
750 + if(!empty($post['post_password'])){
751 + if($_REQUEST['post_sticky'] == true){
752 + $msg['error'] = __pl('post_pass_with_sticky_err');
753 + pagelayer_json_output($msg);
754 + }
755 +
756 + // Prevent unauthorized password protection
757 + $can_protect = current_user_can($post_type_obj->cap->edit_private_posts);
758 + if(!$can_protect){
759 + $msg['error'][] = __pl('no_permission_to_set_password');
760 + pagelayer_json_output($msg);
761 + }
762 + }
763 +
764 + // Prevent unauthorized modification of `post_author`
765 + if(isset($_REQUEST['post_author']) && $_REQUEST['post_author'] != $_post->post_author){
766 +
767 + $edit_others_posts = current_user_can($post_type_obj->cap->edit_others_posts);
768 +
769 + if($edit_others_posts){
770 + $post['post_author'] = (int) $_REQUEST['post_author'];
771 + }else{
772 + $msg['error'][] = __pl('no_permission_to_change_author');
773 + pagelayer_json_output($msg);
774 + }
775 + }
776 +
777 + $post['comment_status'] = !empty($_REQUEST['comment_status']) ? 'open' : 'closed';
778 + $post['ping_status'] = !empty($_REQUEST['ping_status']) ? 'open' : 'closed';
779 + $post['post_status'] = empty($post['post_status']) ? $_post->post_status : $post['post_status'];
780 +
781 + if(!empty($post['post_status']) && $post['post_status'] == 'publish'){
782 +
783 + // Allowed to publish pages ?
784 + if($_post->post_type == 'page' && !current_user_can('publish_pages')){
785 + $msg['error'][] = __pl('no_publish_permission');
786 + pagelayer_json_output($msg);
787 + }
788 +
789 + // Allowed to publish posts ?
790 + if($_post->post_type == 'post' && !current_user_can('publish_posts')){
791 + $post['post_status'] = 'pending';
792 + }
793 + }
794 +
795 + if(!empty($post['post_password'])){
796 + $post['post_password'] = (in_array($post['post_status'], array('pass_protected', 'publish')) ? $post['post_password'] : '');
797 + $post['post_status'] = 'publish';
798 + }else{
799 + $post['post_status'] = ($post['post_status'] == 'pass_protected') ? 'publish' : $post['post_status'];
800 + $post['post_password'] = '';
801 + }
802 +
803 + // Set post GMT time
804 + if(!empty($post['post_date']) && '0000-00-00 00:00:00' !== $post['post_date']){
805 + $post['post_date_gmt'] = get_gmt_from_date( $post['post_date'] );
806 +
807 + if( in_array($post['post_status'], array('future', 'publish')) && $_post->post_date_gmt === '0000-00-00 00:00:00' ){
808 + $post['edit_date'] = true;
809 + }
810 + }
811 +
812 + $_REQUEST['featured_image'] = (int) $_REQUEST['featured_image'];
813 + if(!empty($_REQUEST['featured_image'])){
814 + set_post_thumbnail($postID, $_REQUEST['featured_image']);
815 + }else{
816 + delete_post_thumbnail($postID);
817 + }
818 +
819 + if(!isset($_REQUEST['post_category'])){
820 + $_REQUEST['post_category'] = '';
821 + }
822 +
823 + if(!isset($_REQUEST['post_tags'])){
824 + $_REQUEST['post_tags'] = '';
825 + }
826 +
827 + if($_post->post_type == 'post'){
828 + $post['post_category'] = pagelayer_sanitize_text_field($_REQUEST['post_category']);
829 +
830 + $post['tags_input'] = pagelayer_sanitize_text_field($_REQUEST['post_tags']);
831 + }else{
832 + $cat_name = pagelayer_post_type_category($_post->post_type);
833 + if($cat_name){
834 + $post['tax_input'][$cat_name] = pagelayer_sanitize_text_field($_REQUEST['post_category']);
835 + }
836 +
837 + $tag_name = pagelayer_post_type_tag($_post->post_type);
838 + if($tag_name){
839 + $post['tax_input'][$tag_name] = pagelayer_sanitize_text_field($_REQUEST['post_tags']);
840 + }
841 + }
842 +
843 + if(isset($_REQUEST['post_sticky']) && !empty($_REQUEST['post_sticky'])){
844 + stick_post( $postID );
845 + }else{
846 + if(is_sticky($postID)){
847 + unstick_post( $postID );
848 + }
849 + }
850 +
851 + // Any contact templates ?
852 + if(!empty($_REQUEST['contacts']) && current_user_can('activate_plugins')){
853 + update_post_meta($postID, 'pagelayer_contact_templates', $_REQUEST['contacts']);
854 + }else{
855 + delete_post_meta($postID, 'pagelayer_contact_templates');
856 + }
857 +
858 + // Save copyright
859 + if(isset($_REQUEST['copyright']) && current_user_can('manage_options')){
860 + update_option('pagelayer-copyright', wp_unslash($_REQUEST['copyright']));
861 + }
862 +
863 + // Apply a filter
864 + $post = apply_filters('pagelayer_save_content', $post);
865 +
145 866 // Update the post into the database
146 - wp_update_post($post);
867 + $ret = wp_update_post($post, true);
868 +
869 + // Render the post
870 + //update_post_meta($postID, 'pagelayer_rendered_post', pagelayer_get_post_content($postID));
147 871
148 - if (is_wp_error($postID)) {
149 - $msg['error'] = __pl('post_update_err');
872 + if (is_wp_error($ret)) {
873 + $errors = $ret->get_error_messages();
874 + $msg['error'] = __pl('post_update_err').' : '.implode('', $errors);
150 875 }else{
151 - $msg['success'] = __pl('post_update_success');
876 +
877 + // Get the updated post
878 + $_post = get_post($postID);
879 +
880 + // Is this a Pagelayer post
881 + $data = get_post_meta($postID, 'pagelayer-data', true);
882 +
883 + if(empty($data)){
884 +
885 + // Convert to pagelayer accessed post
886 + if(!add_post_meta($postID, 'pagelayer-data', time(), true)){
887 + update_post_meta($postID, 'pagelayer-data', time());
888 + }
889 + }
890 +
891 + if(!empty($pagelayer_comment_alerts)){
892 + $msg['comment_alerts'] = $pagelayer_comment_alerts;
893 + }
894 +
895 + if(!empty($pagelayer_comment_errors)){
896 + $msg['error'][] = 'Comment Mode errrors found !';
897 + $msg['comment_errors'] = $pagelayer_comment_errors;
898 + }
899 +
900 + $msg['success'] = __pl('post_update_success');
152 901 }
153 902
154 903 }else{
155 - $msg['error'] = __pl('post_update_err');
904 + $msg['error'] = __pl('post_update_err');
156 905 }
906 +
907 + $msg['post_status'] = (empty($_post->post_password)) ? $_post->post_status : 'pass_protected';
908 +
909 + // Save global widgets data
910 + if(!empty($_REQUEST['global_widgets'])){
911 + pagelayer_save_templ_content(true);
912 + }
913 +
914 + // Save nav menu data
915 + if(!empty($_REQUEST['pagelayer_nav_items']) && current_user_can('edit_theme_options')){
916 + $menu_items = (array) $_REQUEST['pagelayer_nav_items'];
917 + foreach($menu_items as $items){
918 + pagelayer_save_nav_menu_items($items);
919 + }
920 + }
921 +
922 + // Save Customizer data
923 + if(!empty($_REQUEST['pagelayer_customizer_options']) && current_user_can('edit_theme_options')){
924 +
925 + $customizer_options = wp_unslash($_REQUEST['pagelayer_customizer_options']);
926 + $customizer_options = json_decode($customizer_options, true);
927 +
928 + // Add current post type
929 + $customizer_options['pagelayer_current_post_type'] = $_post->post_type;
930 +
931 + pagelayer_save_customizer_options($customizer_options);
932 + }
933 +
934 + pagelayer_json_output($msg);
935 +
936 +}
157 937
158 - pagelayer_json_output($msg);
938 +// Save sections and global sections
939 +add_action('wp_ajax_pagelayer_save_templ_content', 'pagelayer_save_templ_content');
940 +function pagelayer_save_templ_content($echo = false){
159 941
942 + // Some AJAX security
943 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
944 +
945 + if ( ! current_user_can( get_post_type_object( 'pagelayer-template' )->cap->create_posts ) ) {
946 + $ret['error'][$g_post_id] = __pl('no_permission');
947 + pagelayer_json_output($ret);
948 + return false;
949 + }
950 +
951 + // Are you allowed to edit ?
952 + if(!pagelayer_user_can_edit($_REQUEST['postID'])){
953 + $msg['error'][] = __pl('no_permission');
954 + pagelayer_json_output($msg);
955 + }
956 +
957 + $ret = array();
958 +
959 + // Save global widgets data
960 + if(empty($_REQUEST['global_widgets'])){
961 + $ret['error'][] = 'No widgets given';
962 + pagelayer_json_output($ret);
963 + return false;
964 + }
965 +
966 + $global_widgets = $_REQUEST['global_widgets'];
967 +
968 + foreach($global_widgets as $key => $value){
969 +
970 + $g_post_id = (int) $value['post_id'];
971 +
972 + // Are you allowed to edit ?
973 + if(!empty($g_post_id) && !pagelayer_user_can_edit($g_post_id)){
974 + $ret['error'][$g_post_id] = __pl('no_permission').' : '.$g_post_id;
975 + continue;
976 + }
977 +
978 + // Decode base64 data
979 + $value['content'] = base64_decode($value['content']);
980 +
981 + $is_xss = pagelayer_xss_content($value['content']);
982 +
983 + if(!current_user_can('manage_options') && strlen($is_xss) > 0){
984 + $ret['error'][$g_post_id] = __pl('xss_found').' - '.$is_xss;
985 + pagelayer_json_output($ret);
986 + }
987 +
988 + // Add slash to save data in post
989 + $value['content'] = wp_slash($value['content']);
990 +
991 + // We need to create the post
992 + if(empty($value['post_id'])){
993 +
994 + $g_ret = wp_insert_post([
995 + 'post_type' => 'pagelayer-template',
996 + 'post_title' => $value['title'],
997 + 'post_content' => $value['content'],
998 + 'post_status' => 'publish',
999 + 'comment_status' => 'closed',
1000 + 'ping_status' => 'closed'
1001 + ]);
1002 +
1003 + $g_post_id = $g_ret;
1004 +
1005 + // Save our template metas
1006 + update_post_meta($g_post_id, 'pagelayer_template_type', $value['type']);
1007 + update_post_meta($g_post_id, 'pagelayer-data', time());
1008 +
1009 + }else if(!empty($value['content'])){
1010 +
1011 + // Save global widget content
1012 + $post = array(
1013 + 'ID' => $g_post_id,
1014 + 'post_title' => $value['title'],
1015 + 'post_content' => $value['content'],
1016 + );
1017 +
1018 + wp_update_post($post);
1019 + }
1020 +
1021 + if(is_wp_error($g_post_id)){
1022 + $ret['error'][$g_post_id] = __pl('template_update_err');
1023 + }else{
1024 + $ret['success'][$g_post_id] = __pl('template_update_success');
1025 + }
1026 + }
1027 +
1028 + if(!$echo){
1029 + pagelayer_json_output($ret);
1030 + }else{
1031 + return $ret;
1032 + }
160 1033 }
161 1034
1035 +// Update the Site Title
1036 +add_action('wp_ajax_pagelayer_set_jscss_giver', 'pagelayer_set_jscss_giver');
1037 +function pagelayer_set_jscss_giver(){
1038 + global $wpdb;
1039 +
1040 + // Some AJAX security
1041 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
1042 +
1043 + if( !current_user_can('manage_options') ){
1044 + $ret['error'] = __pl('no_permission');
1045 + pagelayer_json_output($ret);
1046 + }
1047 +
1048 + $val = (int) @$_REQUEST['set'];
1049 +
1050 + if(in_array($val, [1, -1])){
1051 + update_option('pagelayer_enable_giver', $val);
1052 + }
1053 +
1054 + $ret['success'] = 1;
1055 + pagelayer_json_output($ret);
1056 +}
1057 +
162 1058 // Shortcodes Widget Handler
163 1059 add_action('wp_ajax_pagelayer_do_shortcodes', 'pagelayer_do_shortcodes');
164 1060 function pagelayer_do_shortcodes(){
165 1061
@@ -165,8 +1061,13 @@
165 1061
166 1062 // Some AJAX security
167 1063 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
168 1064
1065 + if(!current_user_can('edit_posts')){// TODO : WooCommerce
1066 + $ret['error'][] = __pl('no_permission');
1067 + pagelayer_json_output($ret);
1068 + }
1069 +
169 1070 $data = '';
170 1071 if(isset($_REQUEST['shortcode_data'])){
171 1072 $data = stripslashes($_REQUEST['shortcode_data']);
172 1073 }
@@ -173,12 +1074,12 @@
173 1074
174 1075 // Load shortcodes
175 1076 pagelayer_load_shortcodes();
176 1077
177 - $data = do_shortcode($data);
1078 + $data = pagelayer_the_content($data);
178 1079
179 1080 // Create the HTML object
180 - $node = pQuery::parseStr($data);
1081 + $node = pagelayerQuery::parseStr($data);
181 1082 $node->query('.pagelayer-ele')->removeClass('pagelayer-ele');
182 1083 echo $node->html();
183 1084
184 1085 wp_die();
@@ -184,8 +1085,210 @@
184 1085 wp_die();
185 1086
186 1087 }
187 1088
1089 +// Give the JS
1090 +add_action('wp_ajax_pagelayer_givejs', 'pagelayer_givejs');
1091 +function pagelayer_givejs(){
1092 +
1093 + global $pagelayer;
1094 +
1095 + // WordPress adds the Expires header in all AJAX calls. We need to remove it for cache to work
1096 + header_remove("Expires");
1097 + header_remove("Cache-Control");
1098 +
1099 + // Load shortcodes
1100 + pagelayer_load_shortcodes();
1101 +
1102 + // Load font options
1103 + pagelayer_load_font_options();
1104 +
1105 + // Pagelayer Template Loading Mechanism
1106 + include_once(PAGELAYER_DIR.'/js/givejs.php');
1107 +
1108 + exit();
1109 +
1110 +}
1111 +
1112 +add_action('wp_ajax_pagelayer_givecss', 'pagelayer_givecss');
1113 +add_action('wp_ajax_nopriv_pagelayer_givecss', 'pagelayer_givecss');
1114 +function pagelayer_givecss(){
1115 +
1116 + global $pagelayer;
1117 +
1118 + // WordPress adds the Expires header in all AJAX calls. We need to remove it for cache to work
1119 + header_remove("Expires");
1120 + header_remove("Cache-Control");
1121 +
1122 + // Pagelayer Template Loading Mechanism
1123 + include_once(PAGELAYER_DIR.'/css/givecss.php');
1124 +
1125 + exit();
1126 +
1127 +}
1128 +
1129 +// Shortcodes Widget Handler
1130 +add_action('wp_ajax_pagelayer_get_section_shortcodes', 'pagelayer_get_section_shortcodes');
1131 +function pagelayer_get_section_shortcodes(){
1132 +
1133 + global $pagelayer;
1134 +
1135 + // Some AJAX security
1136 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
1137 +
1138 + if(!current_user_can('edit_posts')){
1139 + $ret['error'][] = __pl('no_permission');
1140 + pagelayer_json_output($ret);
1141 + }
1142 +
1143 + $data = '';
1144 + if(isset($_REQUEST['pagelayer_section_id'])){
1145 +
1146 + $get_url = PAGELAYER_API.'/library.php?give_id='.sanitize_text_field($_REQUEST['pagelayer_section_id']).(!empty($pagelayer->license['license']) ? '&license='.$pagelayer->license['license'] : '').'&url='.rawurlencode(site_url());
1147 +
1148 + // For SitePad users
1149 + if(function_exists('get_softaculous_file')){
1150 + $get_url = get_softaculous_file($get_url, 1);
1151 + }
1152 +
1153 + $fetch = wp_remote_get($get_url, array('timeout' => 60));
1154 +
1155 + if ( is_array( $fetch ) && ! is_wp_error( $fetch ) && isset( $fetch['body'] ) ) {
1156 + $data = json_decode( $fetch['body'], true ); // use the content
1157 + }else{
1158 + $data['error'] = __pl('The response was malformed');
1159 + pagelayer_json_output($data);
1160 + }
1161 + }
1162 +
1163 + if(isset($_REQUEST['postID'])){
1164 + $post_id = (int) $_REQUEST['postID'];
1165 +
1166 + if(!empty($post_id)){
1167 + $post = get_post( $post_id );
1168 + // Need to make the reviews post global
1169 + if ( !empty( $post ) ) {
1170 + $GLOBALS['post'] = $post;
1171 +
1172 + $GLOBALS['wp_query'] = new WP_Query([
1173 + 'post_type' => $GLOBALS['post']->post_type,
1174 + 'post__in' => array($post_id),
1175 + ]);
1176 + }
1177 + }
1178 + }
1179 +
1180 + // Upload the images if any in the shortcode
1181 + preg_match_all('/"'.preg_quote('{{pl_lib_images}}', '/').'([^"]*)"/is', $data['code'], $matches);
1182 +
1183 + foreach($matches[0] as $k => $v){
1184 + $image_url = trim($v, '"\'');
1185 + $urls[$image_url] = $image_url;
1186 + }
1187 +
1188 + foreach($urls as $k => $image_url){
1189 +
1190 + $file = basename($image_url);
1191 + $id = 0;
1192 +
1193 + // Upload this
1194 + if(!empty($data[$file])){
1195 +
1196 + $id = pagelayer_upload_media($file, base64_decode($data[$file]));
1197 +
1198 + if(!empty($id)){
1199 + $data['code'] = str_replace('"'.$image_url.'"', '"'.$id.'"', $data['code']);
1200 + }
1201 + }
1202 +
1203 + }
1204 +
1205 + // Load shortcodes
1206 + pagelayer_load_shortcodes();
1207 +
1208 + if(!empty($data['code'])){
1209 + $data['code'] = pagelayer_the_content($data['code'], true);
1210 + }
1211 +
1212 + pagelayer_json_output($data);
1213 +
1214 +}
1215 +
1216 +// Shortcodes Widget Handler
1217 +add_action('wp_ajax_pagelayer_get_section_blocks', 'pagelayer_get_section_blocks');
1218 +function pagelayer_get_section_blocks(){
1219 +
1220 + global $pagelayer;
1221 +
1222 + // Some AJAX security
1223 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
1224 +
1225 + if(!current_user_can('edit_posts')){
1226 + $ret['error'][] = __pl('no_permission');
1227 + pagelayer_json_output($ret);
1228 + }
1229 +
1230 + $data = '';
1231 + if(isset($_REQUEST['pagelayer_section_id'])){
1232 +
1233 + $get_url = PAGELAYER_API.'/library.php?give_id='.sanitize_text_field($_REQUEST['pagelayer_section_id']).(!empty($pagelayer->license['license']) ? '&license='.$pagelayer->license['license'] : '').'&url='.rawurlencode(site_url());
1234 +
1235 + // For SitePad users
1236 + if(function_exists('get_softaculous_file')){
1237 + $get_url = get_softaculous_file($get_url, 1);
1238 + }
1239 +
1240 + $fetch = wp_remote_get($get_url, array('timeout' => 60));
1241 +
1242 + if ( is_array( $fetch ) && ! is_wp_error( $fetch ) && isset( $fetch['body'] ) ) {
1243 + $data = json_decode( $fetch['body'], true ); // use the content
1244 + }else{
1245 + $data['error'] = __pl('The response was malformed');
1246 + pagelayer_json_output($data);
1247 + }
1248 + }
1249 +
1250 + // Upload the images if any in the shortcode
1251 + preg_match_all('/"'.preg_quote('{{pl_lib_images}}', '/').'([^"]*)"/is', $data['code'], $matches);
1252 +
1253 + foreach($matches[0] as $k => $v){
1254 + $image_url = trim($v, '"\'');
1255 + $urls[$image_url] = $image_url;
1256 + }
1257 +
1258 + foreach($urls as $k => $image_url){
1259 +
1260 + $file = basename($image_url);
1261 + $id = 0;
1262 +
1263 + // Upload this
1264 + if(!empty($data[$file])){
1265 +
1266 + $id = pagelayer_upload_media($file, base64_decode($data[$file]));
1267 +
1268 + if(!empty($id)){
1269 + $data['code'] = str_replace('"'.$image_url.'"', '"'.$id.'"', $data['code']);
1270 + }
1271 + }
1272 +
1273 + }
1274 +
1275 + if ( false !== strpos( $data['code'], '[pl_' ) ) {
1276 + // Load shortcodes
1277 + pagelayer_load_shortcodes();
1278 +
1279 + // Load Parse Shortcodes
1280 + include_once(PAGELAYER_DIR.'/main/parse-shortcodes.php');
1281 +
1282 + $data['code'] = pagelayer_do_shortcode_to_block($data['code']);
1283 + }
1284 +
1285 + $data['code'] = pagelayer_add_tmp_atts($data['code']);
1286 +
1287 + pagelayer_json_output($data);
1288 +
1289 +}
1290 +
188 1291 // Get the Site Title
189 1292 add_action('wp_ajax_pagelayer_fetch_site_title', 'pagelayer_fetch_site_title');
190 1293 function pagelayer_fetch_site_title(){
191 1294
@@ -204,14 +1307,16 @@
204 1307 // Some AJAX security
205 1308 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
206 1309
207 1310 $site_title = $_POST['site_title'];
1311 +
1312 + if(!current_user_can('manage_options')){
1313 + $ret['error'][] = __pl('no_permission');
1314 + pagelayer_json_output($ret);
1315 + }
208 1316
209 1317 update_option('blogname', $site_title);
210 -
211 - $wpdb->query("UPDATE `sm_sitemeta`
212 - SET meta_value = '".$site_title."'
213 - WHERE meta_key = 'site_name'");
1318 +
214 1319 wp_die();
215 1320 }
216 1321
217 1322 // Show the SideBars
@@ -252,13 +1357,32 @@
252 1357 // Some AJAX security
253 1358 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
254 1359
255 1360 if(isset($_POST['nav_list'])){
256 - echo wp_nav_menu([
1361 + $_POST['nav_list'] = (int) $_POST['nav_list'];
1362 +
1363 + // Load Pagelayer nav menu walker
1364 + include_once(PAGELAYER_DIR.'/main/nav_walker.php');
1365 +
1366 + $postID = (int) $_REQUEST['postID'];
1367 +
1368 + // To on live mode
1369 + $GLOBALS['post'] = get_post($postID);
1370 + $GLOBALS['wp_query'] = new WP_Query([
1371 + 'post_type' => $GLOBALS['post']->post_type,
1372 + 'post__in' => array($postID),
1373 + ]);
1374 +
1375 + // Load short
1376 + pagelayer_load_shortcodes();
1377 +
1378 + wp_nav_menu([
257 1379 'menu' => wp_get_nav_menu_object($_POST['nav_list']),
258 1380 'menu_id' => $_POST["nav_list"],
1381 + 'menu_class' => 'pagelayer-wp_menu-ul',
1382 + 'walker' => new Pagelayer_Walker_Nav_Menu(),
259 1383 //'theme_location' => 'primary',
260 - //'menu_class' => 'primary-menu',
1384 + 'echo' => true,
261 1385 ]);
262 1386 }
263 1387
264 1388 wp_die();
@@ -263,8 +1387,47 @@
263 1387
264 1388 wp_die();
265 1389 }
266 1390
1391 +// Save post revision
1392 +add_action('wp_ajax_pagelayer_create_post_autosave', 'pagelayer_create_post_autosave');
1393 +function pagelayer_create_post_autosave(){
1394 +
1395 + // Some AJAX security
1396 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
1397 +
1398 + $ret = array();
1399 + $postID = (int) $_GET['postID'];
1400 + $content = $_REQUEST['pagelayer_post_content'];
1401 +
1402 + // Decode base64 data
1403 + $content = base64_decode($content);
1404 + $content = wp_slash($content);
1405 +
1406 + // Are you allowed to edit ?
1407 + if(!pagelayer_user_can_edit($postID)){
1408 + $ret['error'][] = __pl('no_permission');
1409 + pagelayer_json_output($ret);
1410 + }
1411 +
1412 + if(empty($postID)){
1413 + $ret['error'] = __pl('invalid_post_id');
1414 + }else{
1415 +
1416 + $post = array(
1417 + 'post_ID' => $postID,
1418 + 'post_content' => $content,
1419 + );
1420 +
1421 + $ret['id'] = wp_create_post_autosave($post);
1422 + }
1423 +
1424 + $ret['url'] = get_preview_post_link($postID);
1425 +
1426 + pagelayer_json_output($ret);
1427 +
1428 +}
1429 +
267 1430 // Get post revision
268 1431 add_action('wp_ajax_pagelayer_get_revision', 'pagelayer_get_revision');
269 1432 function pagelayer_get_revision(){
270 1433
@@ -270,22 +1433,28 @@
270 1433
271 1434 // Some AJAX security
272 1435 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
273 1436
1437 + $ret = array();
274 1438 $postID = (int) $_GET['postID'];
275 - $post_revisions = array();
1439 +
1440 + // Are you allowed to edit ?
1441 + if(!pagelayer_user_can_edit($postID)){
1442 + $ret['error'][] = __pl('no_permission');
1443 + pagelayer_json_output($ret);
1444 + }
276 1445
277 1446 if(empty($postID)){
278 - $post_revisions['error'] = __pl('invalid_post_id');
1447 + $ret['error'] = __pl('invalid_post_id');
279 1448 }else{
280 - $post_revisions = pagelayer_get_post_revision_by_id($postID);
1449 + $ret = pagelayer_get_post_revision_by_id($postID);
281 1450 }
282 1451
283 - pagelayer_json_output($post_revisions);
1452 + pagelayer_json_output($ret);
284 1453
285 1454 }
286 1455
287 -// Get post revision
1456 +// Apply post revision
288 1457 add_action('wp_ajax_pagelayer_apply_revision', 'pagelayer_apply_revision');
289 1458 function pagelayer_apply_revision(){
290 1459
291 1460 // Some AJAX security
@@ -291,39 +1460,55 @@
291 1460 // Some AJAX security
292 1461 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
293 1462
294 1463 $revisionID = (int) $_REQUEST['revisionID'];
295 - $post_data = array();
1464 + $parID = wp_get_post_parent_id($revisionID);
1465 + $ret = array();
296 1466
1467 + if(empty($parID)){
1468 + $parID = $revisionID;
1469 + }
1470 +
1471 + // Are you allowed to edit ?
1472 + if(!pagelayer_user_can_edit($parID)){
1473 + $ret['error'][] = __pl('no_permission');
1474 + pagelayer_json_output($ret);
1475 + }
1476 +
297 1477 if(empty($revisionID)){
298 - $post_data['error'] = __pl('invalid_post_id');
1478 + $ret['error'] = __pl('invalid_post_id');
299 1479 }else{
300 1480
301 1481 $post = get_post( $revisionID );
302 1482
303 1483 if ( empty( $post ) ) {
304 - $post_data['error'] = __pl('invalid_revision');
305 - pagelayer_json_output($post_data);
1484 + $ret['error'] = __pl('invalid_revision');
1485 + pagelayer_json_output($ret);
306 1486 }
307 1487
308 1488 // Need to make the reviews post global
309 1489 $GLOBALS['post'] = $post;
1490 + $GLOBALS['wp_query'] = new WP_Query([
1491 + 'post_type' => $GLOBALS['post']->post_type,
1492 + 'post__in' => array($parID),
1493 + ]);
310 1494
311 1495 // Need to reload the shortcodes
312 1496 pagelayer_load_shortcodes();
313 1497
314 - $post_data['content'] = do_shortcode($post->post_content);
1498 + $ret['id'] = $revisionID;
1499 + $ret['content'] = pagelayer_the_content($post->post_content, true);
315 1500
316 - if (is_wp_error($postID)) {
317 - $post_data['error'] = __pl('rev_load_error');
1501 + if(is_wp_error($post)) {
1502 + $ret['error'] = __pl('rev_load_error');
318 1503 }else{
319 - $post_data['success'] = __pl('rev_load_success');
1504 + $ret['success'] = __pl('rev_load_success');
320 1505 }
321 1506
322 1507 wp_reset_postdata();
323 1508 }
324 1509
325 - pagelayer_json_output($post_data);
1510 + pagelayer_json_output($ret);
326 1511
327 1512 }
328 1513
329 1514 // Get post revision
@@ -333,40 +1518,47 @@
333 1518 // Some AJAX security
334 1519 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
335 1520
336 1521 $revisionID = (int) $_REQUEST['revisionID'];
1522 + $parID = wp_get_post_parent_id($revisionID);
1523 + $ret = array();
337 1524
1525 + // Are you allowed to edit ?
1526 + if(!pagelayer_user_can_edit($parID)){
1527 + $ret['error'][] = __pl('no_permission');
1528 + pagelayer_json_output($ret);
1529 + }
1530 +
338 1531 if(empty($revisionID)){
339 - $post_data['error'] = __pl('invalid_post_id');
1532 + $ret['error'] = __pl('invalid_post_id');
340 1533 }else{
341 1534
342 1535 $revision = get_post( $revisionID );
343 1536
344 1537 if ( empty( $revision ) ) {
345 - $post_data['error'] = __pl('invalid_revision');
1538 + $ret['error'] = __pl('invalid_revision');
346 1539 }else{
347 1540
348 - if ( ! current_user_can( 'delete_post', $revision->ID ) ) {
349 - $post_data['error'] = __pl('access_denied');
350 - pagelayer_json_output($post_data);
351 - return false;
1541 + if ( ! current_user_can( 'delete_post', $parID ) ) {
1542 + $ret['error'] = __pl('access_denied');
1543 + pagelayer_json_output($ret);
352 1544 }
353 1545
354 1546 $deleted = wp_delete_post_revision( $revision->ID );
355 1547
356 1548 if ( ! $deleted || is_wp_error( $deleted ) ) {
357 - $post_data['error'] = __pl('delete_rev_error');
1549 + $ret['error'] = __pl('delete_rev_error');
358 1550 }else{
359 - $post_data['success'] = __pl('delete_rev_success');
1551 + $ret['success'] = __pl('delete_rev_success');
360 1552 }
361 1553 }
362 1554 }
363 1555
364 - pagelayer_json_output($post_data);
1556 + pagelayer_json_output($ret);
365 1557
366 1558 }
367 1559
368 -// Get post revision
1560 +// Get post navigation
369 1561 add_action('wp_ajax_pagelayer_post_nav', 'pagelayer_post_nav');
370 1562 function pagelayer_post_nav() {
371 1563
372 1564 // Some AJAX security
@@ -414,9 +1606,9 @@
414 1606 pagelayer_json_output($el);
415 1607
416 1608 }
417 1609
418 -// Get post comment template
1610 +// Get post comment template
419 1611 add_action('wp_ajax_pagelayer_post_comment', 'pagelayer_post_comment');
420 1612 function pagelayer_post_comment() {
421 1613 global $post;
422 1614
@@ -429,15 +1621,16 @@
429 1621
430 1622 $GLOBALS['post'] = get_post($_REQUEST['postID']);
431 1623 $GLOBALS['withcomments'] = true;
432 1624
433 - if ( comments_open() || get_comments_number() ) {
434 - echo '<div class="pagelayer-comments-template">'.comments_template().'</div>';
435 - }else{
436 - echo '<div class="pagelayer-comments-close">
437 - <h2>Comments are closed!</h2>
438 - </div>';
439 - }
1625 + // Load shortcodes
1626 + pagelayer_load_shortcodes();
1627 +
1628 + $el = [];
1629 + pagelayer_sc_post_comment($el);
1630 +
1631 + echo $el['atts']['post_comment'];
1632 +
440 1633 wp_die();
441 1634
442 1635 }
443 1636
@@ -456,80 +1649,12 @@
456 1649 $el['atts'] = $_REQUEST['el'];
457 1650
458 1651 $GLOBALS['post'] = get_post($_REQUEST['postID']);
459 1652
460 - $post_info_content ='';
461 - $link ='';
462 - $info_content ='';
463 - $avatar_url ='';
1653 + // Load shortcodes
1654 + pagelayer_load_shortcodes();
464 1655
465 - switch($el['atts']['type']){
466 - case 'author':
467 -
468 - $link = get_author_posts_url( get_the_author_meta( 'ID' ) );
469 - $avatar_url = get_avatar_url( get_the_author_meta( 'ID' ), 96 );
470 - $post_info_content = get_the_author_meta( 'display_name', $post->post_author );
471 - break;
472 -
473 - case 'date':
474 -
475 - $format = [
476 - 'default' => 'F j, Y',
477 - '0' => 'F j, Y',
478 - '1' => 'Y-m-d',
479 - '2' => 'm/d/Y',
480 - '3' => 'd/m/Y',
481 - 'custom' => empty( $el['atts']['date_format_custom'] ) ? 'F j, Y' : $el['atts']['date_format_custom'],
482 - ];
483 -
484 - $post_info_content = get_the_time( $format[ $el['atts']['date_format'] ] );
485 - $link = get_day_link( get_post_time( 'Y' ), get_post_time( 'm' ), get_post_time( 'j' ) );
486 -
487 - break;
488 -
489 - case 'time':
490 -
491 - $format = [
492 - 'default' => 'g:i a',
493 - '0' => 'g:i a',
494 - '1' => 'g:i A',
495 - '2' => 'H:i',
496 - 'custom' => empty( $el['atts']['time_format_custom'] ) ? 'F j, Y' : $el['atts']['time_format_custom'],
497 - ];
498 - $post_info_content = get_the_time( $format[ $el['atts']['time_format'] ] );
499 -
500 - break;
501 -
502 - case 'comments':
503 -
504 - if (comments_open()) {
505 - $post_info_content = (int) get_comments_number();
506 - $link = get_comments_link();
507 - }
508 -
509 - break;
510 -
511 - case 'terms':
512 -
513 - $taxonomy = $el['atts']['taxonomy'];
514 - $terms = wp_get_post_terms( get_the_ID(), $taxonomy );
515 - foreach ( $terms as $term ) {
516 - $post_info_content .= ' <a if-ext="{{info_link}}" href="'. get_term_link( $term ) .'" class="pagelayer-post-info-list-link"> '. $term->name .' </a>';
517 - }
518 -
519 - break;
520 -
521 - case 'custom':
522 -
523 - $post_info_content = $el['atts']['type_custom'];
524 - $link = $el['atts']['info_custom_link'];
525 -
526 - break;
527 - }
528 -
529 - $el['atts']['post_info_content'] = $post_info_content;
530 - $el['atts']['avatar_url'] = $avatar_url;
531 - $el['atts']['link'] = $link;
1656 + pagelayer_sc_post_info_list($el);
532 1657
533 1658 pagelayer_json_output($el['atts']);
534 1659
535 1660 }
@@ -536,18 +1661,22 @@
536 1661
537 1662 // Get the Featured Image
538 1663 add_action('wp_ajax_pagelayer_fetch_featured_img', 'pagelayer_fetch_featured_img');
539 1664 function pagelayer_fetch_featured_img(){
540 -
1665 +
541 1666 // Some AJAX security
542 1667 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
543 1668
544 - if($_POST['size']){
545 - echo get_the_post_thumbnail_url($_POST['post_id'], $_POST['size']);
546 - }else{
547 - echo get_the_post_thumbnail_url($_POST['post_id']);
1669 + $id = get_post_thumbnail_id( (int) $_POST['post_id'] );
1670 + $img = [];
1671 +
1672 + if(empty($id)){
1673 + pagelayer_json_output($img);
548 1674 }
549 - wp_die();
1675 +
1676 + $img = pagelayer_image($id);
1677 + pagelayer_json_output($img);
1678 +
550 1679 }
551 1680
552 1681 // Get the postfolio posts
553 1682 add_action('wp_ajax_pagelayer_fetch_posts', 'pagelayer_fetch_posts');
@@ -555,10 +1684,17 @@
555 1684
556 1685 // Some AJAX security
557 1686 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
558 1687
559 - echo pagelayer_widget_posts($_POST);
1688 + // This ajax call is only used during post/page editing
1689 + if(!current_user_can('edit_posts')){
1690 + echo __pl('no_permission');
1691 + wp_die();
1692 + }
560 1693
1694 + $sanitized_post = pagelayer_sanitize_posts_data($_POST);
1695 + echo pagelayer_widget_posts($sanitized_post);
1696 +
561 1697 wp_die();
562 1698 }
563 1699
564 1700 // Get the Posts
@@ -567,12 +1703,19 @@
567 1703
568 1704 // Some AJAX security
569 1705 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
570 1706
1707 + // This ajax call is only used during post/page editing
1708 + if(!current_user_can('edit_posts')){
1709 + echo __pl('no_permission');
1710 + wp_die();
1711 + }
1712 +
571 1713 // Load shortcodes
572 1714 pagelayer_load_shortcodes();
573 1715
574 - echo pagelayer_posts($_POST);
1716 + $sanitized_post = pagelayer_sanitize_posts_data($_POST, false);
1717 + echo pagelayer_posts($sanitized_post);
575 1718 wp_die();
576 1719 }
577 1720
578 1721 // Get the Posts
@@ -582,10 +1725,10 @@
582 1725 // Some AJAX security
583 1726 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
584 1727
585 1728 // Set excerpt length
586 - if($_POST['exc_length']){
587 - $exc_length = (int) $params['exc_length'];
1729 + if(!empty($_POST['atts']['exc_length'])){
1730 + $exc_length = (int) $_POST['atts']['exc_length'];
588 1731 add_filter( 'excerpt_length', function($length) use($exc_length){
589 1732 return $exc_length;
590 1733 }, 999 );
591 1734 }
@@ -592,9 +1735,21 @@
592 1735
593 1736 // Load shortcodes
594 1737 pagelayer_load_shortcodes();
595 1738
596 - echo pagelayer_posts($_POST, $_POST['pagelayer_wp_query']);
1739 + foreach($_POST['atts'] as $k => $v){
1740 + $v = pagelayer_maybe_implode($v);
1741 + $r[] = esc_html($k).'="'.pagelayer_escapeHTML($v).'"';
1742 + }
1743 +
1744 + $string = implode(' ', $r);
1745 + if(preg_match('/\]/is', $string)){
1746 + die('Hacking Attempt');
1747 + }
1748 +
1749 + $sc = '[pl_archive_posts '.$string.'][/pl_archive_posts]';
1750 +
1751 + echo pagelayer_the_content($sc);
597 1752 wp_die();
598 1753 }
599 1754
600 1755 // Handle Contact Form Data
@@ -600,27 +1755,181 @@
600 1755 // Handle Contact Form Data
601 1756 add_action('wp_ajax_pagelayer_contact_submit', 'pagelayer_contact_submit');
602 1757 add_action('wp_ajax_nopriv_pagelayer_contact_submit', 'pagelayer_contact_submit' );
603 1758 function pagelayer_contact_submit(){
604 -
1759 +
1760 + // Some AJAX security
1761 + check_ajax_referer('pagelayer_global', 'pagelayer_nonce');
1762 +
1763 + // A filter to short circuit this contact form
1764 + $continue = apply_filters('pagelayer_contact_submit_start', 1);
1765 + if(empty($continue)){
1766 + return false;
1767 + }
1768 +
1769 + $formdata = wp_unslash($_POST);
1770 + // NOTE : NEVER add anything to $formdata except $_POST vars
1771 +
1772 + if(isset($_POST['g-recaptcha-response']) ){
1773 +
1774 + if(!pagelayer_captcha_verify()){
1775 + $wp['failed'] = get_option('pagelayer_recaptcha_failed', __pl('cap_ver_fail'));
1776 + pagelayer_json_output($wp);
1777 + }
1778 +
1779 + unset($formdata['g-recaptcha-response']);
1780 + }
1781 +
1782 + // Unset the nonce
1783 + unset($formdata['pagelayer_nonce']);
1784 +
605 1785 $to_mail = get_option('pagelayer_cf_to_email');
1786 + $from_mail = get_option('pagelayer_cf_from_email');
606 1787 $subject = get_option('pagelayer_cf_subject');
1788 + $additional_headers = get_option('pagelayer_cf_headers');
1789 + $reply_to = '';
1790 + $body = '';
1791 + $headers = '';
1792 + $custom_templ = array();
1793 + $use_custom = false;
1794 + $use_html = false;
1795 + $pagelayer_id = sanitize_text_field($formdata['cfa-pagelayer-id']);
607 1796
608 - $fdata = $_POST['form_data'];
609 - parse_str($fdata, $formdata);
1797 + if(isset($formdata['cfa-custom-template']) && !empty($formdata['cfa-post-id'])){
1798 + $post_id = (int) $formdata['cfa-post-id'];
1799 +
1800 + if(!empty($post_id) && ( get_post_status( $post_id ) === 'publish' || current_user_can('publish_posts') )){
1801 + $contact_array = get_post_meta($post_id, 'pagelayer_contact_templates', true);
1802 +
1803 + if(!empty($contact_array) && !empty($contact_array[$pagelayer_id])){
1804 + $custom_templ = $contact_array[$pagelayer_id];
1805 + $use_custom = true;
1806 + }
1807 + }
1808 + }
610 1809
611 - // Make the email content
1810 + if($use_custom && !empty($custom_templ)){
1811 +
1812 + if(!empty($custom_templ['to_email'])){
1813 + $to_mail = $custom_templ['to_email'];
1814 + }
1815 +
1816 + if(!empty($custom_templ['from_email'])){
1817 + $from_mail = $custom_templ['from_email'];
1818 + }
1819 +
1820 + if(!empty($custom_templ['cont_subject'])){
1821 + $subject = $custom_templ['cont_subject'];
1822 + }
1823 +
1824 + if(!empty($custom_templ['cont_header'])){
1825 + $additional_headers = $custom_templ['cont_header'];
1826 + }
1827 +
1828 + if(!empty($custom_templ['cont_body'])){
1829 + $body = $custom_templ['cont_body'];
1830 + }
1831 +
1832 + if(!empty($custom_templ['cont_use_html'])){
1833 + $use_html = true;
1834 + $headers .= "Content-Type: text/html\n";
1835 + }
1836 + }
1837 +
1838 + if(!empty($from_mail)){
1839 + $headers .= "From: $from_mail\n";
1840 + }
1841 +
1842 + if ( !empty($additional_headers) ) {
1843 + $headers .= $additional_headers . "\n";
1844 + }
1845 +
1846 + if ( empty($body) ) {
1847 +
1848 + // Make the email content
1849 + foreach($formdata as $k => $i){
1850 +
1851 + $not_allow = ['cfa-pagelayer-id', 'cfa-redirect', 'cfa-post-id', 'cfa-custom-template', 'pagelayer-contact-submit'];
1852 + if(in_array($k, $not_allow)){
1853 + continue;
1854 + }
1855 +
1856 + $body .= sanitize_text_field($k)."\t : \t $".$k."\n";
1857 +
1858 + }
1859 +
1860 + $body .= "\n\n --\n This e-mail was sent from a contact form (".get_home_url().")";
1861 +
1862 + }
1863 +
1864 + // Add attachment
1865 + if(!empty($_FILES)){
1866 + add_action('phpmailer_init', 'pagelayer_cf_email_attachment', 10, 1);
1867 + }
1868 +
1869 + $sanitized_data = array();
1870 +
1871 + // If we are using HTML, then we should escape html as well
612 1872 foreach($formdata as $k => $i){
613 - $data .= ''.$k.'\t : \t'.$i.'\n';
1873 +
1874 + if(is_array($i)){
1875 + $i = pagelayer_flat_join($i);
1876 + }
1877 +
1878 + $i = pagelayer_esc_crlf($i);
1879 +
1880 + if(!empty($use_html)){
1881 + $i = esc_html($i);
1882 + }
1883 +
1884 + // Sanitize text field
1885 + $i = sanitize_text_field($i);
1886 +
1887 + // Record a reply to if it is to be used
1888 + if(is_email($i) && empty($reply_to)){
1889 + $reply_to = $i;
1890 + }
1891 +
1892 + $sanitized_data[$k] = $i;
614 1893 }
615 1894
1895 + // Dow we have a reply to in the headers ?
1896 + if(!preg_match('/reply\-to/is', $headers) && !empty($reply_to)){
1897 + $headers .= "Reply-To: $reply_to\n";
1898 + }
1899 +
1900 + // Add Site Title as option in formdata
1901 + $sanitized_data['site_title'] = get_bloginfo( 'name' );
1902 +
1903 + // Do parse a variables
1904 + $to_mail = pagelayer_replace_vars($to_mail, $sanitized_data, '$');
1905 + $from_mail = pagelayer_replace_vars($from_mail, $sanitized_data, '$');
1906 + $subject = pagelayer_replace_vars($subject, $sanitized_data, '$');
1907 + $headers = pagelayer_replace_vars($headers, $sanitized_data, '$');
1908 + $body = pagelayer_replace_vars($body, $sanitized_data, '$');
1909 +
1910 + if ( $use_html && ! preg_match( '%<html[>\s].*</html>%is', $body ) ) {
1911 + $header = '<!doctype html>
1912 +<html xmlns="http://www.w3.org/1999/xhtml">
1913 +<head><title>' . esc_html( $subject ) . '</title></head>
1914 +<body>';
1915 +
1916 + $footer = '</body></html>';
1917 +
1918 + $body = $header . wpautop( $body ) . $footer;
1919 + }
1920 +
1921 + $to_mail = apply_filters('pagelayer_contact_send', $to_mail, $sanitized_data);
1922 +
616 1923 // Send the email
617 - $r = wp_mail( $to_mail, $subject, $data );
1924 + if(!empty($to_mail)){
1925 + $r = wp_mail( $to_mail, $subject, $body, $headers );
1926 + }
618 1927
619 1928 if($r == TRUE){
620 - $wp['success'] = get_option( 'pagelayer_cf_success' );
1929 + $wp['success'] = pagelayer_get_option( 'pagelayer_cf_success' );
621 1930 }else{
622 - $wp['failed'] = get_option( 'pagelayer_cf_failed' );
1931 + $wp['failed'] = pagelayer_get_option( 'pagelayer_cf_failed' );
623 1932 }
624 1933
625 1934 pagelayer_json_output($wp);
626 1935
@@ -625,36 +1934,21 @@
625 1934 pagelayer_json_output($wp);
626 1935
627 1936 }
628 1937
629 -// Fetch Google reCaptcha Key
630 -add_action('wp_ajax_pagelayer_fetch_grecaptcha_key', 'pagelayer_fetch_grecaptcha_key');
631 -function pagelayer_fetch_grecaptcha_key(){
632 -
633 - $data['key'] = get_option('pagelayer_google_captcha');
634 -
635 - pagelayer_json_output($data);
636 -
637 -}
638 -
639 1938 // Handle Login Submit
640 1939 add_action('wp_ajax_pagelayer_login_submit', 'pagelayer_login_submit');
641 1940 add_action('wp_ajax_nopriv_pagelayer_login_submit', 'pagelayer_login_submit');
642 1941 function pagelayer_login_submit(){
1942 +
1943 + // Some AJAX security
1944 + check_ajax_referer('pagelayer_global', 'pagelayer_nonce');
643 1945
644 - $fdata = $_POST['form_data'];
645 - parse_str($fdata, $formdata);
646 -
647 1946 $creds = array();
648 - $creds['user_login'] = $formdata['username'];
649 - $creds['user_password'] = $formdata['password'];
650 - $creds['remember'] = $formdata['remember_me'];
1947 + $creds['user_login'] = $_REQUEST['username'];
1948 + $creds['user_password'] = $_REQUEST['password'];
1949 + $creds['remember'] = $_REQUEST['remember_me'];
651 1950
652 - // If After logout URL, then save
653 - if(!empty($formdata['logout_url'])){
654 - update_user_option('pagelayer_logout_url', $formdata['logout_url']);
655 - }
656 -
657 1951 // Login the user
658 1952 $user = wp_signon( $creds, false );
659 1953
660 1954 if ( is_wp_error($user) ){
@@ -659,9 +1953,15 @@
659 1953
660 1954 if ( is_wp_error($user) ){
661 1955 $data['error'] = $user->get_error_message();
662 1956 }else{
663 - $data['redirect'] = (empty($formdata['login_url']) ? '' : $formdata['login_url']);
1957 +
1958 + // If After logout URL, then save
1959 + if(!empty($_REQUEST['logout_url'])){
1960 + update_user_option($user->ID, 'pagelayer_logout_url', sanitize_url($_REQUEST['logout_url']));
1961 + }
1962 +
1963 + $data['redirect'] = (empty($_REQUEST['login_url']) ? '' : sanitize_url($_REQUEST['login_url']));
664 1964 $data['error'] = '';
665 1965 }
666 1966
667 1967 pagelayer_json_output($data);
@@ -667,33 +1967,27 @@
667 1967 pagelayer_json_output($data);
668 1968
669 1969 }
670 1970
671 -// Handle Logout Redirect here
672 -add_action('wp_logout', 'pagelayer_after_logout');
673 -function pagelayer_after_logout(){
674 -
675 - $url = get_user_option('pagelayer_logout_url');
676 -
677 - // We will redirect if we have the given item set.
678 - if(!empty($url)){
679 - wp_redirect( $url );
680 - exit();
681 - }
682 -
683 -}
684 -
685 1971 // Get Page List for SiteMap
686 1972 add_action('wp_ajax_pagelayer_get_pages_list', 'pagelayer_get_pages_list');
687 -add_action('wp_ajax_nopriv_pagelayer_get_pages_list', 'pagelayer_get_pages_list');
688 1973 function pagelayer_get_pages_list(){
1974 +
1975 + // Some AJAX security
1976 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
689 1977
1978 + if(!current_user_can('edit_posts')){
1979 + echo __pl('no_permission');
1980 + wp_die();
1981 + }
1982 +
690 1983 $args = array(
691 - 'post_type' => $_POST['type'],
692 - 'orderby' => $_POST['post_order'],
693 - 'order' => $_POST['order'],
694 - 'hierarchical' => (empty($_POST['hier']) || $_POST['hier'] == null ? '' : $_POST['hier']),
695 - 'number' => (empty($_POST['depth']) || $_POST['depth'] == null ? '' : $_POST['depth']),
1984 + 'post_type' => sanitize_text_field($_POST['type']),
1985 + 'orderby' => sanitize_text_field($_POST['post_order']),
1986 + 'order' => sanitize_text_field($_POST['order']),
1987 + 'hierarchical' => (empty($_POST['hier']) || $_POST['hier'] == null ? '' : sanitize_text_field($_POST['hier'])),
1988 + 'number' => (empty($_POST['depth']) || $_POST['depth'] == null ? '' : sanitize_text_field($_POST['depth'])),
1989 + 'posts_per_page' => -1,
696 1990 );
697 1991
698 1992 $option = '<ul>';
699 1993 $pages = new WP_Query($args);
@@ -702,12 +1996,11 @@
702 1996 $option .= '<li class="pagelayer-sitemap-list-item" data-postID="'.$page->ID.'"><a class="pagelayer-ele-link" href="'.$page->guid.'">'.$page->post_name.'</a></li>';
703 1997 }
704 1998 $option .= '</ul>';
705 1999
706 -
707 2000 echo $option;
708 2001
709 - wp_die();
2002 + wp_die();
710 2003 }
711 2004
712 2005 // Get the data for template
713 2006 add_action('wp_ajax_pagelayer_search_ids', 'pagelayer_search_ids');
@@ -713,9 +2006,9 @@
713 2006 add_action('wp_ajax_pagelayer_search_ids', 'pagelayer_search_ids');
714 2007 function pagelayer_search_ids() {
715 2008
716 2009 // Some AJAX security
717 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2010 + check_ajax_referer('pagelayer_builder', 'pagelayer_nonce');
718 2011
719 2012 if ( empty( $_POST['filter_type'] ) || empty( $_POST['search'] ) ) {
720 2013 wp_die();
721 2014 }
@@ -759,9 +2052,9 @@
759 2052 break;
760 2053
761 2054 case 'author':
762 2055 $query_params = [
763 - 'who' => 'authors',
2056 + 'capability' => array( 'edit_posts' ),
764 2057 'fields' => [
765 2058 'ID',
766 2059 'display_name',
767 2060 ],
@@ -769,9 +2062,15 @@
769 2062 'search_columns' => [
770 2063 'user_login',
771 2064 'user_nicename',
772 2065 ],
773 - ];
2066 + ];
2067 +
2068 + // Capability queries were only introduced in WP 5.9.
2069 + if( version_compare( $GLOBALS['wp_version'], '5.9-alpha', '<' ) ){
2070 + $args['who'] = 'authors';
2071 + unset( $args['capability'] );
2072 + }
774 2073
775 2074 $user_query = new \WP_User_Query( $query_params );
776 2075
777 2076 foreach ( $user_query->get_results() as $author ) {
@@ -777,8 +2076,23 @@
777 2076 foreach ( $user_query->get_results() as $author ) {
778 2077 $sel_opt .= '<span class="pagelayer-temp-search-sel-span" value="'. $author->ID .'">'. $author->display_name .'</span>';
779 2078 }
780 2079 break;
2080 +
2081 + /* case 'menu':
2082 +
2083 + $menuItems = wp_get_nav_menu_items( (int)$_POST['object_type']);
2084 +
2085 + foreach ( $menuItems as $item ) {
2086 +
2087 + if($item -> menu_item_parent !=0 ){
2088 + continue;
2089 + }
2090 + $sel_opt .= '<span class="pagelayer-temp-search-sel-span" value="'. $item -> ID .'">'. $item -> title.'</span>';
2091 + }
2092 +
2093 + break; */
2094 +
781 2095 default:
782 2096 $sel_opt = 'Result Not Found';
783 2097 }
784 2098
@@ -790,23 +2104,33 @@
790 2104
791 2105 wp_die();
792 2106 }
793 2107
794 -
795 2108 // Save the post data from pagelayer setting page
796 2109 add_action('wp_ajax_pagelayer_save_template', 'pagelayer_save_template');
797 2110 function pagelayer_save_template() {
798 2111
799 2112 // Some AJAX security
800 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2113 + check_ajax_referer('pagelayer_builder', 'pagelayer_nonce');
801 2114
802 2115 $done = [];
803 2116
804 2117 $post_id = (int) $_GET['postID'];
2118 +
2119 + // Are you allowed to edit ?
2120 + if(!empty($post_id) && !pagelayer_user_can_edit($post_id)){
2121 + $done['error'][] = __pl('no_permission');
2122 + pagelayer_json_output($done);
2123 + }
805 2124
806 2125 // We need to create the post
807 2126 if(empty($post_id)){
808 2127
2128 + if (!current_user_can('edit_posts')) {
2129 + $done['error'] = __pl('access_denied');
2130 + pagelayer_json_output($done);
2131 + }
2132 +
809 2133 // Get the template type
810 2134 if(empty($_POST['pagelayer_template_type'])){
811 2135 $done['error'] = __pl('temp_error_type');
812 2136 pagelayer_json_output($done);
@@ -876,95 +2200,8 @@
876 2200 pagelayer_json_output($done);
877 2201
878 2202 }
879 2203
880 -// Product Images Handler
881 -add_action('wp_ajax_pagelayer_product_images', 'pagelayer_product_images');
882 -function pagelayer_product_images(){
883 - global $product;
884 -
885 - // Some AJAX security
886 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
887 -
888 - if ( !isset($_REQUEST['postID']) ) {
889 - return;
890 - }
891 -
892 - $product = wc_get_product($_REQUEST['postID']);
893 -
894 - if ( empty( $product ) ) {
895 - return ;
896 - }
897 -
898 - if ( isset($_POST['sale_flash']) ) {
899 - wc_get_template( 'loop/sale-flash.php' );
900 - }
901 - wc_get_template( 'single-product/product-image.php' );
902 -
903 - // On render widget from Editor - trigger the init manually.
904 - echo '
905 - <script>
906 - jQuery(".woocommerce-product-gallery").each( function() {
907 - jQuery(this).wc_product_gallery();
908 - } );
909 - </script>
910 - ';
911 -
912 - wp_die();
913 -}
914 -
915 -// Related Products Handler
916 -add_action('wp_ajax_pagelayer_product_related', 'pagelayer_product_related');
917 -function pagelayer_product_related(){
918 - global $product;
919 -
920 - // Some AJAX security
921 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
922 -
923 - if ( !isset($_REQUEST['postID']) ) {
924 - return;
925 - }
926 -
927 - $product = wc_get_product($_REQUEST['postID']);
928 -
929 - if ( empty( $product ) ) {
930 - return ;
931 - }
932 -
933 - $args = $_REQUEST['pagelayer_args'];
934 -
935 - if(function_exists( 'woocommerce_related_products' )){
936 - woocommerce_related_products($args);
937 - }
938 -
939 - wp_die();
940 -}
941 -
942 -// Upsell Products Handler
943 -add_action('wp_ajax_pagelayer_product_upsell', 'pagelayer_product_upsell');
944 -function pagelayer_product_upsell(){
945 - global $product;
946 -
947 - // Some AJAX security
948 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
949 -
950 - if ( !isset($_REQUEST['postID']) ) {
951 - return;
952 - }
953 -
954 - $product = wc_get_product($_REQUEST['postID']);
955 -
956 - if ( empty( $product ) ) {
957 - return ;
958 - }
959 -
960 - if(function_exists( 'woocommerce_related_products' )){
961 - woocommerce_upsell_display( $_REQUEST['limit'], $_REQUEST['columns'], $_REQUEST['orderby'], $_REQUEST['order'] );
962 - }
963 -
964 - wp_die();
965 -}
966 -
967 2204 // Products Categories Handler
968 2205 add_action('wp_ajax_pagelayer_product_categories', 'pagelayer_product_categories');
969 2206 function pagelayer_product_categories(){
970 2207
@@ -988,54 +2225,14 @@
988 2225
989 2226 $shortcode = '[product_categories '. $attributes .']';
990 2227
991 2228 // do_shortcode the shortcode
992 - echo do_shortcode($shortcode);
2229 + echo pagelayer_the_content($shortcode);
993 2230
994 2231 wp_die();
995 2232 }
996 2233
997 2234 // Products Categories Handler
998 -add_action('wp_ajax_pagelayer_product_archives', 'pagelayer_product_archives');
999 -function pagelayer_product_archives(){
1000 -
1001 - // Some AJAX security
1002 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
1003 -
1004 - if ( WC()->session ) {
1005 - wc_print_notices();
1006 - }
1007 -
1008 - $atts['paginate'] = true;
1009 - $atts['cache'] = false;
1010 - $no_found = $_POST['atts']['no_found'];
1011 -
1012 - if( empty($_POST['atts']['allow_order']) ){
1013 - remove_action( 'woocommerce_before_shop_loop', 'woocommerce_catalog_ordering', 30 );
1014 - }
1015 - if( empty($_POST['atts']['show_result']) ){
1016 - remove_action( 'woocommerce_before_shop_loop', 'woocommerce_result_count', 20 );
1017 - }
1018 -
1019 - $type = 'pagelayer_current_query';
1020 -
1021 - // Set the current query
1022 - add_action( 'woocommerce_shortcode_products_query', 'pagelayer_shortcode_current_query', 10, 10);
1023 -
1024 - // If product not found
1025 - add_action( "woocommerce_shortcode_{$type}_loop_no_results", function ($attributes) use ($no_found){
1026 - echo '<div class="pagelayer-product-no-found">'.$no_found.'</div>';
1027 - } );
1028 -
1029 - // Get the products list
1030 - $shortcode = new WC_Shortcode_Products( $atts, $type );
1031 -
1032 - echo $shortcode->get_content();
1033 -
1034 - wp_die();
1035 -}
1036 -
1037 -// Products Categories Handler
1038 2235 add_action('wp_ajax_pagelayer_products_ajax', 'pagelayer_products_ajax');
1039 2236 function pagelayer_products_ajax(){
1040 2237
1041 2238 // Some AJAX security
@@ -1092,9 +2289,9 @@
1092 2289 }
1093 2290
1094 2291 $shortcode = '['.$type.' '. $attributes .']';
1095 2292
1096 - $content = do_shortcode($shortcode);
2293 + $content = pagelayer_the_content($shortcode);
1097 2294
1098 2295 // If product not found
1099 2296 if('<div class="woocommerce columns-'.$_POST['atts']['columns'] .' "></div>' == $content){
1100 2297 $content = '<div class="pagelayer-product-no-found">'. $no_found .'</div>';
@@ -1104,13 +2301,70 @@
1104 2301
1105 2302 wp_die();
1106 2303 }
1107 2304
2305 +// Markdown Handler
2306 +add_action('wp_ajax_pagelayer_handle_markdown', 'pagelayer_handle_markdown');
2307 +function pagelayer_handle_markdown(){
2308 +
2309 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2310 +
2311 + if(!defined('PAGELAYER_PRO_VERSION')){
2312 + wp_send_json_error(['message' => __('Markdown feature requires Pagelayer Pro.', 'pagelayer')]);
2313 + return;
2314 + }
2315 +
2316 + include_once(PAGELAYER_PRO_DIR.'/main/premium_functions.php');
2317 +
2318 + $raw_atts = isset($_POST['data']) && is_array($_POST['data']) ? wp_unslash($_POST['data']) : [];
2319 + $atts = [];
2320 +
2321 + foreach($raw_atts as $key => $value){
2322 + $clean_key = sanitize_key($key);
2323 +
2324 + // Check for invalid UTF-8 to prevent database errors
2325 + if(in_array($clean_key, ['markdown_text_file', 'markdown_text_url', 'active_markdown_text'])){
2326 + $atts[$clean_key] = wp_check_invalid_utf8($value);
2327 + } else{
2328 + $atts[$clean_key] = sanitize_text_field($value);
2329 + }
2330 + }
2331 +
2332 + $fetched = pagelayer_get_markdown_content($atts);
2333 + $current_text = $fetched['text'];
2334 + $default_text = __pl('Select a Markdown file or enter a URL to load content.');
2335 +
2336 + // Compile HTML
2337 + $html = '';
2338 + if(!empty($fetched['is_error'])){
2339 + $html = '<div class="pagelayer-markdown-error">' . esc_html($current_text) . '</div>';
2340 + } else if($current_text === $default_text){
2341 + $html = '<div class="pagelayer-markdown-placeholder">' . $default_text . '</div>';
2342 + } else if(function_exists('pagelayer_markdown_to_html')){
2343 + $html = pagelayer_markdown_to_html($current_text);
2344 + }
2345 +
2346 + $wp['html'] = wp_kses_post($html);
2347 + $wp['raw_text'] = $current_text;
2348 + $wp['is_error'] = !empty($fetched['is_error']);
2349 +
2350 + pagelayer_json_output($wp);
2351 +
2352 + wp_die();
2353 +}
2354 +
1108 2355 // Get Taxamony List for SiteMap
1109 2356 add_action('wp_ajax_pagelayer_get_taxonomy_list', 'pagelayer_get_taxonomy_list');
1110 -add_action('wp_ajax_nopriv_pagelayer_get_taxonomy_list', 'pagelayer_get_taxonomy_list');
1111 2357 function pagelayer_get_taxonomy_list(){
1112 2358
2359 + // Some AJAX security
2360 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2361 +
2362 + if(!current_user_can('edit_posts')){
2363 + echo __pl('no_permission');
2364 + wp_die();
2365 + }
2366 +
1113 2367 $args = array(
1114 2368 'title_li' => 0,
1115 2369 'orderby' => $_POST['post_order'],
1116 2370 'order' => $_POST['order'],
@@ -1140,12 +2394,17 @@
1140 2394
1141 2395 global $pagelayer;
1142 2396
1143 2397 // Some AJAX security
1144 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2398 + check_ajax_referer('pagelayer_builder', 'pagelayer_nonce');
1145 2399
1146 2400 $done = [];
1147 2401
2402 + if(!current_user_can('edit_theme_options')){
2403 + $done['error'][] = __pl('no_permission');
2404 + pagelayer_json_output($done);
2405 + }
2406 +
1148 2407 // Load the templates
1149 2408 pagelayer_builder_load_templates();
1150 2409
1151 2410 if(empty($pagelayer->templates)){
@@ -1152,8 +2411,11 @@
1152 2411 $done['error'] = __pl('temp_export_empty');
1153 2412 pagelayer_json_output($done);
1154 2413 }
1155 2414
2415 + // Load Shortcodes
2416 + pagelayer_load_shortcodes();
2417 +
1156 2418 // Get the active theme
1157 2419 $theme_dir = get_stylesheet_directory();
1158 2420 $conf = [];
1159 2421
@@ -1168,11 +2430,21 @@
1168 2430 continue;
1169 2431 }
1170 2432 }
1171 2433
1172 - file_put_contents($theme_dir.'/'.$v->post_name.'.pgl', pagelayer_export_content($v->post_content));
2434 + // Only blocks allowed
2435 + if(!has_blocks($v->post_content) && !empty($v->post_content)){
2436 + $done['error'] = 'The pagelayer template '.$v->ID.' has Shortcodes which is not allowed for export !';
2437 + pagelayer_json_output($done);
2438 + }
2439 +
2440 + $v->post_name = (empty($v->post_name) && $v->post_status == 'draft') ? sanitize_title($v->post_title).'-draft' : $v->post_name;
2441 +
2442 + // Write the content
2443 + file_put_contents($theme_dir.'/'.$v->post_name.'.pgl', pagelayer_export_content($v->post_content));
1173 2444 $conf[$v->post_name] = [
1174 2445 'type' => get_post_meta($v->ID, 'pagelayer_template_type', true),
2446 + 'title' => $v->post_title,
1175 2447 'conditions' => get_post_meta($v->ID, 'pagelayer_template_conditions', true),
1176 2448 ];
1177 2449 }
1178 2450
@@ -1177,37 +2449,222 @@
1177 2449 }
1178 2450
1179 2451 // Write the config
1180 2452 file_put_contents($theme_dir.'/pagelayer.conf', json_encode($conf, JSON_PRETTY_PRINT));
2453 +
2454 + $conf = [];
1181 2455
1182 - // Any pages to export for users ?
1183 - if(!empty($_POST['pages'])){
2456 + // Load the other posts
2457 + foreach($pagelayer->settings['post_types'] as $type){
1184 2458
1185 - mkdir($theme_dir.'/data/');
1186 - mkdir($theme_dir.'/data/page');
2459 + // Anything to export for users ?
2460 + if(!empty($_POST[$type]) && is_array($_POST[$type])){
2461 +
2462 + mkdir($theme_dir.'/data/');
2463 + mkdir($theme_dir.'/data/'.$type);
2464 +
2465 + $pids = [];
2466 +
2467 + foreach($_POST[$type] as $k => $v){
2468 + $pids[] = (int) $k;
2469 + }
2470 +
2471 + // Load the type
2472 + $_query = new WP_Query([
2473 + 'post_type' => $type,
2474 + 'status' => 'publish',
2475 + 'post__in' => $pids,
2476 + 'posts_per_page' => -1,
2477 + ]);
2478 +
2479 + $posts = $_query->posts;
1187 2480
1188 - $conf = [];
2481 + // Write the files
2482 + foreach($posts as $k => $v){
1189 2483
1190 - // Load the pages
1191 - $pages_query = new WP_Query(['post_type' => 'page', 'status' => 'publish']);
1192 - $pages = $pages_query->posts;
2484 + // Only blocks allowed
2485 + if(!has_blocks($v->post_content) && !empty($v->post_content)){
2486 + $done['error'] = 'The '.$type.' '.$v->ID.' has Shortcodes which is not allowed for export !';
2487 + pagelayer_json_output($done);
2488 + }
2489 +
2490 + $v->post_name = (empty($v->post_name) && $v->post_status == 'draft') ? sanitize_title($v->post_title).'-draft' : $v->post_name;
2491 +
2492 + file_put_contents($theme_dir.'/data/'.$type.'/'.$v->post_name, pagelayer_export_content($v->post_content));
2493 + unset($v->post_content);
2494 +
2495 + $meta = get_post_meta($v->ID);
2496 + $meta = array_combine(array_keys($meta), array_column($meta, 0));
2497 +
2498 + // Export media
2499 + if(!empty($meta['_thumbnail_id'])){
2500 +
2501 + $file = pagelayer_export_media_files($meta['_thumbnail_id'], $exp_img_url);
2502 +
2503 + // Did it export ?
2504 + if(!empty($file)){
2505 + $meta['_thumbnail_id'] = $exp_img_url;
2506 + }
2507 +
2508 + }
2509 +
2510 + // Also put the meta
2511 + file_put_contents($theme_dir.'/data/'.$type.'/'.$v->post_name.'.meta', json_encode($meta, JSON_PRETTY_PRINT));
2512 +
2513 + //Export taxonomies in post
2514 + $taxonomies = get_object_taxonomies( $v->post_type, 'objects' );
2515 + $post_taxonomies = wp_filter_object_list( $taxonomies, [
2516 + 'public' => true,
2517 + 'show_in_nav_menus' => true,
2518 + ] );
2519 +
2520 + foreach( $post_taxonomies as $slug => $object ){
2521 +
2522 + if(empty($v->taxonomies) || !is_array($v->taxonomies)){
2523 + $v->taxonomies = array();
2524 + }
2525 +
2526 + $tax_name = $object->name;
2527 + $the_terms = get_the_terms($v->ID, $tax_name);
2528 + $v->taxonomies[$tax_name] = '';
2529 +
2530 + if(!empty($the_terms)){
2531 + $v->taxonomies[$tax_name] = implode(',', array_column($the_terms, 'term_id'));
2532 + }
2533 + }
2534 +
2535 + $conf[$type][$v->post_name] = $v;
2536 +
2537 + do_action('pagelayer_'.$type.'_exported', $v, $theme_dir);
2538 +
2539 + }
2540 +
2541 + ksort($conf[$type]);
2542 +
2543 + }
1193 2544
1194 - // Write the files
1195 - foreach($pages as $k => $v){
2545 + }
2546 +
2547 + // Export menus
2548 + if(!empty($pagelayer->export_menus) && is_array($pagelayer->export_menus)){
2549 +
2550 + mkdir($theme_dir.'/data/menus');
2551 +
2552 + foreach($pagelayer->export_menus as $k => $v){
1196 2553
1197 - if(!isset($_POST['pages'][$v->ID])){
2554 + $menu = (int) $k;
2555 + $menu = wp_get_nav_menu_object( $menu );
2556 +
2557 + if(empty($menu)){
2558 + $done['error'] = 'Could not export menu ID - '.$k;
1198 2559 continue;
1199 2560 }
2561 +
2562 + // Menu Items
2563 + $menu_items = wp_get_nav_menu_items( $menu->term_id );
2564 + $data = [];
2565 +
2566 + if(is_array($menu_items) && !empty($menu_items)){
2567 + foreach($menu_items as $kk => $singlenav){
2568 + //$navmetas = get_post_meta($singlenav->ID);
2569 + //$navmetas = array_combine(array_keys($navmetas), array_column($navmetas, 0));
2570 + $data[$kk]['post'] = $singlenav;
2571 + $navmetas = array();
2572 +
2573 + $pl_content = get_post_meta($singlenav->ID, '_pagelayer_content', true);
2574 + if(!empty($pl_content)){
2575 + $navmetas['_pagelayer_content'] = pagelayer_export_content($pl_content);
2576 + }
2577 +
2578 + $data[$kk]['post_metas'] = $navmetas;
2579 + }
2580 + }
2581 +
2582 + // Also put the meta
2583 + file_put_contents($theme_dir.'/data/menus/'.$menu->slug, json_encode($data, JSON_PRETTY_PRINT));
2584 +
2585 + $conf['menus'][$menu->slug] = $menu;
2586 +
2587 + do_action('pagelayer_menus_exported', $v, $theme_dir);
1200 2588
1201 - file_put_contents($theme_dir.'/data/page/'.$v->post_name, pagelayer_export_content($v->post_content));
1202 - unset($v->post_content);
1203 - $conf['page'][$v->post_name] = $v;
2589 + }
2590 +
2591 + }
2592 +
2593 + // Export the settings
2594 + $settings = ['pagelayer_content_width', 'pagelayer_body_font', 'pagelayer_tablet_breakpoint', 'pagelayer_mobile_breakpoint', 'pagelayer_header_code','pagelayer_body_open_code', 'pagelayer_footer_code', 'pagelayer_sidebar', 'page_for_posts', 'pagelayer_global_fonts', 'pagelayer_global_colors'];
2595 +
2596 + foreach($settings as $v){
2597 +
2598 + $vv = get_option($v);
2599 +
2600 + if($vv){
2601 + $conf['conf'][$v] = $vv;
2602 + }
2603 +
2604 + }
2605 +
2606 + // Load CSS settings
2607 + foreach($pagelayer->css_settings as $k => $params){
2608 + foreach($pagelayer->screens as $sk => $sv){
2609 + $suffix = (!empty($sv) ? '_'.$sv : '');
2610 + $setting = empty($params['key']) ? 'pagelayer_'.$k.'_css' : $params['key'];
2611 + $tmp = get_option($setting.$suffix);
2612 + if(!empty($tmp)){
2613 + $conf['conf'][$setting.$suffix] = $tmp;
2614 + }
2615 + }
2616 + }
2617 +
2618 + // Export all the taxonomies
2619 + $post_types = pagelayer_get_public_post_types();
2620 +
2621 + // Export all the Post Type CSS Settings
2622 + foreach ( $post_types as $pt_slug => $type ) {
2623 +
2624 + if ( $pt_slug == 'attachment' ) {
2625 + continue;
2626 + }
2627 +
2628 + foreach($pagelayer->css_settings as $k => $params){
2629 + foreach($pagelayer->screens as $sk => $sv){
2630 + $suffix = (!empty($sv) ? '_'.$sv : '');
2631 + $setting = empty($params['key']) ? 'pagelayer_'.$k.'_css_'.$pt_slug : $params['key'].'_'.$pt_slug;
2632 + $tmp = get_option($setting.$suffix);
2633 +
2634 + if(!empty($tmp)){
2635 + $conf['conf'][$setting.$suffix] = $tmp;
2636 + }
2637 + }
2638 + }
2639 + }
2640 +
2641 + // Export all the taxonomies
2642 + foreach ( $post_types as $post_type => $label ) {
2643 + $type_taxonomies = get_object_taxonomies( $post_type, 'objects' );
2644 + $taxonomies = wp_filter_object_list( $type_taxonomies, [
2645 + 'public' => true,
2646 + 'show_in_nav_menus' => true,
2647 + ] );
2648 +
2649 + foreach( $taxonomies as $slug => $object ){
1204 2650
2651 + $query_params = [
2652 + 'taxonomy' => $object->name,
2653 + 'hide_empty' => false,
2654 + ];
2655 + $terms = get_terms( $query_params );
2656 +
2657 + foreach($terms as $term){
2658 + $conf['taxonomies'][$term->term_id] = $term;
2659 + }
1205 2660 }
2661 +
2662 + }
1206 2663
1207 - // Write the config
2664 + // Write the config
2665 + if(!empty($conf)){
1208 2666 file_put_contents($theme_dir.'/pagelayer-data.conf', json_encode($conf, JSON_PRETTY_PRINT));
1209 -
1210 2667 }
1211 2668
1212 2669 // Are we to export any media ?
1213 2670 if(!empty($pagelayer->media_to_export)){
@@ -1214,8 +2671,10 @@
1214 2671 // TODO
1215 2672 //$done['media'] = $pagelayer->media_to_export;
1216 2673 }
1217 2674
2675 + do_action('pagelayer_template_export_completed');
2676 +
1218 2677 $done['success'] = __pl('temp_export_success');
1219 2678
1220 2679 // Output and die
1221 2680 pagelayer_json_output($done);
@@ -1221,44 +2680,212 @@
1221 2680 pagelayer_json_output($done);
1222 2681
1223 2682 }
1224 2683
1225 -// Export the template
1226 -add_action('wp_ajax_pagelayer_save_settings', 'pagelayer_save_settings');
1227 -function pagelayer_save_settings(){
2684 +add_action('wp_ajax_pagelayer_get_cat_checkboxes', 'pagelayer_get_cat_checkboxes');
2685 +function pagelayer_get_cat_checkboxes(){
1228 2686
1229 2687 // Some AJAX security
1230 2688 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
1231 2689
1232 - if(!current_user_can('edit_posts')){
1233 - $msg['error'] = __pl('current_user_can_not');
1234 - pagelayer_json_output($msg);
2690 + $ret = [];
2691 + $cat_name = '';
2692 +
2693 + if(!current_user_can('manage_categories')){
2694 + $ret['error'] = __pl('no_permission');
2695 + pagelayer_json_output($ret);
1235 2696 }
2697 +
2698 + if(empty($_POST['postid']) || !is_numeric($_POST['postid'])){
2699 + $ret['error'] = __pl('invalid_post_id');
2700 + pagelayer_json_output($ret);
2701 + }
1236 2702
1237 - $postID = (int) $_GET['postID'];
2703 + $post = (int) $_POST['postid'];
2704 + $post = get_post($post);
2705 +
2706 + if(empty($post) || is_wp_error($post)){
2707 + $ret['error'] = __pl('invalid_post_id');
2708 + pagelayer_json_output($ret);
2709 + }
2710 +
2711 + $cat_name = pagelayer_post_type_category($post->post_type);
2712 +
2713 + if(!empty($_POST['new_cat'])){
2714 + parse_str($_POST['new_cat'], $formdata);
2715 + $ret['new_cat_id'] = wp_insert_category([
2716 + 'taxonomy' => $cat_name,
2717 + 'cat_name' => $formdata['category_name'],
2718 + 'category_parent' => (($formdata['pagelayer_cat_parent'] == 0) ? '' : $formdata['pagelayer_cat_parent'])
2719 + ]);
2720 + }
2721 +
2722 + $ret += pagelayer_post_cats($post);
2723 +
2724 + pagelayer_json_output($ret);
2725 +
2726 +}
1238 2727
1239 - if(empty($postID)){
1240 - $msg['error'] = __pl('invalid_post_id');
1241 - pagelayer_json_output($msg);
2728 +add_action('wp_ajax_pagelayer_get_post_tags', 'pagelayer_get_post_tags');
2729 +function pagelayer_get_post_tags(){
2730 +
2731 + // Some AJAX security
2732 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2733 +
2734 + $ret = [];
2735 + $tag_name = '';
2736 +
2737 + if(!current_user_can('manage_categories')){
2738 + $ret['error'] = __pl('no_permission');
2739 + pagelayer_json_output($ret);
1242 2740 }
1243 2741
1244 - // Check if the post exists
2742 + if(empty($_POST['postid']) || !is_numeric($_POST['postid']) ){
2743 + pagelayer_json_output($ret);
2744 + }
1245 2745
1246 - if(!empty($_POST['post_title'])){
2746 + $post = (int) $_POST['postid'];
2747 + $post = get_post($post);
2748 +
2749 + if(empty($post) || is_wp_error($post)){
2750 + $ret['error'] = __pl('invalid_post_id');
2751 + pagelayer_json_output($ret);
2752 + }
2753 +
2754 + $tag_name = pagelayer_post_type_tag($post->post_type);
2755 +
2756 + if(!empty($_POST['new_tag'])){
2757 + $ret['tag_id'] = wp_insert_term($_POST['new_tag'], $tag_name);
2758 + $ret['tag_id'] = $ret['tag_id']['term_id'];
2759 + }
2760 +
2761 + $ret += pagelayer_post_tags($post);
2762 +
2763 + pagelayer_json_output($ret);
2764 +
2765 +}
2766 +
2767 +add_action('wp_ajax_pagelayer_custom_font', 'pagelayer_custom_font');
2768 +function pagelayer_custom_font(){
1247 2769
1248 - $post = array(
1249 - 'ID' => $postID,
1250 - 'post_title' => $_POST['post_title'],
1251 - );
2770 + // Some AJAX security
2771 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2772 +
2773 + $ret = [];
2774 +
2775 + if(empty($_POST['font_name'])){
2776 + pagelayer_json_output($ret);
2777 + }
2778 +
2779 + $name = preg_replace('/_plf$/is', '', pagelayer_optREQ('font_name'));
2780 + //echo $name;
2781 +
2782 + $args = [
2783 + 'post_type' => PAGELAYER_FONT_POST_TYPE,
2784 + 'status' => 'publish',
2785 + 'posts_per_page' => 1,
2786 + 'name' => $name
2787 + ];
2788 +
2789 + //var_dump($pagelayer->fonts);
2790 +
2791 + $query = get_posts($args);
2792 + //var_dump($query);
2793 +
2794 + if(empty($query)){
2795 + pagelayer_json_output($ret);
2796 + }
2797 +
2798 + $post = $query[0];
2799 + $meta_box_value = get_post_meta( $post->ID, 'pagelayer_font_link', true);
2800 + if(empty($meta_box_value)){
2801 + pagelayer_json_output($ret);
2802 + }
2803 +
2804 + $ret['style']= '<style id="'.$name.'_plf" >@font-face { font-family: "'.$name.'_plf"'.'; src: url("'.$meta_box_value.'"); font-weight: 100 200 300 400 500 600 700 800 900;}</style>';
2805 +
2806 + pagelayer_json_output($ret);
2807 +
2808 +}
1252 2809
1253 - // Update the post into the database
1254 - $ret = wp_update_post($post);
2810 +add_action('wp_ajax_pagelayer_trash_post', 'pagelayer_trash_post');
2811 +function pagelayer_trash_post(){
2812 +
2813 + // Some AJAX security
2814 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2815 +
2816 + $ret = [];
2817 +
2818 + if(empty($_POST['postid']) && !is_numeric($_POST['postid'])){
2819 + $ret = ['error' => __pl('invalid_post_id')];
2820 + pagelayer_json_output($ret);
2821 + }
1255 2822
1256 - if (is_wp_error($ret)) {
1257 - $msg['error'] = __pl('post_setting_update_err');
1258 - }else{
1259 - $msg['success'] = __pl('post_setting_update_success');
2823 + if(!current_user_can( 'delete_post', $_POST['postid'] )){
2824 + $ret = ['error' => __pl('no_permission')];
2825 + pagelayer_json_output($ret);
2826 + }
2827 +
2828 + $ret['url'] = admin_url('/edit.php?post_type=') .get_post_type($_POST['postid']);
2829 +
2830 + wp_trash_post($_POST['postid']);
2831 +
2832 + pagelayer_json_output($ret);
2833 +
2834 +}
2835 +
2836 +add_action('wp_ajax_pagelayer_infinite_posts', 'pagelayer_infinite_posts');
2837 +add_action('wp_ajax_nopriv_pagelayer_infinite_posts', 'pagelayer_infinite_posts');
2838 +function pagelayer_infinite_posts(){
2839 +
2840 + // Some AJAX security
2841 + check_ajax_referer('pagelayer_global', 'pagelayer_nonce');
2842 +
2843 + pagelayer_load_shortcodes();
2844 +
2845 + $tag = 'pl_posts';
2846 +
2847 + if(isset($_REQUEST['data']['tag']) && $_REQUEST['data']['tag'] == 'pl_archive_posts' ){
2848 + $tag = 'pl_archive_posts';
2849 + }
2850 +
2851 + $content = get_comment_delimited_block_content( 'pagelayer/'.$tag, $_REQUEST['data']['atts'] , '');
2852 + $wp['posts'] = pagelayer_the_content($content);
2853 + pagelayer_json_output( $wp );
2854 +}
2855 +
2856 +add_action('wp_ajax_pagelayer_pro_dismiss_expired_licenses', 'pagelayer_pro_dismiss_expired_licenses');
2857 +function pagelayer_pro_dismiss_expired_licenses(){
2858 + check_admin_referer('pagelayer_expiry_notice', 'security');
2859 +
2860 + if(!current_user_can('activate_plugins')){
2861 + wp_send_json_error(__('You do not have required access to do this action', 'pagelayer'));
2862 + }
2863 +
2864 + update_option('softaculous_expired_licenses', time());
2865 + wp_send_json_success();
2866 +}
2867 +
2868 +add_action('wp_ajax_pagelayer_close_update_notice', 'pagelayer_close_plugin_update_notice');
2869 +function pagelayer_close_plugin_update_notice(){
2870 + check_ajax_referer('pagelayer_promo_nonce', 'pagelayer_nonce');
2871 +
2872 + if(!current_user_can('manage_options')){
2873 + wp_send_json_error('You don\'t have privilege to close this notice!');
2874 + }
2875 +
2876 + $plugin_update_notice = get_option('softaculous_plugin_update_notice', []);
2877 + $available_update_list = get_site_transient('update_plugins');
2878 + $to_update_plugins = apply_filters('softaculous_plugin_update_notice', []);
2879 +
2880 + if(empty($available_update_list) || empty($available_update_list->response)){
2881 + return;
2882 + }
2883 +
2884 + foreach($to_update_plugins as $plugin_path => $plugin_name){
2885 + if(isset($available_update_list->response[$plugin_path])){
2886 + $plugin_update_notice[$plugin_path] = $available_update_list->response[$plugin_path]->new_version;
1260 2887 }
1261 2888 }
1262 2889
1263 - pagelayer_json_output($msg);
1264 -}
2890 + update_option('softaculous_plugin_update_notice', $plugin_update_notice);
2891 +}