PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.8.0
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.8.0
3.8.0 3.7.5 3.7.4 3.7.3 3.7.2 1-final 3.7.1 3.7.0 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 All 112 releases
templately / modules / block-recovery / Report.php

Report.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! 3.8.0, at modules/block-recovery/Report.php

160 lines 5.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Templately\Modules\BlockRecovery;
4
5 use Templately\Utils\Helper;
6
7 /**
8 * What the browser pass could not repair, aggregated into something a user can act on.
9 *
10 * Skips are not failures of the pass — they are the pass refusing to destroy data. A block is
11 * skipped when the installed plugin does not declare an attribute the stored markup carries
12 * (`parse` would drop it, and rebuilding would write it out of existence permanently). The
13 * useful message is therefore not "we could not fix this" but "this plugin is behind the
14 * version this pack was built with; update it and these blocks fix themselves".
15 */
16 class Report {
17
18 const OPTION = 'templately_block_rebuild_report';
19
20 /** Which trigger produced an outcome (060 FR-013). Rows from before 060 read as the batch. */
21 const TRIGGER_BATCH = 'batch';
22 const TRIGGER_ON_OPEN = 'on-open';
23
24 /** Reports older than this are dropped, matching the queue's own retention. */
25 const MAX_AGE = 7 * DAY_IN_SECONDS;
26
27 /**
28 * Fold one post's result into the stored report.
29 *
30 * @param int $post_id Post that was visited.
31 * @param string $status 'clean' | 'rebuilt' | 'skipped' | 'failed'.
32 * @param int $rebuilt Number of blocks regenerated.
33 * @param array $skipped `[['block' => 'name', 'droppedAttrs' => ['x']], …]`
34 * @param int $preserved Blocks rebuilt whose undeclared attributes were merged back.
35 * @param int $restored Individual attributes merged back.
36 * @param string $trigger Which trigger produced this: 'batch' | 'on-open'. Unknown → 'batch'.
37 * @param int $duration Wall time the trigger spent on this post, in ms (0 = not measured).
38 */
39 public static function record( int $post_id, string $status, int $rebuilt, array $skipped, int $preserved = 0, int $restored = 0, string $trigger = self::TRIGGER_BATCH, int $duration = 0 ) {
40 $report = self::get();
41
42 if ( ! in_array( $trigger, [ self::TRIGGER_BATCH, self::TRIGGER_ON_OPEN ], true ) ) {
43 $trigger = self::TRIGGER_BATCH;
44 }
45 $duration = max( 0, $duration );
46
47 $report['created_at'] = $report['created_at'] ?? time();
48 $report['posts'][ $post_id ] = [
49 'status' => $status,
50 'rebuilt' => $rebuilt,
51 'skipped' => count( $skipped ),
52 // Recorded so a summary rendered from the STORED report (a remount, a later visit)
53 // says the same thing as the one rendered from the live run.
54 'preserved' => $preserved,
55 'restored' => $restored,
56 'trigger' => $trigger,
57 'durationMs' => $duration,
58 ];
59
60 $report['totals']['rebuilt'] = ( $report['totals']['rebuilt'] ?? 0 ) + $rebuilt;
61 $report['totals']['skipped'] = ( $report['totals']['skipped'] ?? 0 ) + count( $skipped );
62 $report['totals']['preserved'] = ( $report['totals']['preserved'] ?? 0 ) + $preserved;
63 $report['totals']['restored'] = ( $report['totals']['restored'] ?? 0 ) + $restored;
64
65 $by_trigger = $report['totals']['byTrigger'][ $trigger ] ?? [ 'posts' => 0, 'durationMs' => 0 ];
66 $by_trigger['posts']++;
67 $by_trigger['durationMs'] += $duration;
68 $report['totals']['byTrigger'][ $trigger ] = $by_trigger;
69
70 foreach ( $skipped as $entry ) {
71 $block = isset( $entry['block'] ) ? (string) $entry['block'] : '';
72 $slug = self::plugin_slug_for_block( $block );
73
74 if ( '' === $slug ) {
75 continue;
76 }
77
78 $bucket = $report['plugins'][ $slug ] ?? [
79 'slug' => $slug,
80 'blocks' => 0,
81 'unknownAttributes' => [],
82 'postIds' => [],
83 ];
84
85 $bucket['blocks']++;
86
87 foreach ( (array) ( $entry['droppedAttrs'] ?? [] ) as $attribute ) {
88 $attribute = (string) $attribute;
89 if ( '' !== $attribute && ! in_array( $attribute, $bucket['unknownAttributes'], true ) ) {
90 $bucket['unknownAttributes'][] = $attribute;
91 }
92 }
93
94 if ( ! in_array( $post_id, $bucket['postIds'], true ) ) {
95 $bucket['postIds'][] = $post_id;
96 }
97
98 $report['plugins'][ $slug ] = $bucket;
99 }
100
101 update_option( self::OPTION, $report, false );
102
103 if ( ! empty( $skipped ) ) {
104 Helper::log(
105 [
106 'context' => 'block_rebuild_skipped',
107 'post_id' => $post_id,
108 'skipped' => $skipped,
109 ],
110 'fsi_event'
111 );
112 }
113 }
114
115 /**
116 * @return array{created_at?:int,posts?:array,totals?:array,plugins?:array}
117 */
118 public static function get(): array {
119 $report = get_option( self::OPTION, [] );
120
121 if ( ! is_array( $report ) ) {
122 return [];
123 }
124
125 if ( ! empty( $report['created_at'] ) && ( time() - (int) $report['created_at'] ) > self::MAX_AGE ) {
126 self::clear();
127
128 return [];
129 }
130
131 return $report;
132 }
133
134 public static function clear() {
135 delete_option( self::OPTION );
136 }
137
138 /**
139 * Map a block name to the plugin the user has to update.
140 *
141 * Block namespaces are not plugin slugs in general, so only the ones we can state with
142 * confidence are mapped; anything else is reported by its namespace rather than guessed at,
143 * because telling someone to update the wrong plugin is worse than naming none.
144 */
145 private static function plugin_slug_for_block( string $block_name ): string {
146 if ( '' === $block_name || false === strpos( $block_name, '/' ) ) {
147 return '';
148 }
149
150 list( $namespace ) = explode( '/', $block_name, 2 );
151
152 $known = [
153 'essential-blocks' => 'essential-blocks',
154 'core' => '',
155 ];
156
157 return array_key_exists( $namespace, $known ) ? $known[ $namespace ] : $namespace;
158 }
159 }
160