PluginProbe
Page Builder: Pagelayer – Drag and Drop website builder / 2.2.1
Page Builder: Pagelayer – Drag and Drop website builder v2.2.1
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 1.0.5 All 129 releases
← All changes | main/ajax.php +1921 -362 1.0.22.2.1 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,62 +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 + );
144 732
145 733 // Any properties ?
146 - if(!empty($_REQUEST['page_props'])){
734 + $allowed = ['post_title', 'post_name', 'post_excerpt', 'post_status', 'post_password', 'post_date', 'post_parent', 'menu_order'];
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 + }
147 755
148 - $allowed = ['post_title', 'post_name', 'post_excerpt', 'post_status'];
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'){
149 782
150 - foreach($allowed as $k){
151 - if(!empty($_REQUEST['page_props'][$k])){
152 - $post[$k] = $_REQUEST['page_props'][$k];
153 - }
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);
154 787 }
155 788
156 - $_REQUEST['page_props']['featured_image'] = (int) $_REQUEST['page_props']['featured_image'];
157 - if(!empty($_REQUEST['page_props']['featured_image'])){
158 - set_post_thumbnail($postID, $_REQUEST['page_props']['featured_image']);
159 - }else{
160 - delete_post_thumbnail($postID);
789 + // Allowed to publish posts ?
790 + if($_post->post_type == 'post' && !current_user_can('publish_posts')){
791 + $post['post_status'] = 'pending';
161 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'] );
162 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 + }
163 810 }
164 -
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 +
165 863 // Apply a filter
166 864 $post = apply_filters('pagelayer_save_content', $post);
167 865
168 866 // Update the post into the database
169 - 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));
170 871
171 - if (is_wp_error($postID)) {
172 - $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);
173 875 }else{
174 - $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');
175 901 }
176 902
177 903 }else{
178 - $msg['error'] = __pl('post_update_err');
904 + $msg['error'] = __pl('post_update_err');
179 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 +}
180 937
181 - 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){
182 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 + }
183 1033 }
184 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 +
185 1058 // Shortcodes Widget Handler
186 1059 add_action('wp_ajax_pagelayer_do_shortcodes', 'pagelayer_do_shortcodes');
187 1060 function pagelayer_do_shortcodes(){
188 1061
@@ -188,8 +1061,13 @@
188 1061
189 1062 // Some AJAX security
190 1063 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
191 1064
1065 + if(!current_user_can('edit_posts')){// TODO : WooCommerce
1066 + $ret['error'][] = __pl('no_permission');
1067 + pagelayer_json_output($ret);
1068 + }
1069 +
192 1070 $data = '';
193 1071 if(isset($_REQUEST['shortcode_data'])){
194 1072 $data = stripslashes($_REQUEST['shortcode_data']);
195 1073 }
@@ -196,12 +1074,12 @@
196 1074
197 1075 // Load shortcodes
198 1076 pagelayer_load_shortcodes();
199 1077
200 - $data = do_shortcode($data);
1078 + $data = pagelayer_the_content($data);
201 1079
202 1080 // Create the HTML object
203 - $node = pQuery::parseStr($data);
1081 + $node = pagelayerQuery::parseStr($data);
204 1082 $node->query('.pagelayer-ele')->removeClass('pagelayer-ele');
205 1083 echo $node->html();
206 1084
207 1085 wp_die();
@@ -220,8 +1098,11 @@
220 1098
221 1099 // Load shortcodes
222 1100 pagelayer_load_shortcodes();
223 1101
1102 + // Load font options
1103 + pagelayer_load_font_options();
1104 +
224 1105 // Pagelayer Template Loading Mechanism
225 1106 include_once(PAGELAYER_DIR.'/js/givejs.php');
226 1107
227 1108 exit();
@@ -227,18 +1108,57 @@
227 1108 exit();
228 1109
229 1110 }
230 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 +
231 1129 // Shortcodes Widget Handler
232 1130 add_action('wp_ajax_pagelayer_get_section_shortcodes', 'pagelayer_get_section_shortcodes');
233 1131 function pagelayer_get_section_shortcodes(){
234 -
1132 +
1133 + global $pagelayer;
1134 +
235 1135 // Some AJAX security
236 1136 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
237 1137
1138 + if(!current_user_can('edit_posts')){
1139 + $ret['error'][] = __pl('no_permission');
1140 + pagelayer_json_output($ret);
1141 + }
1142 +
238 1143 $data = '';
239 1144 if(isset($_REQUEST['pagelayer_section_id'])){
240 - $data = json_decode(file_get_contents(PAGELAYER_API.'/library.php?give_id='.$_REQUEST['pagelayer_section_id']), true);
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 + }
241 1161 }
242 1162
243 1163 if(isset($_REQUEST['postID'])){
244 1164 $post_id = (int) $_REQUEST['postID'];
@@ -247,17 +1167,47 @@
247 1167 $post = get_post( $post_id );
248 1168 // Need to make the reviews post global
249 1169 if ( !empty( $post ) ) {
250 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 + ]);
251 1176 }
252 1177 }
253 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 + }
254 1204
255 1205 // Load shortcodes
256 1206 pagelayer_load_shortcodes();
257 1207
258 1208 if(!empty($data['code'])){
259 - $data['code'] = do_shortcode($data['code']);
1209 + $data['code'] = pagelayer_the_content($data['code'], true);
260 1210 }
261 1211
262 1212 pagelayer_json_output($data);
263 1213
@@ -262,8 +1212,83 @@
262 1212 pagelayer_json_output($data);
263 1213
264 1214 }
265 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 +
266 1291 // Get the Site Title
267 1292 add_action('wp_ajax_pagelayer_fetch_site_title', 'pagelayer_fetch_site_title');
268 1293 function pagelayer_fetch_site_title(){
269 1294
@@ -282,14 +1307,16 @@
282 1307 // Some AJAX security
283 1308 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
284 1309
285 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 + }
286 1316
287 1317 update_option('blogname', $site_title);
288 -
289 - $wpdb->query("UPDATE `sm_sitemeta`
290 - SET meta_value = '".$site_title."'
291 - WHERE meta_key = 'site_name'");
1318 +
292 1319 wp_die();
293 1320 }
294 1321
295 1322 // Show the SideBars
@@ -330,13 +1357,32 @@
330 1357 // Some AJAX security
331 1358 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
332 1359
333 1360 if(isset($_POST['nav_list'])){
334 - 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([
335 1379 'menu' => wp_get_nav_menu_object($_POST['nav_list']),
336 1380 'menu_id' => $_POST["nav_list"],
337 1381 'menu_class' => 'pagelayer-wp_menu-ul',
1382 + 'walker' => new Pagelayer_Walker_Nav_Menu(),
338 1383 //'theme_location' => 'primary',
1384 + 'echo' => true,
339 1385 ]);
340 1386 }
341 1387
342 1388 wp_die();
@@ -347,16 +1393,25 @@
347 1393 function pagelayer_create_post_autosave(){
348 1394
349 1395 // Some AJAX security
350 1396 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
351 -
352 - $postID = (int) $_GET['postID'];
353 - $post_revisions = array();
354 1397
1398 + $ret = array();
1399 + $postID = (int) $_GET['postID'];
355 1400 $content = $_REQUEST['pagelayer_post_content'];
356 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 +
357 1412 if(empty($postID)){
358 - $post_revisions['error'] = __pl('invalid_post_id');
1413 + $ret['error'] = __pl('invalid_post_id');
359 1414 }else{
360 1415
361 1416 $post = array(
362 1417 'post_ID' => $postID,
@@ -362,14 +1417,14 @@
362 1417 'post_ID' => $postID,
363 1418 'post_content' => $content,
364 1419 );
365 1420
366 - $post_revisions['id'] = wp_create_post_autosave($post);
1421 + $ret['id'] = wp_create_post_autosave($post);
367 1422 }
368 1423
369 - $post_revisions['url'] = get_preview_post_link($postID);
1424 + $ret['url'] = get_preview_post_link($postID);
370 1425
371 - pagelayer_json_output($post_revisions);
1426 + pagelayer_json_output($ret);
372 1427
373 1428 }
374 1429
375 1430 // Get post revision
@@ -378,22 +1433,28 @@
378 1433
379 1434 // Some AJAX security
380 1435 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
381 1436
1437 + $ret = array();
382 1438 $postID = (int) $_GET['postID'];
383 - $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 + }
384 1445
385 1446 if(empty($postID)){
386 - $post_revisions['error'] = __pl('invalid_post_id');
1447 + $ret['error'] = __pl('invalid_post_id');
387 1448 }else{
388 - $post_revisions = pagelayer_get_post_revision_by_id($postID);
1449 + $ret = pagelayer_get_post_revision_by_id($postID);
389 1450 }
390 1451
391 - pagelayer_json_output($post_revisions);
1452 + pagelayer_json_output($ret);
392 1453
393 1454 }
394 1455
395 -// Get post revision
1456 +// Apply post revision
396 1457 add_action('wp_ajax_pagelayer_apply_revision', 'pagelayer_apply_revision');
397 1458 function pagelayer_apply_revision(){
398 1459
399 1460 // Some AJAX security
@@ -399,39 +1460,55 @@
399 1460 // Some AJAX security
400 1461 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
401 1462
402 1463 $revisionID = (int) $_REQUEST['revisionID'];
403 - $post_data = array();
1464 + $parID = wp_get_post_parent_id($revisionID);
1465 + $ret = array();
404 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 +
405 1477 if(empty($revisionID)){
406 - $post_data['error'] = __pl('invalid_post_id');
1478 + $ret['error'] = __pl('invalid_post_id');
407 1479 }else{
408 1480
409 1481 $post = get_post( $revisionID );
410 1482
411 1483 if ( empty( $post ) ) {
412 - $post_data['error'] = __pl('invalid_revision');
413 - pagelayer_json_output($post_data);
1484 + $ret['error'] = __pl('invalid_revision');
1485 + pagelayer_json_output($ret);
414 1486 }
415 1487
416 1488 // Need to make the reviews post global
417 1489 $GLOBALS['post'] = $post;
1490 + $GLOBALS['wp_query'] = new WP_Query([
1491 + 'post_type' => $GLOBALS['post']->post_type,
1492 + 'post__in' => array($parID),
1493 + ]);
418 1494
419 1495 // Need to reload the shortcodes
420 1496 pagelayer_load_shortcodes();
421 1497
422 - $post_data['content'] = do_shortcode($post->post_content);
1498 + $ret['id'] = $revisionID;
1499 + $ret['content'] = pagelayer_the_content($post->post_content, true);
423 1500
424 - if (is_wp_error($postID)) {
425 - $post_data['error'] = __pl('rev_load_error');
1501 + if(is_wp_error($post)) {
1502 + $ret['error'] = __pl('rev_load_error');
426 1503 }else{
427 - $post_data['success'] = __pl('rev_load_success');
1504 + $ret['success'] = __pl('rev_load_success');
428 1505 }
429 1506
430 1507 wp_reset_postdata();
431 1508 }
432 1509
433 - pagelayer_json_output($post_data);
1510 + pagelayer_json_output($ret);
434 1511
435 1512 }
436 1513
437 1514 // Get post revision
@@ -441,40 +1518,47 @@
441 1518 // Some AJAX security
442 1519 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
443 1520
444 1521 $revisionID = (int) $_REQUEST['revisionID'];
1522 + $parID = wp_get_post_parent_id($revisionID);
1523 + $ret = array();
445 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 +
446 1531 if(empty($revisionID)){
447 - $post_data['error'] = __pl('invalid_post_id');
1532 + $ret['error'] = __pl('invalid_post_id');
448 1533 }else{
449 1534
450 1535 $revision = get_post( $revisionID );
451 1536
452 1537 if ( empty( $revision ) ) {
453 - $post_data['error'] = __pl('invalid_revision');
1538 + $ret['error'] = __pl('invalid_revision');
454 1539 }else{
455 1540
456 - if ( ! current_user_can( 'delete_post', $revision->ID ) ) {
457 - $post_data['error'] = __pl('access_denied');
458 - pagelayer_json_output($post_data);
459 - return false;
1541 + if ( ! current_user_can( 'delete_post', $parID ) ) {
1542 + $ret['error'] = __pl('access_denied');
1543 + pagelayer_json_output($ret);
460 1544 }
461 1545
462 1546 $deleted = wp_delete_post_revision( $revision->ID );
463 1547
464 1548 if ( ! $deleted || is_wp_error( $deleted ) ) {
465 - $post_data['error'] = __pl('delete_rev_error');
1549 + $ret['error'] = __pl('delete_rev_error');
466 1550 }else{
467 - $post_data['success'] = __pl('delete_rev_success');
1551 + $ret['success'] = __pl('delete_rev_success');
468 1552 }
469 1553 }
470 1554 }
471 1555
472 - pagelayer_json_output($post_data);
1556 + pagelayer_json_output($ret);
473 1557
474 1558 }
475 1559
476 -// Get post revision
1560 +// Get post navigation
477 1561 add_action('wp_ajax_pagelayer_post_nav', 'pagelayer_post_nav');
478 1562 function pagelayer_post_nav() {
479 1563
480 1564 // Some AJAX security
@@ -522,9 +1606,9 @@
522 1606 pagelayer_json_output($el);
523 1607
524 1608 }
525 1609
526 -// Get post comment template
1610 +// Get post comment template
527 1611 add_action('wp_ajax_pagelayer_post_comment', 'pagelayer_post_comment');
528 1612 function pagelayer_post_comment() {
529 1613 global $post;
530 1614
@@ -537,15 +1621,16 @@
537 1621
538 1622 $GLOBALS['post'] = get_post($_REQUEST['postID']);
539 1623 $GLOBALS['withcomments'] = true;
540 1624
541 - if ( comments_open() || get_comments_number() ) {
542 - echo '<div class="pagelayer-comments-template">'.comments_template().'</div>';
543 - }else{
544 - echo '<div class="pagelayer-comments-close">
545 - <h2>Comments are closed!</h2>
546 - </div>';
547 - }
1625 + // Load shortcodes
1626 + pagelayer_load_shortcodes();
1627 +
1628 + $el = [];
1629 + pagelayer_sc_post_comment($el);
1630 +
1631 + echo $el['atts']['post_comment'];
1632 +
548 1633 wp_die();
549 1634
550 1635 }
551 1636
@@ -564,80 +1649,12 @@
564 1649 $el['atts'] = $_REQUEST['el'];
565 1650
566 1651 $GLOBALS['post'] = get_post($_REQUEST['postID']);
567 1652
568 - $post_info_content ='';
569 - $link ='';
570 - $info_content ='';
571 - $avatar_url ='';
1653 + // Load shortcodes
1654 + pagelayer_load_shortcodes();
572 1655
573 - switch($el['atts']['type']){
574 - case 'author':
575 -
576 - $link = get_author_posts_url( get_the_author_meta( 'ID' ) );
577 - $avatar_url = get_avatar_url( get_the_author_meta( 'ID' ), 96 );
578 - $post_info_content = get_the_author_meta( 'display_name', $post->post_author );
579 - break;
580 -
581 - case 'date':
582 -
583 - $format = [
584 - 'default' => 'F j, Y',
585 - '0' => 'F j, Y',
586 - '1' => 'Y-m-d',
587 - '2' => 'm/d/Y',
588 - '3' => 'd/m/Y',
589 - 'custom' => empty( $el['atts']['date_format_custom'] ) ? 'F j, Y' : $el['atts']['date_format_custom'],
590 - ];
591 -
592 - $post_info_content = get_the_time( $format[ $el['atts']['date_format'] ] );
593 - $link = get_day_link( get_post_time( 'Y' ), get_post_time( 'm' ), get_post_time( 'j' ) );
594 -
595 - break;
596 -
597 - case 'time':
598 -
599 - $format = [
600 - 'default' => 'g:i a',
601 - '0' => 'g:i a',
602 - '1' => 'g:i A',
603 - '2' => 'H:i',
604 - 'custom' => empty( $el['atts']['time_format_custom'] ) ? 'F j, Y' : $el['atts']['time_format_custom'],
605 - ];
606 - $post_info_content = get_the_time( $format[ $el['atts']['time_format'] ] );
607 -
608 - break;
609 -
610 - case 'comments':
611 -
612 - if (comments_open()) {
613 - $post_info_content = (int) get_comments_number();
614 - $link = get_comments_link();
615 - }
616 -
617 - break;
618 -
619 - case 'terms':
620 -
621 - $taxonomy = $el['atts']['taxonomy'];
622 - $terms = wp_get_post_terms( get_the_ID(), $taxonomy );
623 - foreach ( $terms as $term ) {
624 - $post_info_content .= ' <a if-ext="{{info_link}}" href="'. get_term_link( $term ) .'" class="pagelayer-post-info-list-link"> '. $term->name .' </a>';
625 - }
626 -
627 - break;
628 -
629 - case 'custom':
630 -
631 - $post_info_content = $el['atts']['type_custom'];
632 - $link = $el['atts']['info_custom_link'];
633 -
634 - break;
635 - }
636 -
637 - $el['atts']['post_info_content'] = $post_info_content;
638 - $el['atts']['avatar_url'] = $avatar_url;
639 - $el['atts']['link'] = $link;
1656 + pagelayer_sc_post_info_list($el);
640 1657
641 1658 pagelayer_json_output($el['atts']);
642 1659
643 1660 }
@@ -644,18 +1661,22 @@
644 1661
645 1662 // Get the Featured Image
646 1663 add_action('wp_ajax_pagelayer_fetch_featured_img', 'pagelayer_fetch_featured_img');
647 1664 function pagelayer_fetch_featured_img(){
648 -
1665 +
649 1666 // Some AJAX security
650 1667 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
651 1668
652 - if($_POST['size']){
653 - echo get_the_post_thumbnail_url($_POST['post_id'], $_POST['size']);
654 - }else{
655 - 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);
656 1674 }
657 - wp_die();
1675 +
1676 + $img = pagelayer_image($id);
1677 + pagelayer_json_output($img);
1678 +
658 1679 }
659 1680
660 1681 // Get the postfolio posts
661 1682 add_action('wp_ajax_pagelayer_fetch_posts', 'pagelayer_fetch_posts');
@@ -663,10 +1684,17 @@
663 1684
664 1685 // Some AJAX security
665 1686 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
666 1687
667 - 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 + }
668 1693
1694 + $sanitized_post = pagelayer_sanitize_posts_data($_POST);
1695 + echo pagelayer_widget_posts($sanitized_post);
1696 +
669 1697 wp_die();
670 1698 }
671 1699
672 1700 // Get the Posts
@@ -675,12 +1703,19 @@
675 1703
676 1704 // Some AJAX security
677 1705 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
678 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 +
679 1713 // Load shortcodes
680 1714 pagelayer_load_shortcodes();
681 1715
682 - echo pagelayer_posts($_POST);
1716 + $sanitized_post = pagelayer_sanitize_posts_data($_POST, false);
1717 + echo pagelayer_posts($sanitized_post);
683 1718 wp_die();
684 1719 }
685 1720
686 1721 // Get the Posts
@@ -690,10 +1725,10 @@
690 1725 // Some AJAX security
691 1726 check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
692 1727
693 1728 // Set excerpt length
694 - if($_POST['exc_length']){
695 - $exc_length = (int) $params['exc_length'];
1729 + if(!empty($_POST['atts']['exc_length'])){
1730 + $exc_length = (int) $_POST['atts']['exc_length'];
696 1731 add_filter( 'excerpt_length', function($length) use($exc_length){
697 1732 return $exc_length;
698 1733 }, 999 );
699 1734 }
@@ -700,9 +1735,21 @@
700 1735
701 1736 // Load shortcodes
702 1737 pagelayer_load_shortcodes();
703 1738
704 - 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);
705 1752 wp_die();
706 1753 }
707 1754
708 1755 // Handle Contact Form Data
@@ -708,27 +1755,181 @@
708 1755 // Handle Contact Form Data
709 1756 add_action('wp_ajax_pagelayer_contact_submit', 'pagelayer_contact_submit');
710 1757 add_action('wp_ajax_nopriv_pagelayer_contact_submit', 'pagelayer_contact_submit' );
711 1758 function pagelayer_contact_submit(){
712 -
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 +
713 1785 $to_mail = get_option('pagelayer_cf_to_email');
1786 + $from_mail = get_option('pagelayer_cf_from_email');
714 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']);
715 1796
716 - $fdata = $_POST['form_data'];
717 - 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 + }
718 1809
719 - // 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
720 1872 foreach($formdata as $k => $i){
721 - $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;
722 1893 }
723 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 +
724 1923 // Send the email
725 - $r = wp_mail( $to_mail, $subject, $data );
1924 + if(!empty($to_mail)){
1925 + $r = wp_mail( $to_mail, $subject, $body, $headers );
1926 + }
726 1927
727 1928 if($r == TRUE){
728 - $wp['success'] = get_option( 'pagelayer_cf_success' );
1929 + $wp['success'] = pagelayer_get_option( 'pagelayer_cf_success' );
729 1930 }else{
730 - $wp['failed'] = get_option( 'pagelayer_cf_failed' );
1931 + $wp['failed'] = pagelayer_get_option( 'pagelayer_cf_failed' );
731 1932 }
732 1933
733 1934 pagelayer_json_output($wp);
734 1935
@@ -733,36 +1934,21 @@
733 1934 pagelayer_json_output($wp);
734 1935
735 1936 }
736 1937
737 -// Fetch Google reCaptcha Key
738 -add_action('wp_ajax_pagelayer_fetch_grecaptcha_key', 'pagelayer_fetch_grecaptcha_key');
739 -function pagelayer_fetch_grecaptcha_key(){
740 -
741 - $data['key'] = get_option('pagelayer_google_captcha');
742 -
743 - pagelayer_json_output($data);
744 -
745 -}
746 -
747 1938 // Handle Login Submit
748 1939 add_action('wp_ajax_pagelayer_login_submit', 'pagelayer_login_submit');
749 1940 add_action('wp_ajax_nopriv_pagelayer_login_submit', 'pagelayer_login_submit');
750 1941 function pagelayer_login_submit(){
1942 +
1943 + // Some AJAX security
1944 + check_ajax_referer('pagelayer_global', 'pagelayer_nonce');
751 1945
752 - $fdata = $_POST['form_data'];
753 - parse_str($fdata, $formdata);
754 -
755 1946 $creds = array();
756 - $creds['user_login'] = $formdata['username'];
757 - $creds['user_password'] = $formdata['password'];
758 - $creds['remember'] = $formdata['remember_me'];
1947 + $creds['user_login'] = $_REQUEST['username'];
1948 + $creds['user_password'] = $_REQUEST['password'];
1949 + $creds['remember'] = $_REQUEST['remember_me'];
759 1950
760 - // If After logout URL, then save
761 - if(!empty($formdata['logout_url'])){
762 - update_user_option('pagelayer_logout_url', $formdata['logout_url']);
763 - }
764 -
765 1951 // Login the user
766 1952 $user = wp_signon( $creds, false );
767 1953
768 1954 if ( is_wp_error($user) ){
@@ -767,9 +1953,15 @@
767 1953
768 1954 if ( is_wp_error($user) ){
769 1955 $data['error'] = $user->get_error_message();
770 1956 }else{
771 - $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']));
772 1964 $data['error'] = '';
773 1965 }
774 1966
775 1967 pagelayer_json_output($data);
@@ -775,33 +1967,27 @@
775 1967 pagelayer_json_output($data);
776 1968
777 1969 }
778 1970
779 -// Handle Logout Redirect here
780 -add_action('wp_logout', 'pagelayer_after_logout');
781 -function pagelayer_after_logout(){
782 -
783 - $url = get_user_option('pagelayer_logout_url');
784 -
785 - // We will redirect if we have the given item set.
786 - if(!empty($url)){
787 - wp_redirect( $url );
788 - exit();
789 - }
790 -
791 -}
792 -
793 1971 // Get Page List for SiteMap
794 1972 add_action('wp_ajax_pagelayer_get_pages_list', 'pagelayer_get_pages_list');
795 -add_action('wp_ajax_nopriv_pagelayer_get_pages_list', 'pagelayer_get_pages_list');
796 1973 function pagelayer_get_pages_list(){
1974 +
1975 + // Some AJAX security
1976 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
797 1977
1978 + if(!current_user_can('edit_posts')){
1979 + echo __pl('no_permission');
1980 + wp_die();
1981 + }
1982 +
798 1983 $args = array(
799 - 'post_type' => $_POST['type'],
800 - 'orderby' => $_POST['post_order'],
801 - 'order' => $_POST['order'],
802 - 'hierarchical' => (empty($_POST['hier']) || $_POST['hier'] == null ? '' : $_POST['hier']),
803 - '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,
804 1990 );
805 1991
806 1992 $option = '<ul>';
807 1993 $pages = new WP_Query($args);
@@ -810,12 +1996,11 @@
810 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>';
811 1997 }
812 1998 $option .= '</ul>';
813 1999
814 -
815 2000 echo $option;
816 2001
817 - wp_die();
2002 + wp_die();
818 2003 }
819 2004
820 2005 // Get the data for template
821 2006 add_action('wp_ajax_pagelayer_search_ids', 'pagelayer_search_ids');
@@ -821,9 +2006,9 @@
821 2006 add_action('wp_ajax_pagelayer_search_ids', 'pagelayer_search_ids');
822 2007 function pagelayer_search_ids() {
823 2008
824 2009 // Some AJAX security
825 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2010 + check_ajax_referer('pagelayer_builder', 'pagelayer_nonce');
826 2011
827 2012 if ( empty( $_POST['filter_type'] ) || empty( $_POST['search'] ) ) {
828 2013 wp_die();
829 2014 }
@@ -867,9 +2052,9 @@
867 2052 break;
868 2053
869 2054 case 'author':
870 2055 $query_params = [
871 - 'who' => 'authors',
2056 + 'capability' => array( 'edit_posts' ),
872 2057 'fields' => [
873 2058 'ID',
874 2059 'display_name',
875 2060 ],
@@ -877,9 +2062,15 @@
877 2062 'search_columns' => [
878 2063 'user_login',
879 2064 'user_nicename',
880 2065 ],
881 - ];
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 + }
882 2073
883 2074 $user_query = new \WP_User_Query( $query_params );
884 2075
885 2076 foreach ( $user_query->get_results() as $author ) {
@@ -885,8 +2076,23 @@
885 2076 foreach ( $user_query->get_results() as $author ) {
886 2077 $sel_opt .= '<span class="pagelayer-temp-search-sel-span" value="'. $author->ID .'">'. $author->display_name .'</span>';
887 2078 }
888 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 +
889 2095 default:
890 2096 $sel_opt = 'Result Not Found';
891 2097 }
892 2098
@@ -898,23 +2104,33 @@
898 2104
899 2105 wp_die();
900 2106 }
901 2107
902 -
903 2108 // Save the post data from pagelayer setting page
904 2109 add_action('wp_ajax_pagelayer_save_template', 'pagelayer_save_template');
905 2110 function pagelayer_save_template() {
906 2111
907 2112 // Some AJAX security
908 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2113 + check_ajax_referer('pagelayer_builder', 'pagelayer_nonce');
909 2114
910 2115 $done = [];
911 2116
912 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 + }
913 2124
914 2125 // We need to create the post
915 2126 if(empty($post_id)){
916 2127
2128 + if (!current_user_can('edit_posts')) {
2129 + $done['error'] = __pl('access_denied');
2130 + pagelayer_json_output($done);
2131 + }
2132 +
917 2133 // Get the template type
918 2134 if(empty($_POST['pagelayer_template_type'])){
919 2135 $done['error'] = __pl('temp_error_type');
920 2136 pagelayer_json_output($done);
@@ -984,95 +2200,8 @@
984 2200 pagelayer_json_output($done);
985 2201
986 2202 }
987 2203
988 -// Product Images Handler
989 -add_action('wp_ajax_pagelayer_product_images', 'pagelayer_product_images');
990 -function pagelayer_product_images(){
991 - global $product;
992 -
993 - // Some AJAX security
994 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
995 -
996 - if ( !isset($_REQUEST['postID']) ) {
997 - return;
998 - }
999 -
1000 - $product = wc_get_product($_REQUEST['postID']);
1001 -
1002 - if ( empty( $product ) ) {
1003 - return ;
1004 - }
1005 -
1006 - if ( isset($_POST['sale_flash']) ) {
1007 - wc_get_template( 'loop/sale-flash.php' );
1008 - }
1009 - wc_get_template( 'single-product/product-image.php' );
1010 -
1011 - // On render widget from Editor - trigger the init manually.
1012 - echo '
1013 - <script>
1014 - jQuery(".woocommerce-product-gallery").each( function() {
1015 - jQuery(this).wc_product_gallery();
1016 - } );
1017 - </script>
1018 - ';
1019 -
1020 - wp_die();
1021 -}
1022 -
1023 -// Related Products Handler
1024 -add_action('wp_ajax_pagelayer_product_related', 'pagelayer_product_related');
1025 -function pagelayer_product_related(){
1026 - global $product;
1027 -
1028 - // Some AJAX security
1029 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
1030 -
1031 - if ( !isset($_REQUEST['postID']) ) {
1032 - return;
1033 - }
1034 -
1035 - $product = wc_get_product($_REQUEST['postID']);
1036 -
1037 - if ( empty( $product ) ) {
1038 - return ;
1039 - }
1040 -
1041 - $args = $_REQUEST['pagelayer_args'];
1042 -
1043 - if(function_exists( 'woocommerce_related_products' )){
1044 - woocommerce_related_products($args);
1045 - }
1046 -
1047 - wp_die();
1048 -}
1049 -
1050 -// Upsell Products Handler
1051 -add_action('wp_ajax_pagelayer_product_upsell', 'pagelayer_product_upsell');
1052 -function pagelayer_product_upsell(){
1053 - global $product;
1054 -
1055 - // Some AJAX security
1056 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
1057 -
1058 - if ( !isset($_REQUEST['postID']) ) {
1059 - return;
1060 - }
1061 -
1062 - $product = wc_get_product($_REQUEST['postID']);
1063 -
1064 - if ( empty( $product ) ) {
1065 - return ;
1066 - }
1067 -
1068 - if(function_exists( 'woocommerce_related_products' )){
1069 - woocommerce_upsell_display( $_REQUEST['limit'], $_REQUEST['columns'], $_REQUEST['orderby'], $_REQUEST['order'] );
1070 - }
1071 -
1072 - wp_die();
1073 -}
1074 -
1075 2204 // Products Categories Handler
1076 2205 add_action('wp_ajax_pagelayer_product_categories', 'pagelayer_product_categories');
1077 2206 function pagelayer_product_categories(){
1078 2207
@@ -1096,54 +2225,14 @@
1096 2225
1097 2226 $shortcode = '[product_categories '. $attributes .']';
1098 2227
1099 2228 // do_shortcode the shortcode
1100 - echo do_shortcode($shortcode);
2229 + echo pagelayer_the_content($shortcode);
1101 2230
1102 2231 wp_die();
1103 2232 }
1104 2233
1105 2234 // Products Categories Handler
1106 -add_action('wp_ajax_pagelayer_product_archives', 'pagelayer_product_archives');
1107 -function pagelayer_product_archives(){
1108 -
1109 - // Some AJAX security
1110 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
1111 -
1112 - if ( WC()->session ) {
1113 - wc_print_notices();
1114 - }
1115 -
1116 - $atts['paginate'] = true;
1117 - $atts['cache'] = false;
1118 - $no_found = $_POST['atts']['no_found'];
1119 -
1120 - if( empty($_POST['atts']['allow_order']) ){
1121 - remove_action( 'woocommerce_before_shop_loop', 'woocommerce_catalog_ordering', 30 );
1122 - }
1123 - if( empty($_POST['atts']['show_result']) ){
1124 - remove_action( 'woocommerce_before_shop_loop', 'woocommerce_result_count', 20 );
1125 - }
1126 -
1127 - $type = 'pagelayer_current_query';
1128 -
1129 - // Set the current query
1130 - add_action( 'woocommerce_shortcode_products_query', 'pagelayer_shortcode_current_query', 10, 10);
1131 -
1132 - // If product not found
1133 - add_action( "woocommerce_shortcode_{$type}_loop_no_results", function ($attributes) use ($no_found){
1134 - echo '<div class="pagelayer-product-no-found">'.$no_found.'</div>';
1135 - } );
1136 -
1137 - // Get the products list
1138 - $shortcode = new WC_Shortcode_Products( $atts, $type );
1139 -
1140 - echo $shortcode->get_content();
1141 -
1142 - wp_die();
1143 -}
1144 -
1145 -// Products Categories Handler
1146 2235 add_action('wp_ajax_pagelayer_products_ajax', 'pagelayer_products_ajax');
1147 2236 function pagelayer_products_ajax(){
1148 2237
1149 2238 // Some AJAX security
@@ -1200,9 +2289,9 @@
1200 2289 }
1201 2290
1202 2291 $shortcode = '['.$type.' '. $attributes .']';
1203 2292
1204 - $content = do_shortcode($shortcode);
2293 + $content = pagelayer_the_content($shortcode);
1205 2294
1206 2295 // If product not found
1207 2296 if('<div class="woocommerce columns-'.$_POST['atts']['columns'] .' "></div>' == $content){
1208 2297 $content = '<div class="pagelayer-product-no-found">'. $no_found .'</div>';
@@ -1212,13 +2301,70 @@
1212 2301
1213 2302 wp_die();
1214 2303 }
1215 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 +
1216 2355 // Get Taxamony List for SiteMap
1217 2356 add_action('wp_ajax_pagelayer_get_taxonomy_list', 'pagelayer_get_taxonomy_list');
1218 -add_action('wp_ajax_nopriv_pagelayer_get_taxonomy_list', 'pagelayer_get_taxonomy_list');
1219 2357 function pagelayer_get_taxonomy_list(){
1220 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 +
1221 2367 $args = array(
1222 2368 'title_li' => 0,
1223 2369 'orderby' => $_POST['post_order'],
1224 2370 'order' => $_POST['order'],
@@ -1248,12 +2394,17 @@
1248 2394
1249 2395 global $pagelayer;
1250 2396
1251 2397 // Some AJAX security
1252 - check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2398 + check_ajax_referer('pagelayer_builder', 'pagelayer_nonce');
1253 2399
1254 2400 $done = [];
1255 2401
2402 + if(!current_user_can('edit_theme_options')){
2403 + $done['error'][] = __pl('no_permission');
2404 + pagelayer_json_output($done);
2405 + }
2406 +
1256 2407 // Load the templates
1257 2408 pagelayer_builder_load_templates();
1258 2409
1259 2410 if(empty($pagelayer->templates)){
@@ -1260,8 +2411,11 @@
1260 2411 $done['error'] = __pl('temp_export_empty');
1261 2412 pagelayer_json_output($done);
1262 2413 }
1263 2414
2415 + // Load Shortcodes
2416 + pagelayer_load_shortcodes();
2417 +
1264 2418 // Get the active theme
1265 2419 $theme_dir = get_stylesheet_directory();
1266 2420 $conf = [];
1267 2421
@@ -1276,9 +2430,18 @@
1276 2430 continue;
1277 2431 }
1278 2432 }
1279 2433
1280 - 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));
1281 2444 $conf[$v->post_name] = [
1282 2445 'type' => get_post_meta($v->ID, 'pagelayer_template_type', true),
1283 2446 'title' => $v->post_title,
1284 2447 'conditions' => get_post_meta($v->ID, 'pagelayer_template_conditions', true),
@@ -1286,37 +2449,222 @@
1286 2449 }
1287 2450
1288 2451 // Write the config
1289 2452 file_put_contents($theme_dir.'/pagelayer.conf', json_encode($conf, JSON_PRETTY_PRINT));
2453 +
2454 + $conf = [];
1290 2455
1291 - // Any pages to export for users ?
1292 - if(!empty($_POST['pages'])){
2456 + // Load the other posts
2457 + foreach($pagelayer->settings['post_types'] as $type){
1293 2458
1294 - mkdir($theme_dir.'/data/');
1295 - 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;
1296 2480
1297 - $conf = [];
2481 + // Write the files
2482 + foreach($posts as $k => $v){
1298 2483
1299 - // Load the pages
1300 - $pages_query = new WP_Query(['post_type' => 'page', 'status' => 'publish']);
1301 - $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 + }
1302 2544
1303 - // Write the files
1304 - 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){
1305 2553
1306 - 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;
1307 2559 continue;
1308 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);
1309 2588
1310 - file_put_contents($theme_dir.'/data/page/'.$v->post_name, pagelayer_export_content($v->post_content));
1311 - unset($v->post_content);
1312 - $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 ){
1313 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 + }
1314 2660 }
2661 +
2662 + }
1315 2663
1316 - // Write the config
2664 + // Write the config
2665 + if(!empty($conf)){
1317 2666 file_put_contents($theme_dir.'/pagelayer-data.conf', json_encode($conf, JSON_PRETTY_PRINT));
1318 -
1319 2667 }
1320 2668
1321 2669 // Are we to export any media ?
1322 2670 if(!empty($pagelayer->media_to_export)){
@@ -1323,8 +2671,10 @@
1323 2671 // TODO
1324 2672 //$done['media'] = $pagelayer->media_to_export;
1325 2673 }
1326 2674
2675 + do_action('pagelayer_template_export_completed');
2676 +
1327 2677 $done['success'] = __pl('temp_export_success');
1328 2678
1329 2679 // Output and die
1330 2680 pagelayer_json_output($done);
@@ -1329,4 +2679,213 @@
1329 2679 // Output and die
1330 2680 pagelayer_json_output($done);
1331 2681
1332 2682 }
2683 +
2684 +add_action('wp_ajax_pagelayer_get_cat_checkboxes', 'pagelayer_get_cat_checkboxes');
2685 +function pagelayer_get_cat_checkboxes(){
2686 +
2687 + // Some AJAX security
2688 + check_ajax_referer('pagelayer_ajax', 'pagelayer_nonce');
2689 +
2690 + $ret = [];
2691 + $cat_name = '';
2692 +
2693 + if(!current_user_can('manage_categories')){
2694 + $ret['error'] = __pl('no_permission');
2695 + pagelayer_json_output($ret);
2696 + }
2697 +
2698 + if(empty($_POST['postid']) || !is_numeric($_POST['postid'])){
2699 + $ret['error'] = __pl('invalid_post_id');
2700 + pagelayer_json_output($ret);
2701 + }
2702 +
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 +}
2727 +
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);
2740 + }
2741 +
2742 + if(empty($_POST['postid']) || !is_numeric($_POST['postid']) ){
2743 + pagelayer_json_output($ret);
2744 + }
2745 +
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(){
2769 +
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 +}
2809 +
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 + }
2822 +
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;
2887 + }
2888 + }
2889 +
2890 + update_option('softaculous_plugin_update_notice', $plugin_update_notice);
2891 +}