Lorsqu'un utilisateur crée/met à jour une publication dans l'administrateur, cette opération prend entre 15 et 30 secondes.
Le coupable semble être cette requête lente:
SELECT ID
FROM wp_posts
WHERE post_type = 'attachment'
AND post_mime_type LIKE 'video%'
LIMIT 1
Il s'agit d'un bug connu et l'équipe principale y travaille, mais entre-temps, j'aimerais pouvoir désactiver cette requête. Puis-je faire cela dans mon fichier functions.php en utilisant quelque chose comme le filtre pre_get_posts
?
Ticket # 31071 introduit des correctifs avec de nouveaux filtres pour remplacer trois requêtes de média lentes possibles, dans la fonction wp_enqueue_media()
:
media_library_show_audio_playlist
(@param bool | null)
Depuis le document en ligne: Indique si le bouton doit être affiché ou null
afin de décider en fonction de l'existence de fichiers audio dans la bibliothèque multimédia.
media_library_show_video_playlist
(@param bool | null)
Dans le document en ligne: Indique si le bouton doit être affiché ou null
pour décider si des fichiers vidéo existent dans la bibliothèque multimédia.
media_library_months_with_files
(@param array | null)
Dans le document en ligne: Un tableau d'objets avec les propriétés month
et year
, ou null
(ou toute autre valeur autre qu'un tableau) pour le comportement par défaut.
Exemple:
Voici un plugin de démonstration:
<?php
/**
* Plugin Name: Override Possible Slow Media Queries
* Plugin URI: https://wordpress.stackexchange.com/a/200383/26350
*/
// Always show audio button
add_filter( 'media_library_show_audio_playlist', '__return_true' );
// Always show video button
add_filter( 'media_library_show_video_playlist', '__return_true' );
// Cache media library file months with the transients API
add_filter( 'media_library_months_with_files', function( $months )
{
// Generate file months when it's not cached or the transient has expired
if ( false === ( $months = get_transient( 'wpse_media_library_months_with_files' ) ) )
{
global $wpdb;
/**
* Note that we want to avoid returning non-array file months,
* to avoid running the slow query twice.
*
* From the Codex for wpdb::get_results( $query, $output_type ):
*
* "If no matching rows are found, or if there is a
* database error, the return value will be an empty array.
* If your $query string is empty, or you pass an invalid
* $output_type, NULL will be returned."
*
* So it looks like we're covered, as we're not dealing with
* empty query or a wrong return type.
*/
$months = $wpdb->get_results( $wpdb->prepare( "
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
FROM $wpdb->posts
WHERE post_type = %s
ORDER BY post_date DESC
", 'attachment' ) );
// Cache the results
set_transient(
'wpse_media_library_months_with_files',
$months,
12 * HOUR_IN_SECONDS // <-- Override to your needs!
);
}
return $months;
} );
Notez que nous pourrions également sélectionner manuellement le fichier mois avec, par exemple:
$months = [
(object) [ 'year' => 2017, 'month' => 2 ],
(object) [ 'year' => 2017, 'month' => 1 ],
(object) [ 'year' => 2016, 'month' => 12 ],
];
en utilisant le filtre media_library_months_with_files
.
Ces requêtes sont dans la fonction wp_enqueue_media()
:
$has_audio = $wpdb->get_var( "
SELECT ID
FROM $wpdb->posts
WHERE post_type = 'attachment'
AND post_mime_type LIKE 'audio%'
LIMIT 1
" );
$has_video = $wpdb->get_var( "
SELECT ID
FROM $wpdb->posts
WHERE post_type = 'attachment'
AND post_mime_type LIKE 'video%'
LIMIT 1
" );
$months = $wpdb->get_results( $wpdb->prepare( "
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
FROM $wpdb->posts
WHERE post_type = %s
ORDER BY post_date DESC
", 'attachment' ) );
Voici un moyen de modifier ces requêtes lentes potentielles:
/**
* Modify the potential slow $has_audio, $has_video and $months queries
*
* @link http://wordpress.stackexchange.com/a/200383/26350
*/
add_filter( 'media_upload_tabs', function( $tabs )
{
add_filter( 'query', 'wpse_replace_months_sql' );
add_filter( 'query', 'wpse_replace_audio_video_sql' );
return $tabs;
} );
add_filter( 'media_view_settings', function( $settings )
{
remove_filter( 'query', 'wpse_replace_months_sql' );
remove_filter( 'query', 'wpse_replace_audio_video_sql' );
return $settings;
} );
où (PHP 5.4+):
/**
* Use "SELECT false" for the $has_audio and $has_video queries
*/
function wpse_replace_audio_video_sql( $sql )
{
global $wpdb;
foreach( [ 'audio', 'video' ] as $type )
{
$find = "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment'
AND post_mime_type LIKE '{$type}%' LIMIT 1";
if( trim( preg_replace('/\s+/', ' ', $sql) ) == trim( preg_replace('/\s+/', ' ', $find) ) )
return "SELECT false"; // <-- We could also use true here if needed
}
return $sql;
}
et
/**
* Replace the available months query with the current month
*/
function wpse_replace_months_sql( $sql )
{
global $wpdb;
$find = "SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
FROM {$wpdb->posts} WHERE post_type = 'attachment' ORDER BY post_date DESC";
if( trim( preg_replace('/\s+/', ' ', $sql) ) == trim( preg_replace('/\s+/', ' ', $find) ) )
$sql = "SELECT YEAR( CURDATE() ) as year, MONTH( CURDATE() ) as month";
return $sql;
}
Nous pourrions essayer d’affiner la situation en créant des compteurs has_audio
et has_video
dans la table d’options et en le mettant à jour chaque fois que nous téléchargeons/supprimons un fichier audio ou vidéo.
Dans le ticket de traçabilité mentionné dans la question, il y a un index proposé :
ALTER TABLE $wpdb->posts ADD INDEX type_mime(post_type,post_mime_type)
cela pourrait donner un coup de pouce.
@ Denis-de-Bernardy donne également un exemple de requêtes alternatives pour la partie mois.