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
← All changes | includes/class-convertkit-broadcasts-importer.php +362 -120 2.2.93.4.3 View file →
@@ -23,8 +23,35 @@
23 23 */
24 24 private $broadcasts_settings = false;
25 25
26 26 /**
27 + * Holds the Media Library class.
28 + *
29 + * @since 2.6.3
30 + *
31 + * @var bool|ConvertKit_Media_Library
32 + */
33 + private $media_library = false;
34 +
35 + /**
36 + * Holds the Settings class.
37 + *
38 + * @since 2.6.4
39 + *
40 + * @var bool|ConvertKit_Settings
41 + */
42 + private $settings = false;
43 +
44 + /**
45 + * Holds the Logging class.
46 + *
47 + * @since 2.6.4
48 + *
49 + * @var bool|ConvertKit_Log
50 + */
51 + private $log = false;
52 +
53 + /**
27 54 * Constructor. Registers actions and filters to output ConvertKit Forms and Landing Pages
28 55 * on the frontend web site.
29 56 *
30 57 * @since 2.2.9
@@ -30,8 +57,13 @@
30 57 * @since 2.2.9
31 58 */
32 59 public function __construct() {
33 60
61 + // Initialize required classes.
62 + $this->broadcasts_settings = new ConvertKit_Settings_Broadcasts();
63 + $this->media_library = new ConvertKit_Media_Library();
64 + $this->settings = new ConvertKit_Settings();
65 +
34 66 // Create WordPress Posts when the ConvertKit Posts Resource is refreshed.
35 67 add_action( 'convertkit_resource_refreshed_posts', array( $this, 'refresh' ) );
36 68
37 69 }
@@ -47,13 +79,8 @@
47 79 * @param array $broadcasts Broadcasts.
48 80 */
49 81 public function refresh( $broadcasts ) {
50 82
51 - // Initialize required classes.
52 - $this->broadcasts_settings = new ConvertKit_Settings_Broadcasts();
53 - $settings = new ConvertKit_Settings();
54 - $log = new ConvertKit_Log( CONVERTKIT_PLUGIN_PATH );
55 -
56 83 // Bail if Broadcasts to Posts are disabled.
57 84 if ( ! $this->broadcasts_settings->enabled() ) {
58 85 return;
59 86 }
@@ -62,111 +89,203 @@
62 89 if ( ! count( $broadcasts ) ) {
63 90 return;
64 91 }
65 92
66 - // Bail if the Plugin API keys have not been configured.
67 - if ( ! $settings->has_api_key_and_secret() ) {
68 - return;
93 + foreach ( $broadcasts as $broadcast_id => $broadcast ) {
94 + // If a WordPress Post exists for this Broadcast ID, we previously imported it - skip it.
95 + if ( $this->broadcast_exists_as_post( $broadcast_id ) ) {
96 + $this->maybe_log( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . ' already exists as a WordPress Post. Skipping...' );
97 + continue;
98 + }
99 +
100 + // Skip if the published_at date is older than the 'Earliest Date' setting.
101 + if ( strtotime( $broadcast['published_at'] ) < strtotime( $this->broadcasts_settings->published_at_min_date() ) ) {
102 + $this->maybe_log( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . ' published_at date is before ' . $this->broadcasts_settings->published_at_min_date() . '. Skipping...' );
103 + continue;
104 + }
105 +
106 + // Import the broadcast.
107 + $this->import_broadcast(
108 + $broadcast_id,
109 + $this->broadcasts_settings->post_status(),
110 + $this->broadcasts_settings->author_id(),
111 + $this->broadcasts_settings->category_id(),
112 + $this->broadcasts_settings->import_thumbnail(),
113 + $this->broadcasts_settings->import_images(),
114 + $this->broadcasts_settings->no_styles()
115 + );
69 116 }
70 117
118 + }
119 +
120 +
121 +
122 + /**
123 + * Imports the given Kit Broadcast ID to a new WordPress Post.
124 + *
125 + * @since 2.6.4
126 + *
127 + * @param int $broadcast_id Broadcast ID.
128 + * @param string $post_status WordPress Post Status to save Post as (publish,draft etc).
129 + * @param int $author_id WordPress User ID to assign as the author of the Post.
130 + * @param bool|int $category_id WordPress Category to assign to the Post.
131 + * @param bool $import_thumbnail Store Broadcast's thumbnail as the WordPress Post's Featured Image.
132 + * @param bool $import_images Store Broadcast's inline images in the Media Library.
133 + * @param bool $disable_styles Remove CSS styles and layout elements from the Broadcast content.
134 + *
135 + * @return WP_Error|int
136 + */
137 + public function import_broadcast( $broadcast_id, $post_status = 'publish', $author_id = 1, $category_id = false, $import_thumbnail = false, $import_images = false, $disable_styles = false ) {
138 +
139 + // Bail if the Plugin Access Token has not been configured.
140 + if ( ! $this->settings->has_access_and_refresh_token() ) {
141 + return new WP_Error(
142 + 'convertkit_broadcasts_importer_error',
143 + __( 'No Access Token specified in Plugin Settings', 'convertkit' )
144 + );
145 + }
146 +
71 147 // Initialize the API.
72 - $api = new ConvertKit_API( $settings->get_api_key(), $settings->get_api_secret(), $settings->debug_enabled() );
148 + $api = new ConvertKit_API_V4(
149 + CONVERTKIT_OAUTH_CLIENT_ID,
150 + CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI,
151 + $this->settings->get_access_token(),
152 + $this->settings->get_refresh_token(),
153 + $this->settings->debug_enabled(),
154 + 'broadcasts_importer'
155 + );
73 156
74 157 // Check that we're using the ConvertKit WordPress Libraries 1.3.8 or higher.
75 158 // If another ConvertKit Plugin is active and out of date, its libraries might
76 159 // be loaded that don't have this method.
77 - if ( ! method_exists( $api, 'get_post' ) ) {
78 - return;
160 + if ( ! method_exists( $api, 'get_post' ) ) { // @phpstan-ignore-line Older WordPress Libraries won't have this function.
161 + return new WP_Error(
162 + 'convertkit_broadcasts_importer_error',
163 + __( 'Kit WordPress Libraries 1.3.7 or older detected, missing the `get_post` method.', 'convertkit' )
164 + );
79 165 }
80 166
81 - // Iterate through each Broadcast.
82 - foreach ( $broadcasts as $broadcast_id => $broadcast ) {
83 - // If a WordPress Post exists for this Broadcast ID, we previously imported it - skip it.
84 - if ( $this->broadcast_exists_as_post( $broadcast_id ) ) {
85 - if ( $settings->debug_enabled() ) {
86 - $log->add( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . ' already exists as a WordPress Post. Skipping...' );
87 - }
88 - continue;
89 - }
167 + // Fetch Broadcast's content.
168 + // We need to query wordpress/posts/{id} to fetch the full Broadcast information and content.
169 + $broadcast = $api->get_post( $broadcast_id );
90 170
91 - // Fetch Broadcast's content.
92 - // We need to query wordpress/posts/{id} to fetch the full Broadcast information and content.
93 - $broadcast = $api->get_post( $broadcast_id );
171 + // Unset API class.
172 + unset( $api );
94 173
95 - // Skip if an error occured fetching the Broadcast.
96 - if ( is_wp_error( $broadcast ) ) {
97 - if ( $settings->debug_enabled() ) {
98 - $log->add( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Error fetching from API: ' . $broadcast->get_error_message() );
99 - }
100 - continue;
101 - }
174 + // Bail if an error occurred fetching the Broadcast.
175 + if ( is_wp_error( $broadcast ) ) {
176 + $this->maybe_log( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Error fetching from API: ' . $broadcast->get_error_message() );
177 + return $broadcast;
178 + }
102 179
103 - // Skip if the published_at date is older than the 'Earliest Date' setting.
104 - if ( strtotime( $broadcast['published_at'] ) < strtotime( $this->broadcasts_settings->published_at_min_date() ) ) {
105 - if ( $settings->debug_enabled() ) {
106 - $log->add( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . ' published_at date is before ' . $this->broadcasts_settings->published_at_min_date() . '. Skipping...' );
107 - }
108 - continue;
109 - }
180 + // Create Post as a draft, without content or a Featured Image.
181 + // This gives us a Post ID we can then use if we need to import
182 + // the Featured Image and/or Broadcast images to the Media Library,
183 + // storing them against the Post ID just created.
184 + $post_id = wp_insert_post(
185 + $this->build_post_args(
186 + $broadcast,
187 + $author_id,
188 + $category_id
189 + ),
190 + true
191 + );
110 192
111 - // Create Post as a draft.
112 - $post_id = wp_insert_post(
113 - $this->build_post_args(
114 - $broadcast,
115 - $this->broadcasts_settings->author_id(),
116 - $this->broadcasts_settings->category_id()
193 + // Bail if an error occurred.
194 + if ( is_wp_error( $post_id ) ) {
195 + $this->maybe_log( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Error on wp_insert_post(): ' . $post_id->get_error_message() );
196 + return $post_id;
197 + }
198 +
199 + // Parse the Broadcast's content, storing it in the Post.
200 + $post_id = wp_update_post(
201 + array(
202 + 'ID' => $post_id,
203 + 'post_content' => $this->parse_broadcast_content(
204 + $post_id,
205 + $broadcast['content'],
206 + $broadcast['title'],
207 + $import_images,
208 + $disable_styles
117 209 ),
118 - true
119 - );
210 + ),
211 + true
212 + );
120 213
121 - // Skip if an error occured.
122 - if ( is_wp_error( $post_id ) ) {
123 - if ( $settings->debug_enabled() ) {
124 - $log->add( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Error on wp_insert_post(): ' . $post_id->get_error_message() );
125 - }
126 - continue;
214 + // Bail if an error occurred updating the Post.
215 + if ( is_wp_error( $post_id ) ) {
216 + $this->maybe_log( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Error on wp_update_post() when adding Broadcast content: ' . $post_id->get_error_message() );
217 + return $post_id;
218 + }
219 +
220 + // If a Product is specified, apply it as the Restrict Content setting.
221 + if ( $broadcast['is_paid'] && $broadcast['product_id'] ) {
222 + // Fetch Post's settings.
223 + $convertkit_post = new ConvertKit_Post( $post_id );
224 + $meta = $convertkit_post->get();
225 +
226 + // Define Restrict Content setting.
227 + $meta['restrict_content'] = 'product_' . $broadcast['product_id'];
228 +
229 + // Save Post's settings.
230 + $convertkit_post->save( $meta );
231 + $this->maybe_log( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Set Restrict Content = ' . $broadcast['product_id'] );
232 + }
233 +
234 + // If the Import Thumbnail setting is enabled, and the Broadcast has an image, save it to the Media Library and link it to the Post.
235 + if ( $import_thumbnail ) {
236 + $result = $this->add_broadcast_image_to_post( $broadcast, $post_id );
237 +
238 + if ( is_wp_error( $result ) ) {
239 + $this->maybe_log( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Error on add_broadcast_image_to_post(): ' . $result->get_error_message() );
127 240 }
241 + } else {
242 + $this->maybe_log( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Skipping thumbnail.' );
243 + }
128 244
129 - // If a Product is specified, apply it as the Restrict Content setting.
130 - if ( $broadcast['is_paid'] && $broadcast['product_id'] ) {
131 - // Fetch Post's settings.
132 - $convertkit_post = new ConvertKit_Post( $post_id );
133 - $meta = $convertkit_post->get();
245 + // Transition the Post to the defined Post Status in the settings, now that the image has been added to it.
246 + $post_id = wp_update_post(
247 + array(
248 + 'ID' => $post_id,
249 + 'post_status' => $post_status,
250 + ),
251 + true
252 + );
134 253
135 - // Define Restrict Content setting.
136 - $meta['restrict_content'] = 'product_' . $broadcast['product_id'];
254 + // Maybe log if an error occurred updating the Post to the publish status.
255 + if ( is_wp_error( $post_id ) ) {
256 + $this->maybe_log( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Error on wp_update_post() when transitioning post status from draft to publish: ' . $post_id->get_error_message() );
257 + return $post_id;
258 + }
137 259
138 - // Save Post's settings.
139 - $convertkit_post->save( $meta );
260 + // Import successful.
261 + $this->maybe_log( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Added as Post ID #' . $post_id );
262 + return $post_id;
140 263
141 - if ( $settings->debug_enabled() ) {
142 - $log->add( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Set Restrict Content = ' . $broadcast['product_id'] );
143 - }
144 - }
264 + }
145 265
146 - // If the Broadcast has an image, save it to the Media Library and link it to the Post.
147 - $this->add_broadcast_image_to_post( $broadcast, $post_id );
266 + /**
267 + * Logs the given message if debug logging is enabled
268 + * in the Plugin's settings.
269 + *
270 + * @since 2.6.4
271 + *
272 + * @param string $message Log message.
273 + */
274 + private function maybe_log( $message ) {
148 275
149 - // Publish the draft Post, now that the image has been added to it.
150 - $post_id = wp_update_post(
151 - array(
152 - 'ID' => $post_id,
153 - 'post_status' => 'publish',
154 - ),
155 - true
156 - );
276 + // Don't log if debugging is not enabled.
277 + if ( ! $this->settings->debug_enabled() ) {
278 + return;
279 + }
157 280
158 - // Maybe log if an error occured updating the Post to the publish status.
159 - if ( is_wp_error( $post_id ) ) {
160 - if ( $settings->debug_enabled() ) {
161 - $log->add( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Error on wp_update_post(): ' . $post_id->get_error_message() );
162 - }
163 - }
164 - if ( $settings->debug_enabled() ) {
165 - $log->add( 'ConvertKit_Broadcasts_Importer::refresh(): Broadcast #' . $broadcast_id . '. Added as Post ID #' . $post_id );
166 - }
281 + // Initialize logging class, if not yet initialized.
282 + if ( ! $this->log ) {
283 + $this->log = new ConvertKit_Log( CONVERTKIT_PLUGIN_PATH );
167 284 }
168 285
286 + $this->log->add( $message );
287 +
169 288 }
170 289
171 290 /**
172 291 * Helper method to determine if the given ConvertKit Broadcast already exists
@@ -219,15 +338,17 @@
219 338 $post_args = array(
220 339 'post_type' => 'post',
221 340 'post_title' => $broadcast['title'],
222 341 'post_excerpt' => ( ! is_null( $broadcast['description'] ) ? $broadcast['description'] : '' ),
223 - 'post_content' => $this->parse_broadcast_content( $broadcast['content'] ),
224 342 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', strtotime( $broadcast['published_at'] ) ),
225 343 'post_author' => $author_id,
344 + 'post_name' => $this->generate_permalink( $broadcast['title'] ),
226 345 );
227 346
228 347 // If a Category was supplied, assign the Post to the given Category ID when created.
229 - $post_args['post_category'] = array( $category_id );
348 + if ( $category_id ) {
349 + $post_args['post_category'] = array( $category_id );
350 + }
230 351
231 352 /**
232 353 * Define the wp_insert_post() compatible arguments for importing a ConvertKit Broadcast
233 354 * to a new WordPress Post.
@@ -254,39 +375,175 @@
254 375
255 376 }
256 377
257 378 /**
379 + * Removes emojis from the given string.
380 + *
381 + * @since 2.8.2
382 + *
383 + * @param string $title Broadcast Title.
384 + * @return string
385 + */
386 + public function generate_permalink( $title ) {
387 +
388 + // Remove emojis.
389 + $title = preg_replace( '/[^\p{L}\p{N}\p{P}\s]+/u', '', $title );
390 +
391 + // Return the Permalink.
392 + return sanitize_title( $title );
393 +
394 + }
395 +
396 + /**
258 397 * Parses the given Broadcast's content, removing unnecessary HTML tags and styles.
259 398 *
399 + * If 'Import Images' is enabled in the Plugin settings, imports images to the
400 + * Media Library, replacing the <img> `src` with the WordPress Media Library
401 + * Image URL.
402 + *
260 403 * @since 2.2.9
261 404 *
405 + * @param int $post_id WordPress Post ID.
262 406 * @param string $broadcast_content Broadcast Content.
263 - * @return string Parsed Content.
407 + * @param string $broadcast_title Broadcast Title.
408 + * @param bool $import_images Import images to Media Library.
409 + * @param bool $disable_styles Disable CSS styles in content.
410 + * @return string Parsed Content.
264 411 */
265 - private function parse_broadcast_content( $broadcast_content ) {
412 + private function parse_broadcast_content( $post_id, $broadcast_content, $broadcast_title = '', $import_images = false, $disable_styles = false ) {
266 413
267 414 $content = $broadcast_content;
268 415
416 + // Load the content into the parser.
417 + $parser = new ConvertKit_HTML_Parser( $content );
418 +
419 + // Remove certain elements and their contents, as we never want these to be included in the WordPress Post.
420 + // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
421 +
269 422 // Remove open tracking.
270 - $content = str_replace( '<img src="https://preview.convertkit-mail2.com/open" alt="">', '', $content );
423 + foreach ( $parser->xpath->query( '//img[@src="https://preview.convertkit-mail2.com/open"]' ) as $node ) {
424 + $node->parentNode->removeChild( $node );
425 + }
271 426
272 - // Remove <style> elements.
273 - $content = preg_replace( '/(<style *?>.*?<\/style>)/is', '', $content );
274 - $content = preg_replace( '/(<style>.*?<\/style>)/is', '', $content );
427 + // Remove blank contenteditable table cells.
428 + foreach ( $parser->xpath->query( '//td[@contenteditable="false"]' ) as $node ) {
429 + $node->parentNode->removeChild( $node );
430 + }
275 431
276 - // Remove blank contenteditable table cells.
277 - $content = str_replace( '<td contenteditable="false"></td>', '', $content );
432 + // Remove <style> elements and their contents.
433 + foreach ( $parser->xpath->query( '//style' ) as $node ) {
434 + $node->parentNode->removeChild( $node );
435 + }
278 436
437 + // Remove ck-hide-in-public-posts and their contents.
438 + // This includes the unsubscribe section.
439 + foreach ( $parser->xpath->query( '//div[contains(@class, "ck-hide-in-public-posts")]' ) as $node ) {
440 + $node->parentNode->removeChild( $node );
441 + }
442 +
443 + // Remove ck-poll, as interacting with these results in an error.
444 + foreach ( $parser->xpath->query( '//table[contains(@class, "ck-poll")]' ) as $node ) {
445 + $node->parentNode->removeChild( $node );
446 + }
447 +
448 + // If a H1 through H6 heading matches the Broadcast's title, remove it from the content.
449 + // The Broadcast's title will always display as the WordPress Post title.
450 + for ( $i = 1; $i <= 6; $i++ ) {
451 + foreach ( $parser->xpath->query( '//h' . $i ) as $node ) {
452 + if ( $node->textContent === $broadcast_title ) {
453 + $node->parentNode->removeChild( $node );
454 + }
455 + }
456 + }
457 + // phpcs:enable
458 +
459 + // If the Import Images setting is enabled, iterate through all images within the Broadcast, importing them and changing their
460 + // URLs to the WordPress Media Library hosted versions.
461 + if ( $import_images ) {
462 + foreach ( $parser->xpath->query( '//img' ) as $node ) {
463 + $image = array(
464 + 'src' => $node->getAttribute( 'src' ), // @phpstan-ignore-line
465 + 'alt' => $node->getAttribute( 'alt' ), // @phpstan-ignore-line
466 + );
467 +
468 + // Skip if this image isn't served from https://embed.filekitcdn.com, as it isn't
469 + // a user uploaded image to the Broadcast.
470 + if ( strpos( $image['src'], 'https://embed.filekitcdn.com' ) === false ) {
471 + continue;
472 + }
473 +
474 + // Import Image into the Media Library.
475 + $image_id = $this->media_library->import_remote_image(
476 + $image['src'],
477 + $post_id,
478 + $image['alt']
479 + );
480 +
481 + // If the image could not be imported, serve the original CDN version.
482 + if ( is_wp_error( $image_id ) ) {
483 + continue;
484 + }
485 +
486 + // Get image URL from Media Library.
487 + $image_url = wp_get_attachment_image_src(
488 + $image_id,
489 + 'full'
490 + );
491 +
492 + // Replace this image's `src` attribute with the Media Library Image URL.
493 + $node->setAttribute( 'src', $image_url[0] ); // @phpstan-ignore-line
494 + }
495 + }
496 +
497 + // Save HTML to a string.
498 + $content = $parser->get_body_html();
499 +
500 + // Return content with permitted HTML tags and inline styles included/excluded, depending on the setting.
501 + $content = $this->get_permitted_html( $content, $disable_styles );
502 +
503 + /**
504 + * Parses the given Broadcast's content, removing unnecessary HTML tags and styles.
505 + *
506 + * @since 2.2.9
507 + *
508 + * @param string $content Parsed Content.
509 + * @param int $post_id WordPress Post ID.
510 + * @param string $broadcast_content Broadcast Content.
511 + * @param string $broadcast_title Broadcast Title.
512 + * @param bool $import_images Import images to Media Library.
513 + * @param bool $disable_styles Disable CSS styles in content.
514 + */
515 + $content = apply_filters( 'convertkit_broadcasts_parse_broadcast_content', $content, $post_id, $broadcast_content, $broadcast_title, $import_images, $disable_styles );
516 +
517 + return $content;
518 +
519 + }
520 +
521 + /**
522 + * Returns the given content containing only the permitted HTML tags,
523 + * cleans up empty div elements and removes multiple newlines.
524 + *
525 + * Content contained within non-permitted HTML tags is returned, without
526 + * the HTML tags wrapping the content.
527 + *
528 + * @since 2.4.0
529 + *
530 + * @param string $content HTML Content.
531 + * @param bool $disable_styles Disable styles.
532 + * @return string HTML Content
533 + */
534 + public function get_permitted_html( $content, $disable_styles = false ) {
535 +
279 536 // For PHP 7.4 and lower compatibility, convert permitted HTML tags array to a string
280 537 // for use in strip_tags().
281 - $permitted_html_tags_string = '<' . implode( '><', $this->permitted_html_tags() ) . '>';
538 + $permitted_html_tags_string = '<' . implode( '><', $this->permitted_html_tags( $disable_styles ) ) . '>';
282 539
283 540 // Remove other tags, retaining inner contents.
284 541 // For HTML broadcasts, this will remove e.g. <html>, <head> and <body> tags.
285 542 $content = strip_tags( $content, $permitted_html_tags_string );
286 543
287 - // If Disable Styles is checked, remove inline styles and class attributes from remaining HTML elements.
288 - if ( $this->broadcasts_settings->no_styles() ) {
544 + // If Disable Styles is enabled, remove inline styles and class attributes from remaining HTML elements.
545 + if ( $disable_styles ) {
289 546 $content = preg_replace( '/(<[^>]+) style=".*?"/i', '$1', $content );
290 547 $content = preg_replace( '/(<[^>]+) class=".*?"/i', '$1', $content );
291 548 }
292 549
@@ -296,21 +553,8 @@
296 553 // Remove leading and trailing newlines and spaces, so WordPress doesn't convert these to blank paragraph tags.
297 554 $content = preg_replace( "/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $content );
298 555 $content = trim( $content );
299 556
300 - // Remove unsubscribe section.
301 - $content = preg_replace( '/(<div class="ck-section ck-hide-in-public-posts".*?>.*?<\/tr><\/tbody><\/table>\\n<\/div>\\n)/is', '', $content );
302 -
303 - /**
304 - * Parses the given Broadcast's content, removing unnecessary HTML tags and styles.
305 - *
306 - * @since 2.2.9
307 - *
308 - * @param string $content Parsed Content.
309 - * @param string $broadcast_content Original Broadcast's Content.
310 - */
311 - $content = apply_filters( 'convertkit_broadcasts_parse_broadcast_content', $content, $broadcast_content );
312 -
313 557 return $content;
314 558
315 559 }
316 560
@@ -318,11 +562,12 @@
318 562 * Returns an array of permitted HTML tags to retain in the imported Broadcast.
319 563 *
320 564 * @since 2.2.9
321 565 *
566 + * @param bool $disable_styles Disable styles.
322 567 * @return array
323 568 */
324 - private function permitted_html_tags() {
569 + private function permitted_html_tags( $disable_styles = false ) {
325 570
326 571 // Define HTML tags to retain in the content.
327 572 $permitted_html_tags = array(
328 573 'h1',
@@ -338,13 +583,16 @@
338 583 'u',
339 584 's',
340 585 'a',
341 586 'img',
587 + 'figure',
588 + 'figcaption',
342 589 'br',
590 + 'style', // Deliberate; we'll use DOMDocument to remove inline styles and their contents.
343 591 );
344 592
345 - // If Disable Styles isn't selected, include layout tags.
346 - if ( ! $this->broadcasts_settings->no_styles() ) {
593 + // If Disable Styles is false, include layout tags.
594 + if ( ! $disable_styles ) {
347 595 $permitted_html_tags = array_merge(
348 596 $permitted_html_tags,
349 597 array(
350 598 'span',
@@ -387,22 +635,16 @@
387 635 if ( empty( $broadcast['thumbnail_url'] ) ) {
388 636 return false;
389 637 }
390 638
391 - // Initialize class.
392 - $media_library = new ConvertKit_Media_Library();
393 -
394 639 // Import Image into the Media Library.
395 - $image_id = $media_library->import_remote_image(
640 + $image_id = $this->media_library->import_remote_image(
396 641 $broadcast['thumbnail_url'],
397 642 $post_id,
398 643 $broadcast['thumbnail_alt']
399 644 );
400 645
401 - // Destroy class.
402 - unset( $media_library );
403 -
404 - // Bail if an error occured.
646 + // Bail if an error occurred.
405 647 if ( is_wp_error( $image_id ) ) {
406 648 return $image_id;
407 649 }
408 650