$split( SWCC_Rest_Create_Draft::META_CLAIMS ),
'quotes' => $split( SWCC_Rest_Create_Draft::META_UNVERIFIED_QUOTES ),
);
}
/**
* On a delivered article's edit screen, list the flagged passages above the editor (1.0.5).
*
* Before this the only pointer was the first passage, quoted on the topic, and the operator
* had to carry it over to the article by hand. The block editor hoists admin notices into its
* own notice area, so this shows in both editors.
*
* @return void
*/
public static function review_notice() {
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
$post = get_post();
if ( ! $screen instanceof WP_Screen || 'post' !== $screen->base || ! $post instanceof WP_Post || ! current_user_can( 'edit_post', $post->ID ) ) {
return;
}
self::render_review_notice( $post->ID );
}
/**
* The notice itself, separated so it can be rendered without a screen.
*
* @param int $post_id A delivered article.
* @return void
*/
public static function render_review_notice( $post_id ) {
$passages = self::review_passages( $post_id );
if ( empty( $passages['claims'] ) && empty( $passages['quotes'] ) ) {
return;
}
?>
post_type || ! current_user_can( 'edit_post', $post->ID ) ) {
return $actions;
}
if ( (int) get_post_meta( $post->ID, SWCC_Topic::META_GENERATED, true ) > 0 ) {
if ( ! SWCC_Topic::is_regenerating( $post->ID ) ) {
$actions['swcc_regenerate'] = '' . esc_html__( 'Regenerate', 'saidweekly' ) . '';
}
return $actions;
}
$url = wp_nonce_url(
add_query_arg(
array(
'action' => self::ACTION,
'topic_id' => $post->ID,
),
admin_url( 'admin-post.php' )
),
self::ACTION . '_' . $post->ID
);
$actions['swcc_generate'] = '' . esc_html__( 'Generate now', 'saidweekly' ) . '';
return $actions;
}
/**
* The nonce-protected URL that regenerates a topic's article.
*
* @param int $topic_id Topic ID.
* @return string
*/
public static function regenerate_url( $topic_id ) {
return wp_nonce_url(
add_query_arg(
array(
'action' => self::ACTION_REGENERATE,
'topic_id' => (int) $topic_id,
),
admin_url( 'admin-post.php' )
),
self::ACTION_REGENERATE . '_' . (int) $topic_id
);
}
/**
* The consequence named before a regeneration, as business.md requires for anything billable.
*
* @return string
*/
public static function regenerate_confirmation() {
return __( 'Write this article again? This uses 1 credit when it succeeds. If the current draft is unedited it is replaced; otherwise the new article is added beside it.', 'saidweekly' );
}
/**
* Regenerate a topic's article (admin-post handler).
*
* @return void
*/
public static function handle_regenerate() {
$topic_id = isset( $_GET['topic_id'] ) ? absint( $_GET['topic_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- verified below with the topic-specific nonce.
if ( 0 === $topic_id || ! current_user_can( 'edit_post', $topic_id ) ) {
wp_die( esc_html__( 'You do not have permission to regenerate this topic.', 'saidweekly' ) );
}
check_admin_referer( self::ACTION_REGENERATE . '_' . $topic_id );
$result = ( new SWCC_Remote_Content_Generator() )->regenerate( $topic_id );
$args = is_wp_error( $result )
? array(
'swcc_generation' => 'error',
'swcc_message' => $result->get_error_code(),
)
: array( 'swcc_generation' => 'queued' );
wp_safe_redirect( add_query_arg( $args, get_edit_post_link( $topic_id, 'raw' ) ) );
exit;
}
/**
* Handle a nonce-protected Generate Now request.
*
* @return void
*/
public static function handle() {
$topic_id = isset( $_GET['topic_id'] ) ? absint( $_GET['topic_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- verified below with the topic-specific nonce.
if ( 0 === $topic_id || ! current_user_can( 'edit_post', $topic_id ) ) {
wp_die( esc_html__( 'You do not have permission to generate this topic.', 'saidweekly' ) );
}
check_admin_referer( self::ACTION . '_' . $topic_id );
$result = ( new SWCC_Remote_Content_Generator() )->generate( $topic_id );
$args = is_wp_error( $result )
? array(
'swcc_generation' => 'error',
'swcc_message' => $result->get_error_code(),
)
: array( 'swcc_generation' => 'queued' );
wp_safe_redirect( add_query_arg( $args, get_edit_post_link( $topic_id, 'raw' ) ) );
exit;
}
/**
* Render the result of a manual generation request.
*
* @return void
*/
public static function notice() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- redirect-only display state, never used for a write.
$state = isset( $_GET['swcc_generation'] ) ? sanitize_key( wp_unslash( $_GET['swcc_generation'] ) ) : '';
if ( 'queued' === $state ) {
echo '' . esc_html__( 'Generation is queued. This page will show the linked draft when delivery finishes.', 'saidweekly' ) . '
';
} elseif ( 'error' === $state ) {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- redirect-only display state, never used for a write.
$message = isset( $_GET['swcc_message'] ) ? sanitize_key( wp_unslash( $_GET['swcc_message'] ) ) : '';
if ( 'swcc_staging_site' === $message ) {
echo '' . esc_html__( 'This installation is designated staging (SWCC_SITE_ROLE) and never asks for articles.', 'saidweekly' ) . '
';
} elseif ( 'swcc_branding_incomplete' === $message ) {
$url = admin_url( 'edit.php?post_type=' . SWCC_Topic::POST_TYPE . '&page=' . SWCC_Branding_Page::PAGE_SLUG );
echo '' . sprintf( '%2$s', esc_url( $url ), esc_html__( 'Complete the required Branding settings before generating.', 'saidweekly' ) ) . '
';
} else {
echo '' . esc_html__( 'Could not queue generation. Confirm activation and try again.', 'saidweekly' ) . '
';
}
}
}
/**
* Return the current local delivery state for one job.
*
* @return void
*/
public static function ajax_status() {
check_ajax_referer( 'swcc_generation_status' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( array( 'message' => __( 'Unauthorized.', 'saidweekly' ) ), 403 );
}
$job_id = isset( $_POST['job_id'] ) ? sanitize_text_field( wp_unslash( $_POST['job_id'] ) ) : '';
// An empty job ID would match any post whose job-ID meta is an empty string rather than
// matching nothing, and report an unrelated post as this topic's delivered draft.
if ( '' === $job_id ) {
wp_send_json_error( array( 'message' => __( 'Missing job ID.', 'saidweekly' ) ), 400 );
}
$posts = get_posts(
array(
'post_type' => 'post',
'post_status' => array( 'publish', 'draft', 'pending', 'private', 'future', 'trash' ),
'posts_per_page' => 1,
'fields' => 'ids',
'no_found_rows' => true,
'update_post_meta_cache' => false,
'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- job ID is the delivery idempotency key.
array(
'key' => SWCC_Topic::META_JOB_ID,
'value' => $job_id,
),
),
)
);
if ( empty( $posts ) ) {
wp_send_json_success( array( 'state' => 'queued' ) );
}
$post_id = (int) $posts[0];
wp_send_json_success(
array(
'state' => 'delivered',
'url' => get_edit_post_link( $post_id, 'raw' ),
)
);
}
/**
* Enqueue the poller that watches a queued topic's job from the editor (1.1.1: a registered
* script with its configuration passed through wp_add_inline_script(), not a printed tag).
*
* @param string $hook_suffix Current admin page identifier.
* @return void
*/
public static function enqueue_status_poll( $hook_suffix ) {
if ( 'post.php' !== $hook_suffix ) {
return;
}
$screen = get_current_screen();
if ( ! $screen instanceof WP_Screen || SWCC_Topic::POST_TYPE !== $screen->post_type ) {
return;
}
wp_enqueue_script(
'swcc-generation-status',
SWCC_PLUGIN_URL . 'assets/js/generation-status.js',
array(),
SWCC_VERSION,
true
);
wp_add_inline_script(
'swcc-generation-status',
'window.swccGenerationStatus = ' . wp_json_encode(
array(
'nonce' => wp_create_nonce( 'swcc_generation_status' ),
'label' => __( 'Draft delivered — open it.', 'saidweekly' ),
)
) . ';',
'before'
);
}
}