PluginProbe
TableKit – WordPress Table Builder for Data Tables, WooCommerce Product Tables & Post Tables / 2.3.0
TableKit – WordPress Table Builder for Data Tables, WooCommerce Product Tables & Post Tables v2.3.0
2.3.0 2.2.14 2.2.13 2.2.12 2.2.11 2.2.10 2.2.9 2.2.8 2.2.7 2.2.6 2.2.5 2.2.4 2.2.3 trunk 1.0.0 1.0.1 2.0.0 2.0.1 2.1.0 2.1.1 2.1.2 2.2.0 2.2.1 2.2.2
← All changes | includes/Config/CPT/InlineTableScanner.php +135 -69 2.2.7 → 2.3.0 View file →
@@ -1,53 +1,72 @@
1 1 <?php
2 +/**
3 + * Scans post content for inline table blocks
4 + *
5 + * @package TableKit
6 + */
2 7
3 8 namespace TableBuilder\Config\CPT;
4 9
5 -defined('ABSPATH') || exit;
10 +defined( 'ABSPATH' ) || exit;
6 11
7 12 use TableBuilder\Shortcode\ShortcodeUtils;
8 13 use WP_Post;
9 14 use WP_Query;
10 15
11 -class InlineTableScanner
12 -{
16 +/**
17 + * Finds and caches table blocks embedded inline within other posts' content.
18 + */
19 +class InlineTableScanner {
20 +
13 21 private const BLOCK_NAMESPACE = 'tablebuilder/';
14 - private const CACHE_GROUP = 'tablekit_blocks';
15 - private const CACHE_KEY = 'inline_tables_v2';
16 - private const CACHE_TTL = 5 * MINUTE_IN_SECONDS;
22 + private const CACHE_GROUP = 'tablekit_blocks';
23 + private const CACHE_KEY = 'inline_tables_v2';
24 + private const CACHE_TTL = 5 * MINUTE_IN_SECONDS;
17 25
18 - public function get_inline_table_source_options(): array
19 - {
26 + /**
27 + * Builds a SELECT-style options list of source posts containing inline table
28 + * blocks, keyed by source post ID, labeled with block count.
29 + *
30 + * @return array<string,string> Options keyed by source post ID (as a string).
31 + */
32 + public function get_inline_table_source_options(): array {
20 33 $inline_tables = $this->get_all_inline_block_tables();
21 34
22 - if (empty($inline_tables)) {
35 + if ( empty( $inline_tables ) ) {
23 36 return array();
24 37 }
25 38
26 39 $options = array();
27 - $grouped = $this->group_inline_tables_by_source($inline_tables);
40 + $grouped = $this->group_inline_tables_by_source( $inline_tables );
28 41
29 - foreach (array_values($grouped) as $group) {
30 - $block_count = count($group['blocks']);
42 + foreach ( array_values( $grouped ) as $group ) {
43 + $block_count = count( $group['blocks'] );
31 44
32 - /* translators: %2$s = source post title. */
33 45 $label = sprintf(
34 - _n('Table in: %2$s', 'Tables in: %2$s', $block_count, 'table-builder-block'),
46 + /* translators: %2$s = source post title. */
47 + _n( 'Table in: %2$s', 'Tables in: %2$s', $block_count, 'table-builder-block' ),
35 48 $block_count,
36 49 $group['source_title']
37 50 );
38 51
39 - $options[(string) $group['source_id']] = $label;
52 + $options[ (string) $group['source_id'] ] = $label;
40 53 }
41 54
42 55 return $options;
43 56 }
44 57
45 - public function get_all_inline_block_tables(): array
46 - {
47 - $cached = wp_cache_get(self::CACHE_KEY, self::CACHE_GROUP);
58 + /**
59 + * Scans every scannable post type for table blocks embedded inline (i.e. not
60 + * inside a dedicated tablekit_table post), cached for 5 minutes.
61 + *
62 + * @return array Flat list of inline table block records (source_id/source_title/
63 + * source_type/source_author/source_date/block_name/block_id/shortcode_id/attrs).
64 + */
65 + public function get_all_inline_block_tables(): array {
66 + $cached = wp_cache_get( self::CACHE_KEY, self::CACHE_GROUP );
48 67
49 - if (false !== $cached) {
68 + if ( false !== $cached ) {
50 69 return (array) $cached;
51 70 }
52 71
53 72 $results = array();
@@ -52,10 +71,10 @@
52 71
53 72 $results = array();
54 73 $post_types = $this->get_scannable_post_types();
55 74
56 - if (empty($post_types)) {
57 - $this->store_cache($results);
75 + if ( empty( $post_types ) ) {
76 + $this->store_cache( $results );
58 77 return $results;
59 78 }
60 79
61 80 $query = new WP_Query(
@@ -60,122 +79,164 @@
60 79
61 80 $query = new WP_Query(
62 81 array(
63 82 'post_type' => $post_types,
64 - 'post_status' => array('publish', 'draft', 'pending', 'private'),
83 + 'post_status' => array( 'publish', 'draft', 'pending', 'private' ),
65 84 'posts_per_page' => -1,
66 85 'no_found_rows' => true,
67 86 's' => self::BLOCK_NAMESPACE,
68 - 'search_columns' => array('post_content'),
87 + 'search_columns' => array( 'post_content' ),
69 88 )
70 89 );
71 90
72 - if (! $query->have_posts()) {
73 - $this->store_cache($results);
91 + if ( ! $query->have_posts() ) {
92 + $this->store_cache( $results );
74 93 return $results;
75 94 }
76 95
77 - foreach ($query->posts as $post) {
78 - $found = $this->extract_table_blocks(parse_blocks($post->post_content));
96 + foreach ( $query->posts as $post ) {
97 + $found = $this->extract_table_blocks( parse_blocks( $post->post_content ) );
79 98
80 - if (empty($found)) {
99 + if ( empty( $found ) ) {
81 100 continue;
82 101 }
83 102
84 - $author_name = (string) get_the_author_meta('display_name', $post->post_author);
103 + $author_name = (string) get_the_author_meta( 'display_name', $post->post_author );
85 104
86 - foreach ($found as $block) {
105 + foreach ( $found as $block ) {
87 106 $attrs = $block['attrs'] ?? array();
88 - $block_id = (string) ($attrs['blockID'] ?? '');
107 + $block_id = (string) ( $attrs['blockID'] ?? '' );
89 108
90 109 $results[] = array(
91 110 'source_id' => (int) $post->ID,
92 - 'source_title' => (string) get_the_title($post),
111 + 'source_title' => (string) get_the_title( $post ),
93 112 'source_type' => (string) $post->post_type,
94 113 'source_author' => $author_name,
95 114 'source_date' => (string) $post->post_date,
96 115 'block_name' => (string) $block['blockName'],
97 116 'block_id' => $block_id,
98 - 'shortcode_id' => $this->resolve_shortcode_id($attrs, $block_id),
117 + 'shortcode_id' => $this->resolve_shortcode_id( $attrs, $block_id ),
99 118 'attrs' => $attrs,
100 119 );
101 120 }
102 121 }
103 122
104 - $this->store_cache($results);
123 + $this->store_cache( $results );
105 124
106 125 return $results;
107 126 }
108 127
109 - public function get_scannable_post_types(): array
110 - {
128 + /**
129 + * Gets the list of post types to scan for inline table blocks: every
130 + * REST-exposed post type except the Tables CPT itself, filterable via
131 + * "tablekit_scannable_post_types".
132 + *
133 + * @return string[] Post type names.
134 + */
135 + public function get_scannable_post_types(): array {
111 136 static $cached = null;
112 - if (is_array($cached)) {
137 + if ( is_array( $cached ) ) {
113 138 return $cached;
114 139 }
115 140
116 - $post_types = get_post_types(array('show_in_rest' => true), 'names');
117 - unset($post_types[TableCPT::POST_TYPE]);
118 - $cached = (array) apply_filters('tablekit_scannable_post_types', array_values($post_types));
141 + $post_types = get_post_types( array( 'show_in_rest' => true ), 'names' );
142 + unset( $post_types[ TableCPT::POST_TYPE ] );
119 143
144 + /**
145 + * Filters the post types scanned for inline table blocks.
146 + *
147 + * @since Unknown
148 + *
149 + * @param string[] $post_types REST-exposed post type names, excluding the Tables CPT itself.
150 + */
151 + $cached = (array) apply_filters( 'tablekit_scannable_post_types', array_values( $post_types ) );
152 +
120 153 return $cached;
121 154 }
122 155
123 - public function extract_table_blocks(array $blocks): array
124 - {
125 - return ShortcodeUtils::filter_table_blocks($blocks);
156 + /**
157 + * Narrow a parsed block tree down to just the plugin's table blocks.
158 + *
159 + * @param array $blocks Parsed block tree.
160 + * @return array Table blocks only.
161 + */
162 + public function extract_table_blocks( array $blocks ): array {
163 + return ShortcodeUtils::filter_table_blocks( $blocks );
126 164 }
127 165
128 - public function maybe_invalidate_cache(int $post_id, ?WP_Post $post = null): void
129 - {
130 - if (null === $post) {
131 - $post = get_post($post_id);
166 + /**
167 + * Invalidates the inline-table scan cache if the saved/deleted post is one
168 + * of the scannable post types. Hooked to "save_post"/"delete_post".
169 + *
170 + * @param int $post_id Post ID being saved/deleted.
171 + * @param WP_Post|null $post Optional. The post object, to avoid a redundant get_post() lookup.
172 + * @return void
173 + */
174 + public function maybe_invalidate_cache( int $post_id, ?WP_Post $post = null ): void {
175 + if ( null === $post ) {
176 + $post = get_post( $post_id );
132 177 }
133 178
134 - if (! ($post instanceof WP_Post)) {
179 + if ( ! ( $post instanceof WP_Post ) ) {
135 180 return;
136 181 }
137 182
138 - if (in_array($post->post_type, $this->get_scannable_post_types(), true)) {
183 + if ( in_array( $post->post_type, $this->get_scannable_post_types(), true ) ) {
139 184 $this->invalidate_cache();
140 185 }
141 186 }
142 187
143 - public function invalidate_cache(): void
144 - {
145 - wp_cache_delete(self::CACHE_KEY, self::CACHE_GROUP);
188 + /**
189 + * Clears the inline-table scan cache.
190 + *
191 + * @return void
192 + */
193 + public function invalidate_cache(): void {
194 + wp_cache_delete( self::CACHE_KEY, self::CACHE_GROUP );
146 195 }
147 196
148 - public function resolve_shortcode_id(array $attrs, string $block_id): string
149 - {
150 - $shortcode_id = (string) ($attrs['shortId'] ?? '');
197 + /**
198 + * Resolves a block's short shortcode ID: its stored "shortId" attribute if
199 + * present, otherwise a deterministic 6-digit hash derived from its blockID.
200 + *
201 + * @param array $attrs Block attributes.
202 + * @param string $block_id Block's own ID (blockID attribute), used as the hash source.
203 + * @return string The resolved shortcode ID, or an empty string if $block_id is also empty.
204 + */
205 + public function resolve_shortcode_id( array $attrs, string $block_id ): string {
206 + $shortcode_id = (string) ( $attrs['shortId'] ?? '' );
151 207
152 - if ('' !== $shortcode_id) {
208 + if ( '' !== $shortcode_id ) {
153 209 return $shortcode_id;
154 210 }
155 211
156 - if ('' === $block_id) {
212 + if ( '' === $block_id ) {
157 213 return '';
158 214 }
159 215
160 216 $hash = 0;
161 217
162 - foreach (str_split($block_id) as $char) {
163 - $hash = (($hash * 31) + ord($char)) & 0x7FFFFFFF;
218 + foreach ( str_split( $block_id ) as $char ) {
219 + $hash = ( ( $hash * 31 ) + ord( $char ) ) & 0x7FFFFFFF;
164 220 }
165 221
166 - return str_pad((string) ($hash % 1000000), 6, '0', STR_PAD_LEFT);
222 + return str_pad( (string) ( $hash % 1000000 ), 6, '0', STR_PAD_LEFT );
167 223 }
168 224
169 - private function group_inline_tables_by_source(array $inline_tables): array
170 - {
225 + /**
226 + * Group flat inline-table records by their source post ID.
227 + *
228 + * @param array $inline_tables Flat list of inline table records from get_all_inline_block_tables().
229 + * @return array<int,array> Records grouped by source_id, each with a "blocks" sub-array.
230 + */
231 + private function group_inline_tables_by_source( array $inline_tables ): array {
171 232 $grouped = array();
172 233
173 - foreach ($inline_tables as $table) {
234 + foreach ( $inline_tables as $table ) {
174 235 $sid = (int) $table['source_id'];
175 236
176 - if (! isset($grouped[$sid])) {
177 - $grouped[$sid] = array(
237 + if ( ! isset( $grouped[ $sid ] ) ) {
238 + $grouped[ $sid ] = array(
178 239 'source_id' => $sid,
179 240 'source_title' => $table['source_title'],
180 241 'source_type' => $table['source_type'],
181 242 'source_author' => $table['source_author'],
@@ -183,9 +244,9 @@
183 244 'blocks' => array(),
184 245 );
185 246 }
186 247
187 - $grouped[$sid]['blocks'][] = array(
248 + $grouped[ $sid ]['blocks'][] = array(
188 249 'block_name' => $table['block_name'],
189 250 'block_id' => $table['block_id'],
190 251 'shortcode_id' => $table['shortcode_id'],
191 252 );
@@ -193,9 +254,14 @@
193 254
194 255 return $grouped;
195 256 }
196 257
197 - private function store_cache(array $results): void
198 - {
199 - wp_cache_set(self::CACHE_KEY, $results, self::CACHE_GROUP, self::CACHE_TTL);
258 + /**
259 + * Stores a scan result set in the object cache.
260 + *
261 + * @param array $results Result set from get_all_inline_block_tables().
262 + * @return void
263 + */
264 + private function store_cache( array $results ): void {
265 + wp_cache_set( self::CACHE_KEY, $results, self::CACHE_GROUP, self::CACHE_TTL );
200 266 }
201 267 }