Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions includes/API/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,18 @@ public static function set_publications( array $items ): void {
set_transient( self::PUBLICATIONS_KEY, $items, self::TTL );
}

/**
* Clear the cached publications list so the next read fetches it from beehiiv.
*
* @since x.x.x
*
* @return void
*/
public static function delete_publications(): void {

delete_transient( self::PUBLICATIONS_KEY );
}

/**
* Cached templates for a publication.
*
Expand Down
14 changes: 12 additions & 2 deletions includes/Admin/Registrar.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private static function register_page_settings_section( string $page_slug ): voi

add_settings_field(
'beehiiv_publication_id',
__( 'Publication', 'beehiiv' ),
__( 'Default publication', 'beehiiv' ),
[ self::class, 'render_publication_id_field' ],
$page_slug,
self::PAGE_SETTINGS_SECTION_ID,
Expand Down Expand Up @@ -147,8 +147,18 @@ static function ( $row ) use ( $selected ) {
</option>
<?php endif; ?>
</select>
<button
type="button"
id="beehiiv_refresh_publications"
class="button button-secondary beehiiv-refresh-button"
>
<?php esc_html_e( 'Refresh publications', 'beehiiv' ); ?>
</button>
<p class="description">
<?php esc_html_e( 'The publication to use for newsletters sent from this site.', 'beehiiv' ); ?>
<?php
// phpcs:ignore Generic.Files.LineLength.MaxExceeded,Generic.Files.LineLength.TooLong -- Single string for translators / i18n tools.
esc_html_e( 'Preselected on new posts. Editors can choose a different publication for each post in the beehiiv sidebar.', 'beehiiv' );
?>
</p>
<?php
}
Expand Down
21 changes: 21 additions & 0 deletions includes/Editor/Meta.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,27 @@ final class Meta {
*/
public const BEEHIIV_POST_TEMPLATE_ID = '_beehiiv_post_template_id';

/**
* Beehiiv publication ID chosen for this post. Empty = use the site-wide default publication.
*
* @since x.x.x
*/
public const BEEHIIV_PUBLICATION_ID = '_beehiiv_publication_id';

/**
* Publication the linked beehiiv post lives in. Server-only; not registered for REST.
*
* @since x.x.x
*/
public const BEEHIIV_LINKED_PUBLICATION_ID = '_beehiiv_linked_publication_id';

/**
* Post template the linked beehiiv post was created with. Server-only; not registered for REST.
*
* @since x.x.x
*/
public const BEEHIIV_LINKED_POST_TEMPLATE_ID = '_beehiiv_linked_post_template_id';

/**
* Beehiiv post ID after the newsletter has been created via the API.
*
Expand Down
13 changes: 12 additions & 1 deletion includes/Editor/PostSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Beehiiv\API\Resources\Workspace;
use Beehiiv\Config;
use Beehiiv\Connection\Manager;
use Beehiiv\Newsletter\PublicationResolver;
use Beehiiv\Newsletter\SupportedBlocks;
use Beehiiv\OAuth\Config as OAuthConfig;

Expand Down Expand Up @@ -66,6 +67,10 @@ final class PostSettings {
'type' => 'string',
'default' => '',
],
Meta::BEEHIIV_PUBLICATION_ID => [
'type' => 'string',
'default' => '',
],
Meta::BEEHIIV_POST_ID => [
'type' => 'string',
'default' => '',
Expand Down Expand Up @@ -145,7 +150,8 @@ public static function register_meta(): void {
* Whether the current user may read or write a beehiiv post meta key.
*
* Readonly keys are never writable via REST. Newsletter send settings and
* newsletter wording require `publish_posts`; other keys allow `edit_posts`.
* the post's publication and newsletter wording require `publish_posts`; other
* keys allow `edit_posts`.
*
* @param bool $allowed Whether the user can add or edit the meta key.
* @param string $meta_key Meta key.
Expand All @@ -162,6 +168,7 @@ public static function authorize_meta( $allowed, $meta_key, $post_id ) {
Meta::SEND_TO_NEWSLETTER,
Meta::SEND_TO_NEWSLETTER_DATE,
Meta::SEND_TO_NEWSLETTER_SNIPPET,
Meta::BEEHIIV_PUBLICATION_ID,
Meta::NEWSLETTER_TITLE,
Meta::NEWSLETTER_SUBTITLE,
Meta::NEWSLETTER_SHOW_TITLE_IN_EMAIL,
Expand Down Expand Up @@ -351,6 +358,7 @@ public static function prepare_rest_post( $response, $post, $request ) {
[
Meta::BEEHIIV_POST_ID,
Meta::BEEHIIV_SCHEDULED_AT,
Meta::BEEHIIV_PUBLICATION_ID,
Meta::SEND_TO_NEWSLETTER,
Meta::NEWSLETTER_ERROR,
Meta::NEWSLETTER_ERROR_TYPE,
Expand Down Expand Up @@ -384,6 +392,7 @@ private static function get_editor_config(): array {
$settings = Options::get();
$is_connected = Manager::is_connected();
$can_write_posts = $is_connected && Workspace::can_write_posts();
$default_pub_id = PublicationResolver::get_default_publication_id();

return [
'isConnected' => $is_connected,
Expand All @@ -396,6 +405,8 @@ private static function get_editor_config(): array {
'publicationId' => trim( (string) ( $settings['publication_id'] ?? '' ) ),
'defaultPostTemplateId' => trim( (string) ( $settings['post_template_id'] ?? '' ) ),
'canPublishPosts' => current_user_can( 'publish_posts' ),
'defaultPublicationId' => $default_pub_id,
'publications' => $is_connected ? PublicationResolver::get_editor_publications() : [],
];
}
}
74 changes: 53 additions & 21 deletions includes/Newsletter/PostSettingsBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ final class PostSettingsBuilder {
/**
* Create beehiiv post settings array for the WordPress post.
*
* @param int $post_id Post ID.
* @param bool $for_update When true, omit schedule validation and `scheduled_at` (used for linked-post updates).
* @param int $post_id Post ID.
* @param bool $for_update When true, omit schedule validation and `scheduled_at` (linked-post updates).
* @param string|null $publication_id Publication the payload is for. Defaults to the post's resolved publication.
* @return array<string, mixed>|WP_Error beehiiv post settings or error.
* @since 1.0.0
*/
public static function get_post_settings( int $post_id, bool $for_update = false ) {
public static function get_post_settings( int $post_id, bool $for_update = false, ?string $publication_id = null ) {
$post_object = get_post( $post_id );

if ( ! $post_object instanceof WP_Post ) {
Expand All @@ -45,7 +46,25 @@ public static function get_post_settings( int $post_id, bool $for_update = false
);
}

$post_template_id = self::get_post_template_id( $post_id );
if ( null === $publication_id ) {
$publication_id = PublicationResolver::resolve_for_post( $post_id );
}

if ( '' === $publication_id ) {
return new WP_Error(
'beehiiv_publication_missing',
sprintf( 'No beehiiv publication is chosen for post ID: %d.', $post_id )
);
}

$post_template_id = self::resolve_post_template_id( $post_id, $publication_id );

if ( '' === $post_template_id && PublicationResolver::get_default_publication_id() !== $publication_id ) {
return new WP_Error(
'beehiiv_post_template_required',
sprintf( 'No post template is chosen for this post\'s publication (post ID: %d).', $post_id )
);
}

if ( '' === $post_template_id ) {
return new WP_Error(
Expand Down Expand Up @@ -154,15 +173,16 @@ public static function get_post_settings( int $post_id, bool $for_update = false
* {@see Sender::reschedule_linked_post()} recreates the beehiiv post because the API
* does not allow updating `scheduled_at` on confirmed posts.
*
* @param int $post_id Post ID.
* @param int $post_id Post ID.
* @param string|null $publication_id Publication the payload is for. Defaults to the post's resolved publication.
* @return array{
* payload: array<string, mixed>,
* meta: array{scheduled_at: string|null, clear_custom_date: bool}
* }|WP_Error
* @since 1.0.0
*/
public static function build_update( int $post_id ) {
$settings = self::get_post_settings( $post_id, true );
public static function build_update( int $post_id, ?string $publication_id = null ) {
$settings = self::get_post_settings( $post_id, true, $publication_id );

if ( is_wp_error( $settings ) ) {
return $settings;
Expand Down Expand Up @@ -358,7 +378,7 @@ private static function advertisement_block_with_unavailable_ad( WP_Post $post )
return null;
}

$publication_id = self::get_publication_id();
$publication_id = self::get_ad_publication_id();

if ( '' === $publication_id ) {
return null;
Expand Down Expand Up @@ -414,24 +434,34 @@ private static function collect_advertisement_ad_ids( array $blocks ): array {
}

/**
* Post template for the post: post meta when set and valid, else plugin default.
* Post template for the post in a publication.
*
* @since 1.0.0
* The post's own template when it exists in that publication. Otherwise the
* plugin default template, but only for the site-wide default publication,
* which is the only publication that has a default template. Empty when
* neither applies.
*
* @param int $post_id Post ID.
* @since x.x.x
*
* @param int $post_id Post ID.
* @param string $publication_id Publication ID.
*
* @return string
*/
private static function get_post_template_id( int $post_id ): string {
public static function resolve_post_template_id( int $post_id, string $publication_id ): string {

$post_template_id = get_post_meta( $post_id, Meta::BEEHIIV_POST_TEMPLATE_ID, true );
$post_template_id = is_string( $post_template_id ) ? trim( $post_template_id ) : '';

if ( '' !== $post_template_id && self::post_template_exists( $post_template_id ) ) {
if ( '' !== $post_template_id && self::post_template_exists( $post_template_id, $publication_id ) ) {
return $post_template_id;
}

return self::get_site_post_template_id();
if ( '' !== $publication_id && PublicationResolver::get_default_publication_id() === $publication_id ) {
return self::get_site_post_template_id();
}

return '';
}

/**
Expand Down Expand Up @@ -483,17 +513,16 @@ private static function should_show_title_in_email( int $post_id ): bool {
}

/**
* Whether a template ID exists for the configured publication.
* Whether a template ID exists in a publication.
*
* @since 1.0.0
*
* @param string $template_id Template ID.
* @param string $template_id Template ID.
* @param string $publication_id Publication ID.
*
* @return bool
*/
private static function post_template_exists( string $template_id ): bool {

$publication_id = self::get_publication_id();
private static function post_template_exists( string $template_id, string $publication_id ): bool {

if ( '' === $publication_id ) {
return false;
Expand All @@ -510,13 +539,16 @@ private static function post_template_exists( string $template_id ): bool {
}

/**
* Configured beehiiv publication ID.
* Publication used to validate Advertisement blocks.
*
* Advertisements stay on the site-wide default publication until per-post
* publications are decided for ads (PRD-06.8.02 Q-001).
*
* @since 1.0.0
*
* @return string
*/
private static function get_publication_id(): string {
private static function get_ad_publication_id(): string {

$settings = Options::get();

Expand Down
Loading
Loading