Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cc4198c
Broadcasts: Export: Use Post Excerpt as Preview Text
n7studios Oct 19, 2026
cfc6f15
Fix failing integration test
n7studios Oct 20, 2026
524c610
Merge branch 'main' into broadcasts-export-preview-text
n7studios Oct 23, 2026
aba06b0
Broadcasts: Export: Greeting, Sign-off and Read on the Web settings
n7studios Oct 26, 2026
b982695
Broadcasts: Export: Use Featured Image as Thumbnail
n7studios Oct 26, 2026
ac35dee
Tests: Improve resource sorting assertions
n7studios Oct 28, 2026
c2c597e
Coding standards
n7studios Oct 28, 2026
bc9da5a
Merge branch 'main' into broadcasts-export-preview-text
n7studios Oct 28, 2026
666b90b
Merge branch 'main' into tests-resource-order-assertion
n7studios Oct 28, 2026
4c6c91b
Merge branch 'tests-resource-order-assertion' into broadcasts-export-…
n7studios Oct 28, 2026
4911568
Merge branch 'broadcasts-export-preview-text' into broadcasts-export-…
n7studios Oct 28, 2026
1893f4b
Merge branch 'broadcasts-export-greeting' into broadcasts-export-feat…
n7studios Oct 28, 2026
09f3a77
Fix test helper
n7studios Oct 28, 2026
6aca142
Merge branch 'tests-resource-order-assertion' into broadcasts-export-…
n7studios Oct 28, 2026
26ce274
Merge remote-tracking branch 'origin/broadcasts-export-preview-text' …
n7studios Oct 28, 2026
cc3aed1
Merge branch 'broadcasts-export-greeting' into broadcasts-export-feat…
n7studios Oct 28, 2026
f60b8de
Broadcasts: Rename Creator Profile to Newsletter site
n7studios Oct 28, 2026
b1caebb
Sanitize Greeting and Sign-off on save only
n7studios Oct 30, 2026
7229911
Merge pull request #1261 from Kit/broadcasts-export-featured-image
n7studios Oct 30, 2026
d26171e
Merge pull request #1260 from Kit/broadcasts-export-greeting
n7studios Oct 30, 2026
4104c7c
Merge pull request #1251 from Kit/broadcasts-export-preview-text
n7studios Oct 30, 2026
5557be4
Merge pull request #1265 from Kit/rename-creator-profile-newsletter-site
n7studios Oct 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 117 additions & 1 deletion admin/section/class-convertkit-admin-section-broadcasts.php
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,46 @@ public function register_fields() {
array(
'name' => 'export_public',
'label_for' => 'export_public',
'label' => __( 'If enabled, draft broadcasts will be published to your Kit Creator Profile and Landing Pages when sent.', 'convertkit' ),
'label' => __( 'If enabled, draft broadcasts will be published to your Kit Newsletter site and Landing Pages when sent.', 'convertkit' ),
)
);

add_settings_field(
'export_greeting',
__( 'Greeting', 'convertkit' ),
array( $this, 'export_greeting_callback' ),
$this->settings_key,
$this->name . '-export',
array(
'name' => 'export_greeting',
'label_for' => 'export_greeting',
'description' => __( 'Optional. Added to the start of draft broadcasts. Supports HTML and Liquid, for example: Hi {{ subscriber.first_name | default: "there" }},', 'convertkit' ),
)
);

add_settings_field(
'export_sign_off',
__( 'Sign-off', 'convertkit' ),
array( $this, 'export_sign_off_callback' ),
$this->settings_key,
$this->name . '-export',
array(
'name' => 'export_sign_off',
'label_for' => 'export_sign_off',
'description' => __( 'Optional. Added to the end of draft broadcasts. Supports HTML and Liquid.', 'convertkit' ),
)
);

add_settings_field(
'export_web_link',
__( 'Read on the Web', 'convertkit' ),
array( $this, 'export_web_link_callback' ),
$this->settings_key,
$this->name . '-export',
array(
'name' => 'export_web_link',
'label_for' => $this->settings_key . '_export_web_link',
'description' => __( 'Adds a link to read the post on your site to draft broadcasts. Only added once the post is published.', 'convertkit' ),
)
);

Expand Down Expand Up @@ -720,6 +759,76 @@ public function export_public_callback( $args ) {

}

/**
* Renders the input for the Greeting setting.
*
* @since 3.4.8
*
* @param array $args Setting field arguments (name,description).
*/
public function export_greeting_callback( $args ) {

// Output field.
$this->output_textarea_field(
$args['name'],
esc_textarea( $this->settings->export_greeting() ),
$args['description'],
array(
'large-text',
'enabled_export',
)
);

}

/**
* Renders the input for the Sign-off setting.
*
* @since 3.4.8
*
* @param array $args Setting field arguments (name,description).
*/
public function export_sign_off_callback( $args ) {

// Output field.
$this->output_textarea_field(
$args['name'],
esc_textarea( $this->settings->export_sign_off() ),
$args['description'],
array(
'large-text',
'enabled_export',
)
);

}

/**
* Renders the input for the Read on the Web setting.
*
* @since 3.4.8
*
* @param array $args Setting field arguments (name,description).
*/
public function export_web_link_callback( $args ) {

// Output field.
$this->output_select_field(
$args['name'],
$this->settings->export_web_link(),
array(
'' => esc_html__( 'None', 'convertkit' ),
'top' => esc_html__( 'Top of broadcast', 'convertkit' ),
'bottom' => esc_html__( 'Bottom of broadcast', 'convertkit' ),
),
$args['description'],
array(
'enabled_export',
)
);

}

/**
* Renders the input for the No Styles setting.
*
Expand Down Expand Up @@ -763,6 +872,13 @@ public function sanitize_settings( $settings ) {
$settings['import_images'] = '';
}

// Remove disallowed HTML from the greeting and sign-off.
foreach ( array( 'export_greeting', 'export_sign_off' ) as $key ) {
if ( array_key_exists( $key, $settings ) ) {
$settings[ $key ] = wp_kses_post( $settings[ $key ] );
}
}

// Merge settings with defaults.
$settings = wp_parse_args( $settings, $this->settings->get_defaults() );

Expand Down
129 changes: 125 additions & 4 deletions includes/class-convertkit-broadcasts-exporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ public function export_post_to_broadcast( $post_id ) {
// Remove responsive image attributes, which email clients don't support.
$content = $this->remove_responsive_image_attributes( $content );

// Add the greeting, sign-off and link to read the Post on the web.
$content = $this->add_greeting_sign_off_and_web_link( $content, $post );

// Convert relative URLs to absolute URLs, as emails have no site context.
$content = links_add_base_url( $content, get_permalink( $post ) );

Expand All @@ -270,7 +273,8 @@ public function export_post_to_broadcast( $post_id ) {
}

// Define the Broadcast's parameters.
$args = array(
$thumbnail = $this->get_thumbnail( $post );
$args = array(
$post->post_title,
$content,
$post->post_excerpt,
Expand All @@ -279,9 +283,9 @@ public function export_post_to_broadcast( $post_id ) {
null,
'',
'',
'',
'',
'',
$thumbnail['alt'],
$thumbnail['url'],
$this->get_preview_text( $post ),
$this->get_subscriber_filter(),
);

Expand All @@ -306,6 +310,32 @@ public function export_post_to_broadcast( $post_id ) {

}

/**
* Returns the preview text for the Broadcast, using the Post's excerpt if one was written.
*
* @since 3.4.8
*
* @param WP_Post $post WordPress Post.
* @return string Preview text
*/
private function get_preview_text( $post ) {

$preview_text = ( has_excerpt( $post ) ? $post->post_excerpt : '' );

/**
* Define the preview text for the Broadcast created from the WordPress Post.
*
* @since 3.4.8
*
* @param string $preview_text Preview text.
* @param WP_Post $post WordPress Post.
*/
$preview_text = apply_filters( 'convertkit_broadcasts_exporter_preview_text', $preview_text, $post );

return (string) $preview_text;

}

/**
* Returns the Broadcast ID the given Post was previously exported to, if any.
*
Expand Down Expand Up @@ -364,6 +394,46 @@ private function get_existing_draft_broadcast_id( $api, $post_id ) {

}

/**
* Returns the Post's featured image URL and alt text, to use as the Broadcast's thumbnail
* if the Broadcast is public.
*
* @since 3.4.8
*
* @param WP_Post $post WordPress Post.
* @return array Thumbnail URL and alt text (blank if no thumbnail)
*/
private function get_thumbnail( $post ) {

$thumbnail = array(
'url' => '',
'alt' => '',
);

// Bail if the Broadcast isn't public, as Kit only uses thumbnails for public Broadcasts.
if ( ! $this->broadcasts_settings->export_public() ) {
return $thumbnail;
}

// Bail if the Post has no featured image.
$image_id = get_post_thumbnail_id( $post );
if ( ! $image_id ) {
return $thumbnail;
}

// Bail if the featured image's URL can't be fetched.
$url = wp_get_attachment_image_url( $image_id, 'full' );
if ( ! $url ) {
return $thumbnail;
}

return array(
'url' => $url,
'alt' => (string) get_post_meta( $image_id, '_wp_attachment_image_alt', true ),
);

}

/**
* Returns the Post's published date and time, if the Broadcast is public and the Post is published.
*
Expand Down Expand Up @@ -430,6 +500,57 @@ private function get_subscriber_filter() {

}

/**
* Adds the greeting, sign-off and link to read the Post on the web to the given content,
* based on the Plugin's settings.
*
* @since 3.4.8
*
* @param string $content HTML Content.
* @param WP_Post $post WordPress Post.
* @return string HTML Content
*/
private function add_greeting_sign_off_and_web_link( $content, $post ) {

// Add the greeting and sign-off, converting any line breaks to paragraphs.
if ( $this->broadcasts_settings->export_greeting() ) {
$content = wpautop( $this->broadcasts_settings->export_greeting() ) . $content;
}
if ( $this->broadcasts_settings->export_sign_off() ) {
$content .= wpautop( $this->broadcasts_settings->export_sign_off() );
}

// Bail if no link to read the Post on the web is required, or the Post isn't published, as its link won't work.
if ( ! $this->broadcasts_settings->export_web_link() || $post->post_status !== 'publish' ) {
return $content;
}

/**
* Define the text for the link to read the Post on the web, in Broadcasts created from WordPress Posts.
*
* @since 3.4.8
*
* @param string $text Link text.
* @param WP_Post $post WordPress Post.
*/
$text = apply_filters( 'convertkit_broadcasts_exporter_web_link_text', __( 'Read this on the web', 'convertkit' ), $post );

// Build link.
$link = sprintf(
'<p><a href="%s">%s</a></p>',
esc_url( get_permalink( $post ) ),
esc_html( $text )
);

// Add link to the top or bottom of the content.
if ( $this->broadcasts_settings->export_web_link() === 'top' ) {
return $link . $content;
}

return $content . $link;

}

/**
* Removes `srcset` and `sizes` attributes from images in the given content.
*
Expand Down
Loading
Loading