PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 3.4.5
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v3.4.5
3.4.5 3.4.4 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 All 198 releases
← All changes | includes/class-convertkit-gutenberg.php +241 -10 2.2.9 → 3.4.5 View file →
@@ -31,11 +31,127 @@
31 31
32 32 // Register Gutenberg Blocks.
33 33 add_action( 'init', array( $this, 'add_blocks' ) );
34 34
35 + // Register Gutenberg Plugin Sidebars.
36 + add_action( 'init', array( $this, 'add_plugin_sidebars' ) );
37 +
38 + // Register REST API routes.
39 + add_action( 'rest_api_init', array( $this, 'register_routes' ) );
40 +
41 + // Delete duplicate Post Meta rows before WordPress updates them.
42 + add_filter( 'update_post_metadata', array( $this, 'maybe_delete_duplicate_post_meta' ), 10, 5 );
43 +
35 44 }
36 45
37 46 /**
47 + * Deletes duplicate Post Meta rows for the Plugin's Post Meta key, before WordPress updates them,
48 + * which have been created by third party Plugins, migrations, or other code.
49 + *
50 + * @since 3.4.5
51 + *
52 + * @param null $check Whether to short circuit the update.
53 + * @param int $post_id Post ID.
54 + * @param string $meta_key Meta key.
55 + * @param mixed $meta_value Meta value.
56 + * @param mixed $prev_value Previous meta value to update.
57 + * @return null|bool Whether to short circuit the update.
58 + */
59 + public function maybe_delete_duplicate_post_meta( $check, $post_id, $meta_key, $meta_value, $prev_value ) {
60 +
61 + // Bail if this isn't the Plugin's Post Meta key.
62 + if ( $meta_key !== ConvertKit_Post::POST_META_KEY ) {
63 + return $check;
64 + }
65 +
66 + // Bail if a previous value is specified, as WordPress will only update matching rows.
67 + if ( ! empty( $prev_value ) ) {
68 + return $check;
69 + }
70 +
71 + // Bail if no duplicate rows exist.
72 + $convertkit_post = new ConvertKit_Post( $post_id );
73 + $rows = $convertkit_post->get_meta_rows();
74 + if ( count( $rows ) < 2 ) {
75 + return $check;
76 + }
77 +
78 + // Delete all but the most recent row.
79 + $row = array_pop( $rows );
80 + foreach ( $rows as $duplicate_row ) {
81 + delete_metadata_by_mid( 'post', $duplicate_row->meta_id );
82 + }
83 +
84 + // Restore the Post in the Member Content cache, as deleting the above rows removed it.
85 + $value = maybe_unserialize( $row->meta_value );
86 + WP_ConvertKit()->get_class( 'restrict_content_cache' )->on_meta_change( 0, $post_id, $meta_key, $value );
87 +
88 + // If the remaining row already holds the value WordPress is about to store, tell WordPress
89 + // the update succeeded, as there's nothing to change. Without this, WordPress' own check for
90 + // a single unchanged row returns false, and the block editor still cannot save the Post.
91 + if ( $value === $meta_value ) {
92 + return true;
93 + }
94 +
95 + return $check;
96 +
97 + }
98 +
99 + /**
100 + * Register REST API routes.
101 + *
102 + * @since 3.1.0
103 + */
104 + public function register_routes() {
105 +
106 + // Register route to refresh resources andreturn all blocks registered by the Plugin,
107 + // when the user clicks the refresh button in the Gutenberg editor.
108 + register_rest_route(
109 + 'kit/v1',
110 + '/blocks',
111 + array(
112 + 'methods' => WP_REST_Server::READABLE,
113 +
114 + // Return blocks.
115 + 'callback' => function () {
116 + // Refresh Forms.
117 + $forms = new ConvertKit_Resource_Forms( 'block_edit' );
118 + $result = $forms->refresh();
119 + if ( is_wp_error( $result ) ) {
120 + // Return blocks without refreshing other resources.
121 + return rest_ensure_response( convertkit_get_blocks() );
122 + }
123 +
124 + // Refresh Posts.
125 + $posts = new ConvertKit_Resource_Posts( 'block_edit' );
126 + $result = $posts->refresh();
127 + if ( is_wp_error( $result ) ) {
128 + // Return blocks without refreshing other resources.
129 + return rest_ensure_response( convertkit_get_blocks() );
130 + }
131 +
132 + // Refresh Products.
133 + $products = new ConvertKit_Resource_Products( 'block_edit' );
134 + $result = $products->refresh();
135 + if ( is_wp_error( $result ) ) {
136 + // Return blocks without refreshing other resources.
137 + return rest_ensure_response( convertkit_get_blocks() );
138 + }
139 +
140 + // Return blocks, which will now include the refreshed resources.
141 + return rest_ensure_response( convertkit_get_blocks() );
142 + },
143 +
144 + // Only refresh resources for users who can edit posts.
145 + 'permission_callback' => function () {
146 + return current_user_can( 'edit_posts' );
147 + },
148 + )
149 + );
150 +
151 + }
152 +
153 + /**
38 154 * Registers the ConvertKit Block Category.
39 155 *
40 156 * @since 1.9.6
41 157 *
@@ -50,9 +166,9 @@
50 166 $categories,
51 167 array(
52 168 array(
53 169 'slug' => 'convertkit',
54 - 'title' => 'ConvertKit',
170 + 'title' => 'Kit',
55 171 ),
56 172 )
57 173 );
58 174
@@ -86,12 +202,15 @@
86 202 // Get blocks.
87 203 $blocks = convertkit_get_blocks();
88 204
89 205 // Bail if no blocks are available.
90 - if ( ! is_array( $blocks ) || ! count( $blocks ) ) {
206 + if ( ! count( $blocks ) ) {
91 207 return;
92 208 }
93 209
210 + // Determine the block API version to use for registering blocks.
211 + $block_api_version = $this->get_block_api_version();
212 +
94 213 // Get registered blocks.
95 214 $registered_blocks = array_keys( WP_Block_Type_Registry::get_instance()->get_all_registered() );
96 215
97 216 // Iterate through blocks, registering them.
@@ -97,15 +216,15 @@
97 216 // Iterate through blocks, registering them.
98 217 foreach ( $blocks as $block => $properties ) {
99 218
100 219 // Skip if this block has already been registered.
101 - if ( is_array( $registered_blocks ) && in_array( 'convertkit/' . $block, $registered_blocks, true ) ) {
220 + if ( in_array( 'convertkit/' . $block, $registered_blocks, true ) ) {
102 221 continue;
103 222 }
104 223
105 224 // Register block.
106 225 register_block_type(
107 - 'convertkit/' . $block,
226 + CONVERTKIT_PLUGIN_PATH . '/includes/blocks/v' . (string) $block_api_version . '/' . $block,
108 227 array(
109 228 'attributes' => $properties['attributes'],
110 229 'editor_script' => 'convertkit-gutenberg',
111 230 'render_callback' => array(
@@ -113,13 +232,14 @@
113 232 $properties['render_callback'][1],
114 233 ),
115 234 )
116 235 );
236 +
117 237 }
118 238
119 239 // Enqueue block scripts and styles in the editor view.
120 240 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
121 - add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_styles' ) );
241 + add_action( 'enqueue_block_assets', array( $this, 'enqueue_styles' ) );
122 242
123 243 // Enqueue block scripts and styles in the editor and frontend views.
124 244 add_action( 'enqueue_block_assets', array( $this, 'enqueue_scripts_editor_and_frontend' ) );
125 245 add_action( 'enqueue_block_assets', array( $this, 'enqueue_styles_editor_and_frontend' ) );
@@ -126,8 +246,101 @@
126 246
127 247 }
128 248
129 249 /**
250 + * Registers post meta for any registered plugin sidebars using register_post_meta(),
251 + * so data is saved when using the Gutenberg editor.
252 + *
253 + * @since 3.3.0
254 + */
255 + public function add_plugin_sidebars() {
256 +
257 + // Get plugin sidebars.
258 + $plugin_sidebars = convertkit_get_plugin_sidebars();
259 +
260 + // Bail if no plugin sidebars are available.
261 + if ( ! count( $plugin_sidebars ) ) {
262 + return;
263 + }
264 +
265 + foreach ( $plugin_sidebars as $plugin_sidebar ) {
266 + register_post_meta(
267 + '',
268 + $plugin_sidebar['meta_key'],
269 + array(
270 + 'show_in_rest' => array(
271 + 'schema' => array(
272 + 'type' => 'object',
273 + 'properties' => $plugin_sidebar['attributes'],
274 + ),
275 + ),
276 + 'single' => true,
277 + 'type' => 'object',
278 + 'default' => $plugin_sidebar['default_values'],
279 + 'sanitize_callback' => function ( $meta ) use ( $plugin_sidebar ) {
280 +
281 + // If the value is not an array, return the default values.
282 + if ( ! is_array( $meta ) ) {
283 + return $plugin_sidebar['default_values'];
284 + }
285 +
286 + // Iterate through the attributes and sanitize the meta.
287 + foreach ( $plugin_sidebar['attributes'] as $key => $attribute ) {
288 + $meta[ $key ] = sanitize_text_field( $meta[ $key ] ?? $attribute['default'] );
289 + }
290 +
291 + // If a Form or Landing Page was specified, request a review.
292 + // This can safely be called multiple times, as the review request
293 + // class will ensure once a review request is dismissed by the user,
294 + // it is never displayed again.
295 + if ( $meta['form'] || $meta['landing_page'] ) {
296 + WP_ConvertKit()->get_class( 'review_request' )->request_review();
297 + }
298 +
299 + // Return the sanitized meta.
300 + return $meta;
301 +
302 + },
303 + 'auth_callback' => function () use ( $plugin_sidebar ) {
304 +
305 + return current_user_can( $plugin_sidebar['minimum_capability'] );
306 +
307 + },
308 + )
309 + );
310 + }
311 +
312 + }
313 +
314 + /**
315 + * Determines the block API version to use for registering blocks.
316 + *
317 + * @since 3.2.0
318 + *
319 + * @return int Block API version.
320 + */
321 + public function get_block_api_version() {
322 +
323 + // Determine the block API version to use for registering blocks.
324 + // WordPress supports Version 3 from WordPress 6.3:
325 + // https://developer.wordpress.org/block-editor/reference-guides/block-api/block-api-versions/.
326 + $block_api_version = ( version_compare( get_bloginfo( 'version' ), '6.3', '>=' ) ? 3 : 2 );
327 +
328 + /**
329 + * Determine the block API version to use for registering blocks.
330 + *
331 + * @since 3.1.4
332 + *
333 + * @param int $block_api_version Block API version.
334 + * @return int Block API version.
335 + */
336 + $block_api_version = apply_filters( 'convertkit_gutenberg_block_api_version', $block_api_version );
337 +
338 + return absint( $block_api_version );
339 +
340 + }
341 +
342 + /**
130 343 * Enqueues scripts for Gutenberg blocks in the editor view.
131 344 *
132 345 * @since 1.9.6
133 346 */
@@ -141,19 +354,37 @@
141 354 // Get settings.
142 355 $settings = new ConvertKit_Settings();
143 356
144 357 // Get blocks and block toolbar buttons.
145 - $blocks = convertkit_get_blocks();
146 - $block_formatters = convertkit_get_block_formatters();
358 + $blocks = convertkit_get_blocks();
359 + $block_formatters = convertkit_get_block_formatters();
360 + $pre_publish_actions = convertkit_get_pre_publish_actions();
361 + $plugin_sidebars = convertkit_get_plugin_sidebars();
147 362
148 363 // Enqueue Gutenberg Javascript, and set the blocks data.
149 364 wp_enqueue_script( 'convertkit-gutenberg', CONVERTKIT_PLUGIN_URL . 'resources/backend/js/gutenberg.js', array( 'jquery' ), CONVERTKIT_PLUGIN_VERSION, true );
150 365 wp_localize_script( 'convertkit-gutenberg', 'convertkit_blocks', $blocks );
366 +
367 + // If pre-publish actions are available, set the data.
368 + if ( count( $pre_publish_actions ) ) {
369 + wp_localize_script( 'convertkit-gutenberg', 'convertkit_pre_publish_actions', $pre_publish_actions );
370 + }
371 +
372 + // If plugin sidebars are available, set the data.
373 + if ( count( $plugin_sidebars ) ) {
374 + wp_localize_script( 'convertkit-gutenberg', 'convertkit_plugin_sidebars', $plugin_sidebars );
375 + }
376 +
377 + // Set the Gutenberg data.
151 378 wp_localize_script(
152 379 'convertkit-gutenberg',
153 380 'convertkit_gutenberg',
154 381 array(
155 - 'get_blocks_nonce' => wp_create_nonce( 'convertkit_get_blocks' ),
382 + 'ajaxurl' => rest_url( 'kit/v1/blocks' ),
383 + 'block_api_version' => $this->get_block_api_version(),
384 + 'get_blocks_nonce' => wp_create_nonce( 'wp_rest' ),
385 + 'refresh_resources_url' => rest_url( 'kit/v1/resources/refresh/' ),
386 + 'refresh_resources_nonce' => wp_create_nonce( 'wp_rest' ),
156 387 )
157 388 );
158 389
159 390 // Enqueue Gutenberg Block Toolbar Javascript, and set the block toolbar buttons data.
@@ -181,10 +412,10 @@
181 412 * @since 1.9.6.9
182 413 */
183 414 public function enqueue_styles() {
184 415
185 - // Bail if request isn't for the Admin or a Frontend Editor.
186 - if ( ! WP_ConvertKit()->is_admin_or_frontend_editor() ) {
416 + // Bail if request isn't for the Admin.
417 + if ( ! is_admin() ) {
187 418 return;
188 419 }
189 420
190 421 /**