Skip to content
116 changes: 116 additions & 0 deletions admin/section/class-convertkit-admin-section-broadcasts.php
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,45 @@ public function register_fields() {
)
);

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' ),
)
);

add_settings_field(
'no_styles',
__( 'Disable Styles', '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
101 changes: 98 additions & 3 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,8 +283,8 @@ public function export_post_to_broadcast( $post_id ) {
null,
'',
'',
'',
'',
$thumbnail['alt'],
$thumbnail['url'],
$this->get_preview_text( $post ),
$this->get_subscriber_filter(),
);
Expand Down Expand Up @@ -390,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 @@ -456,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
63 changes: 63 additions & 0 deletions includes/class-convertkit-settings-broadcasts.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,46 @@ public function export_public() {

}

/**
* Returns the greeting to add to the start of Broadcasts created from WordPress Posts.
*
* @since 3.4.8
*
* @return string HTML, which may include Liquid
*/
public function export_greeting() {

return (string) $this->settings['export_greeting'];

}

/**
* Returns the sign-off to add to the end of Broadcasts created from WordPress Posts.
*
* @since 3.4.8
*
* @return string HTML, which may include Liquid
*/
public function export_sign_off() {

return (string) $this->settings['export_sign_off'];

}

/**
* Returns where to add a link to read the WordPress Post on the web, in Broadcasts
* created from WordPress Posts.
*
* @since 3.4.8
*
* @return string Position (blank = none, top, bottom)
*/
public function export_web_link() {

return ( in_array( $this->settings['export_web_link'], array( 'top', 'bottom' ), true ) ? $this->settings['export_web_link'] : '' );

}

/**
* Returns whether Broadcasts should have their styles imported.
*
Expand Down Expand Up @@ -318,6 +358,19 @@ public function get_schema() {
'enum' => array( '', 'on' ),
'description' => __( 'Whether Broadcasts created from WordPress Posts are published to the web (Kit Creator Profile and Landing Pages).', 'convertkit' ),
),
'export_greeting' => array(
'type' => 'string',
'description' => __( 'HTML to add to the start of Broadcasts created from WordPress Posts. Supports Liquid e.g. {{ subscriber.first_name }}.', 'convertkit' ),
),
'export_sign_off' => array(
'type' => 'string',
'description' => __( 'HTML to add to the end of Broadcasts created from WordPress Posts. Supports Liquid.', 'convertkit' ),
),
'export_web_link' => array(
'type' => 'string',
'enum' => array( '', 'top', 'bottom' ),
'description' => __( 'Where to add a link to read the published WordPress Post on the web, in Broadcasts created from WordPress Posts. Blank for none.', 'convertkit' ),
),
'no_styles' => array(
'type' => 'string',
'enum' => array( '', 'on' ),
Expand Down Expand Up @@ -352,6 +405,9 @@ public function get_defaults() {
'enabled_export' => '',
'export_send_to' => '',
'export_public' => '',
'export_greeting' => '',
'export_sign_off' => '',
'export_web_link' => '',
'no_styles' => '',
);

Expand All @@ -378,6 +434,13 @@ public function get_defaults() {
*/
public function save( $settings ) {

// 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 ] );
}
}

update_option( self::SETTINGS_NAME, array_merge( $this->get(), $settings ) );

// Reload settings in class, to reflect changes.
Expand Down
4 changes: 2 additions & 2 deletions resources/backend/js/settings-conditional-display.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ function convertKitConditionallyDisplaySettings(input) {
return;
}

// Show or hide this row if the input, select, link or span element within the row has the CSS class of the setting ID.
// Show or hide this row if the input, select, textarea, link or span element within the row has the CSS class of the setting ID.
if (
row.querySelector(
`input.${input.id}, select.${input.id}, a.${input.id}, span.${input.id}`
`input.${input.id}, select.${input.id}, textarea.${input.id}, a.${input.id}, span.${input.id}`
)
) {
row.style.display = input.checked ? '' : 'none';
Expand Down
Loading
Loading