Changeset 3789736
- Timestamp:
- 11/07/2026 02:25:46 PM (less than one hour ago)
- Location:
- mega-ai
- Files:
-
- 12 edited
- 1 copied
-
tags/2.34.0 (copied) (copied from mega-ai/trunk )
-
tags/2.34.0/builder-css.php (modified) (4 diffs)
-
tags/2.34.0/editor-blocks.php (modified) (4 diffs)
-
tags/2.34.0/mega.php (modified) (4 diffs)
-
tags/2.34.0/page-duplicate.php (modified) (1 diff)
-
tags/2.34.0/readme.txt (modified) (2 diffs)
-
tags/2.34.0/sandbox.php (modified) (1 diff)
-
trunk/builder-css.php (modified) (4 diffs)
-
trunk/editor-blocks.php (modified) (4 diffs)
-
trunk/mega.php (modified) (4 diffs)
-
trunk/page-duplicate.php (modified) (1 diff)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/sandbox.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
mega-ai/tags/2.34.0/builder-css.php
r3786786 r3789736 15 15 * CSS loading mode itself and rewrites that one file. Never call 16 16 * `Assets_Files::regenerate_css_files()`: it rebuilds every post on the site. 17 * Bricks skips any element CSS it already generated in the same request 18 * (`Assets::$unique_inline_css`), and an undo's `wp_restore_post_revision` runs Bricks' own 19 * `save_post` first, so the rebuild after it wrote only the element-type defaults (an 20 * unstyled page). The tracking is reset first, as Bricks does for its own bulk rebuild. 17 21 * - Beaver keeps `uploads/bb-plugin/cache/<id>-layout*.css|js` and rebuilds a missing file on the 18 22 * next view. `FLBuilderModel::delete_all_asset_cache(<id>)` unlinks only that post's files. … … 24 28 final class MegaBuilderCss { 25 29 const BRICKS_FILES_CLASS = 'Bricks\Assets_Files'; 30 const BRICKS_ASSETS_CLASS = 'Bricks\Assets'; 26 31 const BEAVER_MODEL_CLASS = 'FLBuilderModel'; 27 32 … … 37 42 } 38 43 44 /** True when the post has a Bricks or Beaver Builder layout whose generated CSS it needs. */ 45 public static function has_layout($post_id) { 46 $post_id = is_numeric($post_id) ? (int) $post_id : 0; 47 if ($post_id <= 0) { 48 return false; 49 } 50 $bricks = \get_post_meta($post_id, '_bricks_page_content_2', true); 51 if (is_array($bricks) && $bricks !== array() && (string) \get_post_meta($post_id, '_bricks_editor_mode', true) !== 'wordpress') { 52 return true; 53 } 54 return !empty(\get_post_meta($post_id, '_fl_builder_data', true)) || !empty(\get_post_meta($post_id, '_fl_builder_draft', true)); 55 } 56 39 57 private static function bricks($post_id) { 40 58 try { … … 46 64 return false; 47 65 } 66 self::reset_bricks_duplicates(); 48 67 $file = call_user_func(array(self::BRICKS_FILES_CLASS, 'generate_post_css_file'), $post_id, 'content', $elements); 49 68 return is_string($file) && $file !== ''; 50 69 } catch (\Throwable $e) { 51 70 return false; 71 } 72 } 73 74 /** 75 * Forget the element CSS Bricks generated earlier in this request, so the rebuild emits every 76 * element's rules again. `Assets::reset_duplication_tracking()` (Bricks 2.0.1+) clears all of it; 77 * older Bricks keeps the list in `Assets::$unique_inline_css` (1.8+). 78 */ 79 private static function reset_bricks_duplicates() { 80 $assets = self::BRICKS_ASSETS_CLASS; 81 if (!class_exists($assets)) { 82 return; 83 } 84 // A failed reset must not skip the rebuild that follows it. 85 try { 86 if (method_exists($assets, 'reset_duplication_tracking')) { 87 call_user_func(array($assets, 'reset_duplication_tracking')); 88 } elseif (property_exists($assets, 'unique_inline_css')) { 89 $assets::$unique_inline_css = array(); 90 } 91 } catch (\Throwable $e) { 52 92 } 53 93 } -
mega-ai/tags/2.34.0/editor-blocks.php
r3786786 r3789736 1400 1400 1401 1401 /** 1402 * Two decoded JSON values are the same: objects key by key in any order, lists in order. A 1403 * client may re-encode an element with its object keys sorted (the mega CLI does), and Beaver 1404 * stores maps such as a module's empty `connections` in its own order, so a value sent back 1405 * unchanged must not count as an edit. 1406 */ 1407 private static function same_value($a, $b) { 1408 if (!is_array($a) || !is_array($b)) return $a === $b; 1409 if (count($a) !== count($b) || self::is_list($a) !== self::is_list($b)) return false; 1410 foreach ($a as $k => $v) { 1411 if (!array_key_exists($k, $b) || !self::same_value($v, $b[$k])) return false; 1412 } 1413 return true; 1414 } 1415 1416 /** A cleaned settings object with the stored keys first, in their stored order, then new keys. */ 1417 private static function in_stored_order($out, $norm) { 1418 if (!is_array($norm) || $norm === array() || self::is_list($norm) || self::is_list($out)) return $out; 1419 $ordered = array(); 1420 foreach (array_keys($norm) as $k) { 1421 if (array_key_exists($k, $out)) $ordered[$k] = $out[$k]; 1422 } 1423 foreach ($out as $k => $v) { 1424 if (!array_key_exists($k, $ordered)) $ordered[$k] = $v; 1425 } 1426 return $ordered; 1427 } 1428 1429 /** 1402 1430 * Settings made safe: a value equal to what the node already stores ($orig, compared through 1403 1431 * its normalized form $norm) is kept exactly as stored; anything else is checked. Refused keys … … 1408 1436 */ 1409 1437 private static function clean_node_settings($kind, $value, $orig, $norm, &$sanitized, $key = '') { 1410 if ($norm !== null && $value === $norm) return $orig;1438 if ($norm !== null && self::same_value($value, $norm)) return $orig; 1411 1439 if (is_array($value)) { 1412 1440 $out = array(); … … 1415 1443 $child_orig = $child_norm === null ? null : self::node_field($orig, (string) $k); 1416 1444 if (is_array($orig) && $child_norm !== null && array_key_exists($k, $orig)) $child_orig = $orig[$k]; 1417 $unchanged = $child_norm !== null && $v === $child_norm;1445 $unchanged = $child_norm !== null && self::same_value($v, $child_norm); 1418 1446 if (!$unchanged && in_array((string) $k, self::NODE_REFUSED_KEYS, true) && !($v === array() || $v === '' || $v === null)) { 1419 1447 return self::error('INVALID_VALUE', sprintf('Setting %s is not accepted on an added or edited element.', (string) $k), 400); … … 1426 1454 $out[$k] = $clean; 1427 1455 } 1428 return $out;1456 return self::in_stored_order($out, $norm); 1429 1457 } 1430 1458 if (!is_string($value)) return $value; -
mega-ai/tags/2.34.0/mega.php
r3788788 r3789736 3 3 Plugin Name: MEGA AI 4 4 Description: Connect your WordPress website to MEGA for automated SEO optimization and content management. 5 Version: 2.3 3.05 Version: 2.34.0 6 6 Author: MEGA 7 7 Author URI: https://gomega.ai … … 102 102 class MegaPlugin { 103 103 private static $namespace = 'mega'; 104 private static $version = '2.3 3.0';104 private static $version = '2.34.0'; 105 105 106 106 // Editor (widget) endpoints. … … 4000 4000 $draft_doc = MegaEditorBlocks::parse('nodes', $draft[0], $kind); 4001 4001 $same_bytes = !\is_wp_error($draft_doc) && MegaEditorBlocks::encode($draft_doc['source']) === MegaEditorBlocks::encode($doc['source']); 4002 if (!$same_bytes && !$this->beaver_draft_matches_published($raw, $draft[0])) { 4003 return $this->editor_error('BUILDER_DRAFT_PENDING', 'This page has unpublished Beaver Builder changes (its draft differs from the published layout). Publish or discard them in Beaver first; nothing was written.', 409); 4002 if (!$same_bytes) { 4003 $draft_check = $this->beaver_draft_comparison($raw, $draft[0]); 4004 if (!$draft_check['same']) { 4005 return $this->editor_error('BUILDER_DRAFT_PENDING', 'This page has unpublished Beaver Builder changes (its draft differs from the published layout). Publish or discard them in Beaver first; nothing was written.', 409, $draft_check['details']); 4006 } 4004 4007 } 4005 4008 $writes['_fl_builder_draft'] = $encoded; … … 4018 4021 * never refresh it, so a long-lived process would compare a stale layout. Without Beaver loaded 4019 4022 * there is no way to ask, and the caller keeps refusing. 4020 */ 4021 private function beaver_draft_matches_published($published_raw, $draft_raw) { 4022 if (!\class_exists('FLBuilderModel') || !\is_callable(array('FLBuilderModel', 'clean_layout_data'))) { 4023 return false; 4024 } 4025 $clean = static function ($raw) { 4026 $data = \FLBuilderModel::clean_layout_data(\maybe_unserialize($raw)); 4027 if (\class_exists('FLBuilderSettingsCompat') && \is_callable(array('FLBuilderSettingsCompat', 'filter_layout_data'))) { 4028 $data = \FLBuilderSettingsCompat::filter_layout_data($data); 4029 } 4030 return $data; 4023 * 4024 * Returns array('same' => bool, 'details' => array) where the details say why a refusal was made 4025 * without any page content: whether Beaver was loaded, both rows' byte length and sha256, and up 4026 * to 10 nodes that differ with what differs (only in one, type, parent, position, or the names of 4027 * up to 5 settings). 4028 */ 4029 private function beaver_draft_comparison($published_raw, $draft_raw) { 4030 $details = array( 4031 'beaver_loaded' => \class_exists('FLBuilderModel') && \is_callable(array('FLBuilderModel', 'clean_layout_data')), 4032 'published_bytes' => strlen((string) $published_raw), 4033 'draft_bytes' => strlen((string) $draft_raw), 4034 'published_sha256' => hash('sha256', (string) $published_raw), 4035 'draft_sha256' => hash('sha256', (string) $draft_raw), 4036 'clean_failed' => false, 4037 ); 4038 $published = \maybe_unserialize($published_raw); 4039 $draft = \maybe_unserialize($draft_raw); 4040 $same = false; 4041 if ($details['beaver_loaded']) { 4042 $clean = static function ($data) { 4043 $data = \FLBuilderModel::clean_layout_data($data); 4044 if (\class_exists('FLBuilderSettingsCompat') && \is_callable(array('FLBuilderSettingsCompat', 'filter_layout_data'))) { 4045 $data = \FLBuilderSettingsCompat::filter_layout_data($data); 4046 } 4047 return $data; 4048 }; 4049 try { 4050 $published = $clean($published); 4051 $draft = $clean($draft); 4052 $same = !empty($published) && serialize($published) === serialize($draft); 4053 } catch (\Throwable $e) { 4054 $details['clean_failed'] = true; 4055 } 4056 } 4057 if (!$same) { 4058 $nodes = self::beaver_node_differences($published, $draft); 4059 $details['differing_node_count'] = count($nodes); 4060 $details['differing_nodes'] = array_slice($nodes, 0, 10); 4061 } 4062 return array('same' => $same, 'details' => $details); 4063 } 4064 4065 /** "<node id>: <what differs>" for each node that is not the same in both Beaver layouts. */ 4066 private static function beaver_node_differences($published, $draft) { 4067 $as_map = static function ($layout) { 4068 $out = array(); 4069 if (is_array($layout) || is_object($layout)) { 4070 foreach ((array) $layout as $id => $node) { 4071 $out[(string) $id] = is_object($node) ? (array) $node : (is_array($node) ? $node : array()); 4072 } 4073 } 4074 return $out; 4031 4075 }; 4032 try { 4033 $published = $clean($published_raw); 4034 $draft = $clean($draft_raw); 4035 } catch (\Throwable $e) { 4036 return false; 4037 } 4038 return !empty($published) && serialize($published) === serialize($draft); 4076 $a = $as_map($published); 4077 $b = $as_map($draft); 4078 $out = array(); 4079 foreach (array_unique(array_merge(array_keys($a), array_keys($b))) as $id) { 4080 if (!isset($b[$id])) { 4081 $out[] = $id . ': published only'; 4082 continue; 4083 } 4084 if (!isset($a[$id])) { 4085 $out[] = $id . ': draft only'; 4086 continue; 4087 } 4088 $what = array(); 4089 foreach (array('type', 'parent', 'position') as $field) { 4090 $x = isset($a[$id][$field]) ? $a[$id][$field] : null; 4091 $y = isset($b[$id][$field]) ? $b[$id][$field] : null; 4092 if ($x !== $y) $what[] = $field; 4093 } 4094 $sa = isset($a[$id]['settings']) ? (array) $a[$id]['settings'] : array(); 4095 $sb = isset($b[$id]['settings']) ? (array) $b[$id]['settings'] : array(); 4096 $keys = array(); 4097 foreach (array_unique(array_merge(array_keys($sa), array_keys($sb))) as $key) { 4098 $x = array_key_exists($key, $sa) ? serialize($sa[$key]) : null; 4099 $y = array_key_exists($key, $sb) ? serialize($sb[$key]) : null; 4100 if ($x !== $y) $keys[] = (string) $key; 4101 } 4102 if ($keys !== array()) $what[] = 'settings ' . implode(',', array_slice($keys, 0, 5)) . (count($keys) > 5 ? ',...' : ''); 4103 $rest_a = $a[$id]; 4104 $rest_b = $b[$id]; 4105 unset($rest_a['type'], $rest_a['parent'], $rest_a['position'], $rest_a['settings'], $rest_b['type'], $rest_b['parent'], $rest_b['position'], $rest_b['settings']); 4106 if (serialize($rest_a) !== serialize($rest_b)) $what[] = 'other fields'; 4107 if ($what !== array()) $out[] = $id . ': ' . implode('; ', $what); 4108 } 4109 return $out; 4039 4110 } 4040 4111 -
mega-ai/tags/2.34.0/page-duplicate.php
r3788711 r3789736 110 110 $copied = self::copy_meta((int) $source_id, (int) $copy_id); 111 111 self::copy_terms($source, (int) $copy_id); 112 if (MegaSandbox::is_elementor_post($source_id) ) {112 if (MegaSandbox::is_elementor_post($source_id) || (MegaModules::loaded('builder-css.php') && MegaBuilderCss::has_layout((int) $copy_id))) { 113 113 MegaPlugin::regenerate_post_css_static((int) $copy_id); 114 114 } -
mega-ai/tags/2.34.0/readme.txt
r3788788 r3789736 4 4 Requires at least: 4.4 5 5 Tested up to: 6.8 6 Stable tag: 2.3 3.06 Stable tag: 2.34.0 7 7 Requires PHP: 7.2 8 8 License: GPLv2 or later … … 149 149 150 150 == Changelog == 151 = 2.34.0 = 152 * Fix: after an undo on a Bricks page, its generated CSS file again holds every element's styles. Bricks' own save, run by the revision restore, had marked them generated, so the rebuild wrote only the element defaults and the page lost its styling. 153 * Fix: a private test copy or draft duplicate of a Bricks or Beaver Builder page gets its own generated CSS, so it renders like the original. 154 * Fix: an edited Bricks element or Beaver Builder node keeps a setting sent back unchanged in any key order (such as a Beaver module's empty `connections`) instead of refusing it, and keeps the stored setting order. 155 * Improvement: the `BUILDER_DRAFT_PENDING` refusal reports why the Beaver draft differs (Beaver loaded or not, both layouts' size and hash, and the first differing nodes and fields), without page content. 156 151 157 = 2.33.0 = 152 158 * Feature: `POST /mega/v1/cache/flush` also clears the Kinsta server cache and CDN, the Sucuri firewall cache (when the site saved its Sucuri API key), Cache Enabler, Nginx Helper, Hummingbird, WP-Optimize, the Pantheon edge and Endurance Page Cache. Each uses only that host's or plugin's own purge call, runs only when present, and cannot stop the others if it fails. -
mega-ai/tags/2.34.0/sandbox.php
r3788626 r3789736 101 101 self::copy_meta((int) $source_id, (int) $sandbox_id); 102 102 self::copy_terms($source, (int) $sandbox_id); 103 if (self::is_elementor_post($source_id)) { 104 // Derived caches were not copied; build this copy's own CSS so the baseline preview renders. 103 // Derived caches were not copied; build this copy's own CSS so the baseline preview renders. 104 // Bricks writes a post's CSS file only on its own save, which ran before the layout was copied. 105 if (self::is_elementor_post($source_id) || (MegaModules::loaded('builder-css.php') && MegaBuilderCss::has_layout((int) $sandbox_id))) { 105 106 MegaPlugin::regenerate_post_css_static((int) $sandbox_id); 106 107 } -
mega-ai/trunk/builder-css.php
r3786786 r3789736 15 15 * CSS loading mode itself and rewrites that one file. Never call 16 16 * `Assets_Files::regenerate_css_files()`: it rebuilds every post on the site. 17 * Bricks skips any element CSS it already generated in the same request 18 * (`Assets::$unique_inline_css`), and an undo's `wp_restore_post_revision` runs Bricks' own 19 * `save_post` first, so the rebuild after it wrote only the element-type defaults (an 20 * unstyled page). The tracking is reset first, as Bricks does for its own bulk rebuild. 17 21 * - Beaver keeps `uploads/bb-plugin/cache/<id>-layout*.css|js` and rebuilds a missing file on the 18 22 * next view. `FLBuilderModel::delete_all_asset_cache(<id>)` unlinks only that post's files. … … 24 28 final class MegaBuilderCss { 25 29 const BRICKS_FILES_CLASS = 'Bricks\Assets_Files'; 30 const BRICKS_ASSETS_CLASS = 'Bricks\Assets'; 26 31 const BEAVER_MODEL_CLASS = 'FLBuilderModel'; 27 32 … … 37 42 } 38 43 44 /** True when the post has a Bricks or Beaver Builder layout whose generated CSS it needs. */ 45 public static function has_layout($post_id) { 46 $post_id = is_numeric($post_id) ? (int) $post_id : 0; 47 if ($post_id <= 0) { 48 return false; 49 } 50 $bricks = \get_post_meta($post_id, '_bricks_page_content_2', true); 51 if (is_array($bricks) && $bricks !== array() && (string) \get_post_meta($post_id, '_bricks_editor_mode', true) !== 'wordpress') { 52 return true; 53 } 54 return !empty(\get_post_meta($post_id, '_fl_builder_data', true)) || !empty(\get_post_meta($post_id, '_fl_builder_draft', true)); 55 } 56 39 57 private static function bricks($post_id) { 40 58 try { … … 46 64 return false; 47 65 } 66 self::reset_bricks_duplicates(); 48 67 $file = call_user_func(array(self::BRICKS_FILES_CLASS, 'generate_post_css_file'), $post_id, 'content', $elements); 49 68 return is_string($file) && $file !== ''; 50 69 } catch (\Throwable $e) { 51 70 return false; 71 } 72 } 73 74 /** 75 * Forget the element CSS Bricks generated earlier in this request, so the rebuild emits every 76 * element's rules again. `Assets::reset_duplication_tracking()` (Bricks 2.0.1+) clears all of it; 77 * older Bricks keeps the list in `Assets::$unique_inline_css` (1.8+). 78 */ 79 private static function reset_bricks_duplicates() { 80 $assets = self::BRICKS_ASSETS_CLASS; 81 if (!class_exists($assets)) { 82 return; 83 } 84 // A failed reset must not skip the rebuild that follows it. 85 try { 86 if (method_exists($assets, 'reset_duplication_tracking')) { 87 call_user_func(array($assets, 'reset_duplication_tracking')); 88 } elseif (property_exists($assets, 'unique_inline_css')) { 89 $assets::$unique_inline_css = array(); 90 } 91 } catch (\Throwable $e) { 52 92 } 53 93 } -
mega-ai/trunk/editor-blocks.php
r3786786 r3789736 1400 1400 1401 1401 /** 1402 * Two decoded JSON values are the same: objects key by key in any order, lists in order. A 1403 * client may re-encode an element with its object keys sorted (the mega CLI does), and Beaver 1404 * stores maps such as a module's empty `connections` in its own order, so a value sent back 1405 * unchanged must not count as an edit. 1406 */ 1407 private static function same_value($a, $b) { 1408 if (!is_array($a) || !is_array($b)) return $a === $b; 1409 if (count($a) !== count($b) || self::is_list($a) !== self::is_list($b)) return false; 1410 foreach ($a as $k => $v) { 1411 if (!array_key_exists($k, $b) || !self::same_value($v, $b[$k])) return false; 1412 } 1413 return true; 1414 } 1415 1416 /** A cleaned settings object with the stored keys first, in their stored order, then new keys. */ 1417 private static function in_stored_order($out, $norm) { 1418 if (!is_array($norm) || $norm === array() || self::is_list($norm) || self::is_list($out)) return $out; 1419 $ordered = array(); 1420 foreach (array_keys($norm) as $k) { 1421 if (array_key_exists($k, $out)) $ordered[$k] = $out[$k]; 1422 } 1423 foreach ($out as $k => $v) { 1424 if (!array_key_exists($k, $ordered)) $ordered[$k] = $v; 1425 } 1426 return $ordered; 1427 } 1428 1429 /** 1402 1430 * Settings made safe: a value equal to what the node already stores ($orig, compared through 1403 1431 * its normalized form $norm) is kept exactly as stored; anything else is checked. Refused keys … … 1408 1436 */ 1409 1437 private static function clean_node_settings($kind, $value, $orig, $norm, &$sanitized, $key = '') { 1410 if ($norm !== null && $value === $norm) return $orig;1438 if ($norm !== null && self::same_value($value, $norm)) return $orig; 1411 1439 if (is_array($value)) { 1412 1440 $out = array(); … … 1415 1443 $child_orig = $child_norm === null ? null : self::node_field($orig, (string) $k); 1416 1444 if (is_array($orig) && $child_norm !== null && array_key_exists($k, $orig)) $child_orig = $orig[$k]; 1417 $unchanged = $child_norm !== null && $v === $child_norm;1445 $unchanged = $child_norm !== null && self::same_value($v, $child_norm); 1418 1446 if (!$unchanged && in_array((string) $k, self::NODE_REFUSED_KEYS, true) && !($v === array() || $v === '' || $v === null)) { 1419 1447 return self::error('INVALID_VALUE', sprintf('Setting %s is not accepted on an added or edited element.', (string) $k), 400); … … 1426 1454 $out[$k] = $clean; 1427 1455 } 1428 return $out;1456 return self::in_stored_order($out, $norm); 1429 1457 } 1430 1458 if (!is_string($value)) return $value; -
mega-ai/trunk/mega.php
r3788788 r3789736 3 3 Plugin Name: MEGA AI 4 4 Description: Connect your WordPress website to MEGA for automated SEO optimization and content management. 5 Version: 2.3 3.05 Version: 2.34.0 6 6 Author: MEGA 7 7 Author URI: https://gomega.ai … … 102 102 class MegaPlugin { 103 103 private static $namespace = 'mega'; 104 private static $version = '2.3 3.0';104 private static $version = '2.34.0'; 105 105 106 106 // Editor (widget) endpoints. … … 4000 4000 $draft_doc = MegaEditorBlocks::parse('nodes', $draft[0], $kind); 4001 4001 $same_bytes = !\is_wp_error($draft_doc) && MegaEditorBlocks::encode($draft_doc['source']) === MegaEditorBlocks::encode($doc['source']); 4002 if (!$same_bytes && !$this->beaver_draft_matches_published($raw, $draft[0])) { 4003 return $this->editor_error('BUILDER_DRAFT_PENDING', 'This page has unpublished Beaver Builder changes (its draft differs from the published layout). Publish or discard them in Beaver first; nothing was written.', 409); 4002 if (!$same_bytes) { 4003 $draft_check = $this->beaver_draft_comparison($raw, $draft[0]); 4004 if (!$draft_check['same']) { 4005 return $this->editor_error('BUILDER_DRAFT_PENDING', 'This page has unpublished Beaver Builder changes (its draft differs from the published layout). Publish or discard them in Beaver first; nothing was written.', 409, $draft_check['details']); 4006 } 4004 4007 } 4005 4008 $writes['_fl_builder_draft'] = $encoded; … … 4018 4021 * never refresh it, so a long-lived process would compare a stale layout. Without Beaver loaded 4019 4022 * there is no way to ask, and the caller keeps refusing. 4020 */ 4021 private function beaver_draft_matches_published($published_raw, $draft_raw) { 4022 if (!\class_exists('FLBuilderModel') || !\is_callable(array('FLBuilderModel', 'clean_layout_data'))) { 4023 return false; 4024 } 4025 $clean = static function ($raw) { 4026 $data = \FLBuilderModel::clean_layout_data(\maybe_unserialize($raw)); 4027 if (\class_exists('FLBuilderSettingsCompat') && \is_callable(array('FLBuilderSettingsCompat', 'filter_layout_data'))) { 4028 $data = \FLBuilderSettingsCompat::filter_layout_data($data); 4029 } 4030 return $data; 4023 * 4024 * Returns array('same' => bool, 'details' => array) where the details say why a refusal was made 4025 * without any page content: whether Beaver was loaded, both rows' byte length and sha256, and up 4026 * to 10 nodes that differ with what differs (only in one, type, parent, position, or the names of 4027 * up to 5 settings). 4028 */ 4029 private function beaver_draft_comparison($published_raw, $draft_raw) { 4030 $details = array( 4031 'beaver_loaded' => \class_exists('FLBuilderModel') && \is_callable(array('FLBuilderModel', 'clean_layout_data')), 4032 'published_bytes' => strlen((string) $published_raw), 4033 'draft_bytes' => strlen((string) $draft_raw), 4034 'published_sha256' => hash('sha256', (string) $published_raw), 4035 'draft_sha256' => hash('sha256', (string) $draft_raw), 4036 'clean_failed' => false, 4037 ); 4038 $published = \maybe_unserialize($published_raw); 4039 $draft = \maybe_unserialize($draft_raw); 4040 $same = false; 4041 if ($details['beaver_loaded']) { 4042 $clean = static function ($data) { 4043 $data = \FLBuilderModel::clean_layout_data($data); 4044 if (\class_exists('FLBuilderSettingsCompat') && \is_callable(array('FLBuilderSettingsCompat', 'filter_layout_data'))) { 4045 $data = \FLBuilderSettingsCompat::filter_layout_data($data); 4046 } 4047 return $data; 4048 }; 4049 try { 4050 $published = $clean($published); 4051 $draft = $clean($draft); 4052 $same = !empty($published) && serialize($published) === serialize($draft); 4053 } catch (\Throwable $e) { 4054 $details['clean_failed'] = true; 4055 } 4056 } 4057 if (!$same) { 4058 $nodes = self::beaver_node_differences($published, $draft); 4059 $details['differing_node_count'] = count($nodes); 4060 $details['differing_nodes'] = array_slice($nodes, 0, 10); 4061 } 4062 return array('same' => $same, 'details' => $details); 4063 } 4064 4065 /** "<node id>: <what differs>" for each node that is not the same in both Beaver layouts. */ 4066 private static function beaver_node_differences($published, $draft) { 4067 $as_map = static function ($layout) { 4068 $out = array(); 4069 if (is_array($layout) || is_object($layout)) { 4070 foreach ((array) $layout as $id => $node) { 4071 $out[(string) $id] = is_object($node) ? (array) $node : (is_array($node) ? $node : array()); 4072 } 4073 } 4074 return $out; 4031 4075 }; 4032 try { 4033 $published = $clean($published_raw); 4034 $draft = $clean($draft_raw); 4035 } catch (\Throwable $e) { 4036 return false; 4037 } 4038 return !empty($published) && serialize($published) === serialize($draft); 4076 $a = $as_map($published); 4077 $b = $as_map($draft); 4078 $out = array(); 4079 foreach (array_unique(array_merge(array_keys($a), array_keys($b))) as $id) { 4080 if (!isset($b[$id])) { 4081 $out[] = $id . ': published only'; 4082 continue; 4083 } 4084 if (!isset($a[$id])) { 4085 $out[] = $id . ': draft only'; 4086 continue; 4087 } 4088 $what = array(); 4089 foreach (array('type', 'parent', 'position') as $field) { 4090 $x = isset($a[$id][$field]) ? $a[$id][$field] : null; 4091 $y = isset($b[$id][$field]) ? $b[$id][$field] : null; 4092 if ($x !== $y) $what[] = $field; 4093 } 4094 $sa = isset($a[$id]['settings']) ? (array) $a[$id]['settings'] : array(); 4095 $sb = isset($b[$id]['settings']) ? (array) $b[$id]['settings'] : array(); 4096 $keys = array(); 4097 foreach (array_unique(array_merge(array_keys($sa), array_keys($sb))) as $key) { 4098 $x = array_key_exists($key, $sa) ? serialize($sa[$key]) : null; 4099 $y = array_key_exists($key, $sb) ? serialize($sb[$key]) : null; 4100 if ($x !== $y) $keys[] = (string) $key; 4101 } 4102 if ($keys !== array()) $what[] = 'settings ' . implode(',', array_slice($keys, 0, 5)) . (count($keys) > 5 ? ',...' : ''); 4103 $rest_a = $a[$id]; 4104 $rest_b = $b[$id]; 4105 unset($rest_a['type'], $rest_a['parent'], $rest_a['position'], $rest_a['settings'], $rest_b['type'], $rest_b['parent'], $rest_b['position'], $rest_b['settings']); 4106 if (serialize($rest_a) !== serialize($rest_b)) $what[] = 'other fields'; 4107 if ($what !== array()) $out[] = $id . ': ' . implode('; ', $what); 4108 } 4109 return $out; 4039 4110 } 4040 4111 -
mega-ai/trunk/page-duplicate.php
r3788711 r3789736 110 110 $copied = self::copy_meta((int) $source_id, (int) $copy_id); 111 111 self::copy_terms($source, (int) $copy_id); 112 if (MegaSandbox::is_elementor_post($source_id) ) {112 if (MegaSandbox::is_elementor_post($source_id) || (MegaModules::loaded('builder-css.php') && MegaBuilderCss::has_layout((int) $copy_id))) { 113 113 MegaPlugin::regenerate_post_css_static((int) $copy_id); 114 114 } -
mega-ai/trunk/readme.txt
r3788788 r3789736 4 4 Requires at least: 4.4 5 5 Tested up to: 6.8 6 Stable tag: 2.3 3.06 Stable tag: 2.34.0 7 7 Requires PHP: 7.2 8 8 License: GPLv2 or later … … 149 149 150 150 == Changelog == 151 = 2.34.0 = 152 * Fix: after an undo on a Bricks page, its generated CSS file again holds every element's styles. Bricks' own save, run by the revision restore, had marked them generated, so the rebuild wrote only the element defaults and the page lost its styling. 153 * Fix: a private test copy or draft duplicate of a Bricks or Beaver Builder page gets its own generated CSS, so it renders like the original. 154 * Fix: an edited Bricks element or Beaver Builder node keeps a setting sent back unchanged in any key order (such as a Beaver module's empty `connections`) instead of refusing it, and keeps the stored setting order. 155 * Improvement: the `BUILDER_DRAFT_PENDING` refusal reports why the Beaver draft differs (Beaver loaded or not, both layouts' size and hash, and the first differing nodes and fields), without page content. 156 151 157 = 2.33.0 = 152 158 * Feature: `POST /mega/v1/cache/flush` also clears the Kinsta server cache and CDN, the Sucuri firewall cache (when the site saved its Sucuri API key), Cache Enabler, Nginx Helper, Hummingbird, WP-Optimize, the Pantheon edge and Endurance Page Cache. Each uses only that host's or plugin's own purge call, runs only when present, and cannot stop the others if it fails. -
mega-ai/trunk/sandbox.php
r3788626 r3789736 101 101 self::copy_meta((int) $source_id, (int) $sandbox_id); 102 102 self::copy_terms($source, (int) $sandbox_id); 103 if (self::is_elementor_post($source_id)) { 104 // Derived caches were not copied; build this copy's own CSS so the baseline preview renders. 103 // Derived caches were not copied; build this copy's own CSS so the baseline preview renders. 104 // Bricks writes a post's CSS file only on its own save, which ran before the layout was copied. 105 if (self::is_elementor_post($source_id) || (MegaModules::loaded('builder-css.php') && MegaBuilderCss::has_layout((int) $sandbox_id))) { 105 106 MegaPlugin::regenerate_post_css_static((int) $sandbox_id); 106 107 }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)