PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 3.4.3
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v3.4.3
3.4.3 3.4.2 3.4.1 3.4.0 3.3.9 3.3.8 3.3.7 3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 2.3.1 All 196 releases
convertkit / includes / blocks / helpers / class-convertkit-content-post-helper.php

class-convertkit-content-post-helper.php in Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages 3.4.3, at includes/blocks/helpers/class-convertkit-content-post-helper.php

308 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ConvertKit Content Post Helper class.
4 *
5 * @package ConvertKit
6 * @author ConvertKit
7 */
8
9 /**
10 * Mechanism-agnostic helper to find, insert, update and delete a Kit element
11 * (Broadcast, Form, Form Trigger, Product) within a WordPress Post's content.
12 *
13 * This is the entry point used by the Content MCP abilities. It decides how the
14 * given Post stores its content — Gutenberg blocks, Classic editor / shortcode
15 * markup — and delegates to the appropriate mechanism-specific helper:
16 *
17 * - ConvertKit_Block_Post_Helper for block-based content.
18 *
19 * Callers pass an element name (e.g. `form`); this class applies the correct
20 * prefix for the chosen mechanism (`convertkit/form` for blocks,
21 * `convertkit_form` for shortcodes).
22 *
23 * Page builders (Elementor, etc.) store their content outside post_content and
24 * are not supported; a WP_Error is returned for posts built with one.
25 *
26 * @package ConvertKit
27 * @author ConvertKit
28 */
29 class ConvertKit_Content_Post_Helper {
30
31 /**
32 * Finds all occurrences of the given Kit element in a Post's content.
33 *
34 * @since 3.4.0
35 *
36 * @param int $post_id Post ID.
37 * @param string $element_name Kit Element name (e.g. `form`), without prefix.
38 * @return WP_Error|array
39 */
40 public static function find( $post_id, $element_name ) {
41
42 // Determine how this post stores its content.
43 $mechanism = self::detect_mechanism( $post_id );
44 if ( is_wp_error( $mechanism ) ) {
45 return $mechanism;
46 }
47
48 // Find the element in the post, depending on the mechanism.
49 // A switch is used as shortcodes and other mechanisms will be supported in the future.
50 switch ( $mechanism ) {
51 case 'block':
52 return ConvertKit_Block_Post_Helper::find(
53 $post_id,
54 'convertkit/' . $element_name
55 );
56
57 case 'shortcode':
58 return ConvertKit_Shortcode_Post_Helper::find(
59 $post_id,
60 'convertkit_' . $element_name
61 );
62 }
63
64 return self::unsupported_mechanism_error( $mechanism );
65
66 }
67
68 /**
69 * Inserts a new occurrence of the given Kit Element into a Post's content.
70 *
71 * @since 3.4.0
72 *
73 * @param int $post_id Post ID.
74 * @param string $element_name Kit Element name (e.g. `form`), without prefix.
75 * @param array $attrs Element attributes.
76 * @param string $position One of 'prepend', 'append', 'index'.
77 * @param int $index Zero-based top-level index; only used when $position is 'index'.
78 * @return WP_Error|array
79 */
80 public static function insert( $post_id, $element_name, $attrs, $position = 'append', $index = 0 ) {
81
82 // Determine how this post stores its content.
83 $mechanism = self::detect_mechanism( $post_id );
84 if ( is_wp_error( $mechanism ) ) {
85 return $mechanism;
86 }
87
88 // Insert the element into the post, depending on the mechanism.
89 switch ( $mechanism ) {
90 case 'block':
91 return ConvertKit_Block_Post_Helper::insert(
92 $post_id,
93 'convertkit/' . $element_name,
94 $attrs,
95 $position,
96 $index
97 );
98
99 case 'shortcode':
100 return ConvertKit_Shortcode_Post_Helper::insert(
101 $post_id,
102 'convertkit_' . $element_name,
103 $attrs,
104 $position,
105 $index
106 );
107 }
108
109 return self::unsupported_mechanism_error( $mechanism );
110
111 }
112
113 /**
114 * Updates the attributes of an existing occurrence of the given Kit Element
115 * in a Post's content.
116 *
117 * @since 3.4.0
118 *
119 * @param int $post_id Post ID.
120 * @param string $element_name Kit Element name (e.g. `form`), without prefix.
121 * @param int $occurrence_index Zero-based occurrence index to update.
122 * @param array $attrs Element attributes.
123 * @return WP_Error|array
124 */
125 public static function update( $post_id, $element_name, $occurrence_index, $attrs ) {
126
127 // Determine how this post stores its content.
128 $mechanism = self::detect_mechanism( $post_id );
129 if ( is_wp_error( $mechanism ) ) {
130 return $mechanism;
131 }
132
133 // Updates the existing occurrence of the element in the post, depending on the mechanism.
134 switch ( $mechanism ) {
135 case 'block':
136 return ConvertKit_Block_Post_Helper::update(
137 $post_id,
138 'convertkit/' . $element_name,
139 $occurrence_index,
140 $attrs
141 );
142
143 case 'shortcode':
144 return ConvertKit_Shortcode_Post_Helper::update(
145 $post_id,
146 'convertkit_' . $element_name,
147 $occurrence_index,
148 $attrs
149 );
150 }
151
152 return self::unsupported_mechanism_error( $mechanism );
153
154 }
155
156 /**
157 * Deletes a specific occurrence of the given Kit Element from a Post's
158 * content.
159 *
160 * @since 3.4.0
161 *
162 * @param int $post_id Post ID.
163 * @param string $element_name Kit Element name (e.g. `form`), without prefix.
164 * @param int $occurrence_index Zero-based occurrence index to delete.
165 * @return WP_Error|array
166 */
167 public static function delete( $post_id, $element_name, $occurrence_index ) {
168
169 // Determine how this post stores its content.
170 $mechanism = self::detect_mechanism( $post_id );
171 if ( is_wp_error( $mechanism ) ) {
172 return $mechanism;
173 }
174
175 // Delete the element from the post, depending on the mechanism.
176 // A switch is used as shortcodes and other mechanisms will be supported in the future.
177 switch ( $mechanism ) {
178 case 'block':
179 return ConvertKit_Block_Post_Helper::delete(
180 $post_id,
181 'convertkit/' . $element_name,
182 $occurrence_index
183 );
184
185 case 'shortcode':
186 return ConvertKit_Shortcode_Post_Helper::delete(
187 $post_id,
188 'convertkit_' . $element_name,
189 $occurrence_index
190 );
191 }
192
193 return self::unsupported_mechanism_error( $mechanism );
194
195 }
196
197 /**
198 * Determines how the given Post stores its content.
199 *
200 * Returns one of:
201 * - 'block' The Post uses Gutenberg blocks.
202 * - 'shortcode' The Post uses Classic editor / shortcode markup.
203 * - WP_Error The Post does not exist, or is built with an unsupported
204 * page builder.
205 *
206 * Page builders are checked first, because a page builder typically leaves
207 * post_content empty (or a non-authoritative fallback) and stores its real
208 * content in post meta. Writing a block or shortcode into post_content for
209 * such a Post would have no visible effect, so we refuse rather than fail
210 * silently.
211 *
212 * @since 3.4.0
213 *
214 * @param int $post_id Post ID.
215 * @return string|WP_Error
216 */
217 private static function detect_mechanism( $post_id ) {
218
219 // Get Post.
220 $post = get_post( $post_id );
221 if ( ! $post ) {
222 return new WP_Error(
223 'convertkit_content_post_helper_post_not_found',
224 /* translators: %d: post ID */
225 sprintf( __( 'No post exists with ID %d.', 'convertkit' ), $post_id )
226 );
227 }
228
229 // Bail if the Post is built with a page builder, as these store their
230 // content outside post_content.
231 $page_builder = self::detect_page_builder( $post_id );
232 if ( $page_builder ) {
233 return new WP_Error(
234 'convertkit_content_post_helper_page_builder_unsupported',
235 sprintf(
236 /* translators: %s: page builder name */
237 __( 'This content is built with %s, which is not yet supported. Add the Kit Element using the page builder editor instead.', 'convertkit' ),
238 $page_builder
239 )
240 );
241 }
242
243 // Block-based content if the Post contains block markup; otherwise
244 // treat it as Classic editor / shortcode content. An empty Post also
245 // falls through to 'shortcode' — a shortcode renders correctly in
246 // both Classic and block editors, so this is a safe default.
247 return has_blocks( $post->post_content ) ? 'block' : 'shortcode';
248
249 }
250
251 /**
252 * Returns the human-readable name of the page builder used to build the
253 * given Post, or false if no supported page builder is detected.
254 *
255 * @since 3.4.0
256 *
257 * @param int $post_id Post ID.
258 * @return string|false
259 */
260 private static function detect_page_builder( $post_id ) {
261
262 // Elementor stores its content in the _elementor_data post meta key,
263 // and flags edited posts via _elementor_edit_mode.
264 if ( 'builder' === get_post_meta( $post_id, '_elementor_edit_mode', true ) ) {
265 return 'Elementor';
266 }
267
268 /**
269 * Filters the detected page builder for a Post.
270 *
271 * Return a non-empty string (the page builder's name) to mark the Post
272 * as built with an unsupported page builder, causing the Content MCP
273 * abilities to return an error rather than writing to post_content.
274 *
275 * @since 3.4.0
276 *
277 * @param string|false $page_builder Detected page builder name, or false.
278 * @param int $post_id Post ID.
279 */
280 return apply_filters( 'convertkit_content_post_helper_detect_page_builder', false, $post_id );
281
282 }
283
284 /**
285 * Returns a WP_Error for an unrecognised content mechanism. Acts as a
286 * defensive fallback; detect_mechanism() should only ever return a known
287 * mechanism or a WP_Error.
288 *
289 * @since 3.4.0
290 *
291 * @param string $mechanism The unrecognised mechanism.
292 * @return WP_Error
293 */
294 private static function unsupported_mechanism_error( $mechanism ) {
295
296 return new WP_Error(
297 'convertkit_content_post_helper_unsupported_mechanism',
298 sprintf(
299 /* translators: %s: mechanism identifier */
300 __( 'Unsupported content mechanism: %s.', 'convertkit' ),
301 $mechanism
302 )
303 );
304
305 }
306
307 }
308