diff --git a/includes/functions/_helpers-query.php b/includes/functions/_helpers-query.php index ad2cd4d0..719c91e6 100644 --- a/includes/functions/_helpers-query.php +++ b/includes/functions/_helpers-query.php @@ -710,6 +710,44 @@ if ( ! function_exists( 'fictioneer_sql_has_new_story_chapters' ) ) { } } +if ( ! function_exists( 'fictioneer_get_co_authored_story_ids' ) ) { + /** + * Returns story IDs where the user is a co-author + * + * @since 5.26.0 + * + * @global wpdb $wpdb WordPress database object. + * + * @param int $author_id User ID. + * + * @return int[] Array of story IDs. + */ + + function fictioneer_get_co_authored_story_ids( $author_id ) { + static $cache = []; + + if ( isset( $cache[ $author_id ] ) ) { + return $cache[ $author_id ]; + } + + global $wpdb; + + $story_ids = $wpdb->get_col( + $wpdb->prepare( + "SELECT post_id + FROM {$wpdb->postmeta} + WHERE meta_key = 'fictioneer_story_co_authors' + AND meta_value LIKE %s", + '%"' . $author_id . '"%' + ) + ); + + $cache[ $author_id ] = $story_ids; + + return $story_ids; + } +} + if ( ! function_exists( 'fictioneer_sql_get_chapter_story_selection' ) ) { /** * Returns selectable stories for chapter assignments @@ -729,7 +767,9 @@ if ( ! function_exists( 'fictioneer_sql_get_chapter_story_selection' ) ) { // Setup $stories = array( '0' => _x( '— Unassigned —', 'Chapter story select option.', 'fictioneer' ) ); + $co_authored_stories = []; $other_author = false; + $co_author = false; // Prepare SQL query $values = []; @@ -743,6 +783,15 @@ if ( ! function_exists( 'fictioneer_sql_get_chapter_story_selection' ) ) { if ( get_option( 'fictioneer_limit_chapter_stories_by_author' ) ) { $sql .= " AND p.post_author = %d"; $values[] = $post_author_id; + + $co_authored_stories = fictioneer_get_co_authored_story_ids( $post_author_id ); + + if ( ! empty( $co_authored_stories ) ) { + $placeholders = implode( ',', array_fill( 0, count( $co_authored_stories ), '%d' ) ); + $sql .= " OR p.ID IN ($placeholders)"; + $values = array_merge( $values, $co_authored_stories ); + $co_author = true; + } } $sql .= " ORDER BY p.post_date DESC"; @@ -757,15 +806,24 @@ if ( ! function_exists( 'fictioneer_sql_get_chapter_story_selection' ) ) { mysql2date( get_option( 'date_format' ), $story->post_date ), mysql2date( get_option( 'time_format' ), $story->post_date ) ); + $suffix = []; if ( $story->post_status !== 'publish' ) { - $stories[ $story->ID ] = sprintf( - _x( '%s (%s)', 'Chapter story meta field option with status label.', 'fictioneer' ), - $title, - fictioneer_get_post_status_label( $story->post_status ) - ); - } else { + $suffix['status'] = fictioneer_get_post_status_label( $story->post_status ); + } + + if ( in_array( $story->ID, $co_authored_stories ) ) { + $suffix['co-authored'] = __( 'Co-Author', 'fictioneer' ); + } + + if ( empty( $suffix ) ) { $stories[ $story->ID ] = $title; + } else { + $stories[ $story->ID ] = sprintf( + _x( '%1$s (%2$s)', 'Chapter story meta field option with notes.', 'fictioneer' ), + $title, + implode( ' | ', $suffix ) + ); } } @@ -787,15 +845,16 @@ if ( ! function_exists( 'fictioneer_sql_get_chapter_story_selection' ) ) { // Append to selection $stories[ $current_story_id ] = sprintf( - _x( '%s %s', 'Chapter story meta field mismatched option with author and/or status label.', 'fictioneer' ), + _x( '%1$s (%2$s)', 'Chapter story meta field mismatched option with notes.', 'fictioneer' ), fictioneer_get_safe_title( $current_story_id, 'admin-render-chapter-data-metabox-current-suffix' ), - ( ! empty( $suffix ) ? ' (' . implode( ' | ', $suffix ) . ')' : '' ) + ! empty( $suffix ) ? implode( ' | ', $suffix ) : '' ); } return array( 'stories' => $stories, - 'other_author' => $other_author + 'other_author' => $other_author, + 'co_author' => $co_author ); } } diff --git a/includes/functions/_setup-meta-fields.php b/includes/functions/_setup-meta-fields.php index 6b0c7e09..a27d220c 100644 --- a/includes/functions/_setup-meta-fields.php +++ b/includes/functions/_setup-meta-fields.php @@ -2062,7 +2062,7 @@ function fictioneer_render_story_data_metabox( $post ) { ); $description = get_option( 'fictioneer_limit_chapter_stories_by_author' ) ? - __( 'Select and order chapters assigned to the story (set in the chapter). The author of the chapter and the story must match.', 'fictioneer' ) : + __( 'Select and order chapters assigned to the story (set in the chapter). The author (or co-author) of the chapter and the story must match.', 'fictioneer' ) : __( 'Select and order chapters assigned to the story (set in the chapter).', 'fictioneer' ); $output['fictioneer_story_chapters'] = fictioneer_get_metabox_relationships( @@ -2700,6 +2700,8 @@ function fictioneer_render_chapter_data_metabox( $post ) { $author_warning = $story_selection['other_author'] ? ' ' . __( 'Warning: The selected story belongs to another author. If you change the selection, you cannot go back.', 'fictioneer' ) : ''; + $author_warning = $story_selection['co_author'] ? ' ' . __( 'Note: You are a co-author of the selected story, but only you can edit this chapter.', 'fictioneer' ) : $author_warning; + if ( get_option( 'fictioneer_enable_chapter_appending' ) ) { $description = __( 'Select the story this chapter belongs to. Published and scheduled chapters are automatically appended to the story.', 'fictioneer' ); } @@ -2949,7 +2951,9 @@ function fictioneer_save_chapter_metaboxes( $post_id ) { $invalid_story = false; if ( get_option( 'fictioneer_limit_chapter_stories_by_author' ) ) { - $invalid_story = $story_author_id != $post_author_id; + $co_authored_stories = fictioneer_get_co_authored_story_ids( $post_author_id ); + + $invalid_story = $story_author_id != $post_author_id && ! in_array( $story_id, $co_authored_stories ); } if ( $invalid_story && $current_story_id != $story_id ) { diff --git a/includes/functions/_utility.php b/includes/functions/_utility.php index 77e9cc8a..19855550 100644 --- a/includes/functions/_utility.php +++ b/includes/functions/_utility.php @@ -1590,9 +1590,14 @@ function fictioneer_append_chapter_to_story( $post_id, $story_id, $force = false // Setup, continued $chapter_author_id = get_post_field( 'post_author', $post_id ); $story_author_id = get_post_field( 'post_author', $story_id ); + $co_authored_story_ids = fictioneer_get_co_authored_story_ids( $chapter_author_id ); // Abort if the author IDs do not match - if ( $chapter_author_id != $story_author_id && ! $force ) { + if ( + $chapter_author_id != $story_author_id && + ! in_array( $story_id, $co_authored_story_ids ) && + ! $force + ) { return; }