Use SQL to filter out invalid chapter IDs when story is saved

This commit is contained in:
Tetrakern 2024-10-27 13:31:03 +01:00
parent bae3ca8bb9
commit d1894d3459
2 changed files with 118 additions and 26 deletions

View File

@ -372,3 +372,118 @@ function fictioneer_set_chapter_story_parent( $chapter_id, $story_id ) {
) )
); );
} }
// =============================================================================
// SPECIFIC SQL QUERIES
// =============================================================================
if ( ! function_exists( 'fictioneer_sql_filter_valid_chapter_ids' ) ) {
/**
* Filters out non-valid chapters for ID array
*
* Note: This is about 3 times faster than using WP_Query.
*
* @since 5.26.0
*
* @global wpdb $wpdb WordPress database object.
*
* @param int $story_id Story ID.
* @param int[] $chapter_ids Array of chapter IDs.
*
* @return int[] Filtered array of chapter IDs.
*/
function fictioneer_sql_filter_valid_chapter_ids( $story_id, $chapter_ids ) {
global $wpdb;
// Prepare
$chapter_ids = is_array( $chapter_ids ) ? $chapter_ids : [ $chapter_ids ];
$chapter_ids = array_map( 'intval', $chapter_ids );
$chapter_ids = array_filter( $chapter_ids, function( $value ) { return $value > 0; } );
$chapter_ids = array_unique( $chapter_ids );
// Empty?
if ( empty( $chapter_ids ) ) {
return [];
}
// Prepare placeholders and values
$placeholders = implode( ',', array_fill( 0, count( $chapter_ids ), '%d' ) );
$values = $chapter_ids;
// Prepare SQL
$sql =
"SELECT p.ID
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE p.post_type = 'fcn_chapter'
AND p.ID IN ($placeholders)
AND p.post_status NOT IN ('trash', 'draft', 'auto-draft', 'inherit')";
if ( defined('FICTIONEER_FILTER_STORY_CHAPTERS') && FICTIONEER_FILTER_STORY_CHAPTERS ) {
$sql .= " AND pm.meta_key = %s AND pm.meta_value = %d";
$values[] = 'fictioneer_chapter_story';
$values[] = $story_id;
}
$query = $wpdb->prepare( $sql, ...$values );
// Execute
$filtered_ids = $wpdb->get_col( $query );
// Restore order and return
return array_values( array_intersect( $chapter_ids, $filtered_ids ) );
}
}
/**
* Filters out non-valid chapters for ID array
*
* Note: This is about 3 times faster than using WP_Query.
*
* @since 5.26.0
*
* @global wpdb $wpdb WordPress database object.
*
* @param int $story_id Story ID.
* @param int[] $chapter_ids Array of chapter IDs.
*
* @return int[] Filtered array of chapter IDs.
*/
function fictioneer_sql_filter_valid_chapter_ids( $story_id, $chapter_ids ) {
global $wpdb;
// Prepare
$chapter_ids = is_array( $chapter_ids ) ? $chapter_ids : [ $chapter_ids ];
$chapter_ids = array_map( 'intval', $chapter_ids );
$chapter_ids = array_filter( $chapter_ids, function( $value ) { return $value > 0; } );
$chapter_ids = array_unique( $chapter_ids );
// Empty?
if ( empty( $chapter_ids ) ) {
return [];
}
// Setup
$chapter_ids_placeholder = implode( ',', $chapter_ids ?: [0] );
$sql =
"SELECT p.ID
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE p.post_type = 'fcn_chapter'
AND p.ID IN ($chapter_ids_placeholder)
AND p.post_status NOT IN ('trash', 'draft', 'auto-draft', 'inherit')";
// Chapters need to be assigned to a story, which can be turned off (but really should not)
if ( defined('FICTIONEER_FILTER_STORY_CHAPTERS') && FICTIONEER_FILTER_STORY_CHAPTERS ) {
$sql .= $wpdb->prepare( " AND pm.meta_key = %s AND pm.meta_value = %d", 'fictioneer_chapter_story', $story_id );
}
// Execute
$filtered_ids = $wpdb->get_col( $sql );
// Restore order and return
return array_values( array_intersect( $chapter_ids, $filtered_ids ) );
}

View File

@ -2353,36 +2353,13 @@ function fictioneer_save_story_metaboxes( $post_id ) {
if ( isset( $_POST['fictioneer_story_chapters'] ) && current_user_can( 'edit_fcn_stories', $post_id ) ) { if ( isset( $_POST['fictioneer_story_chapters'] ) && current_user_can( 'edit_fcn_stories', $post_id ) ) {
$previous_chapter_ids = fictioneer_get_story_chapter_ids( $post_id ); $previous_chapter_ids = fictioneer_get_story_chapter_ids( $post_id );
$chapter_ids = $_POST['fictioneer_story_chapters']; // Filter out non-valid chapter IDs
$chapter_ids = is_array( $chapter_ids ) ? $chapter_ids : [ $chapter_ids ]; $chapter_ids = fictioneer_sql_filter_valid_chapter_ids( $post_id, $_POST['fictioneer_story_chapters'] );
$chapter_ids = array_map( 'intval', $chapter_ids );
$chapter_ids = array_filter( $chapter_ids, function( $value ) { return $value > 0; } );
$chapter_ids = array_unique( $chapter_ids );
if ( empty( $chapter_ids ) ) { if ( empty( $chapter_ids ) ) {
$fields['fictioneer_story_chapters'] = []; // Ensure empty meta is removed $fields['fictioneer_story_chapters'] = []; // Ensure empty meta is removed
} else { } else {
// Make sure only allowed posts are in $chapter_ids = array_map( 'strval', $chapter_ids );
$chapter_query_args = array(
'post_type' => 'fcn_chapter',
'post_status' => 'any',
'post__in' => $chapter_ids ?: [0], // Must not be empty!
'orderby' => 'post__in',
'fields' => 'ids',
'posts_per_page' => -1,
'update_post_meta_cache' => false, // Improve performance
'update_post_term_cache' => false, // Improve performance
'no_found_rows' => true // Improve performance
);
if ( FICTIONEER_FILTER_STORY_CHAPTERS ) {
$chapter_query_args['meta_key'] = 'fictioneer_chapter_story';
$chapter_query_args['meta_value'] = $post_id;
}
$chapters_query = new WP_Query( $chapter_query_args );
$chapter_ids = array_map( 'strval', $chapters_query->posts );
$fields['fictioneer_story_chapters'] = $chapter_ids; $fields['fictioneer_story_chapters'] = $chapter_ids;
} }