Votre question ne concerne pas vraiment WordPress, elle concerne plutôt PHP et le refactoring. Mais nous voyons tellement de mauvais code ici, et le modèle que j'expliquerai ci-dessous (MVC) pourrait aider de nombreux autres développeurs, j'ai donc décidé d'écrire une petite réponse. Gardez à l'esprit qu'il existe un site dédié à ces questions dans notre réseau: Code Review . Malheureusement, très peu de développeurs WordPress y sont actifs.
Comment refactoriser le code
- Supprimez le code inutile. Embellissez le reste.
- Trouvez toutes les expressions répétitives et créez des routines (fonctions ou classes) pour les résumer et les encapsuler.
- Séparez la gestion des données, le modèle (stockage, extraction, conversion, interprétation), de la sortie, la vue (HTML, CSV, peu importe).
1. Supprimez le code inutile. Embellissez le reste.
Le résultat
Vous avez cet extrait répété:
if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post();
the_post_thumbnail('thumbnail');
endwhile;
endif;
Vous exécutez le plutôt cher à the_post()
chaque fois pour obtenir la miniature du message. Mais ce n'est pas nécessaire, vous pouvez simplement appeler:
echo get_the_post_thumbnail( $post_id, 'post-thumbnail' );
La requête
Donc, tout ce dont vous avez besoin est l'ID du post, et il est disponible sans appel the_post()
. Encore mieux: vous pouvez restreindre la requête pour récupérer uniquement les ID.
Un exemple simple:
$post_ids = array();
$args = array(
'post_type' => 'post',
'posts_per_page' => 10,
'fields' => 'ids'
);
$query = new WP_Query( $args );
if ( ! empty ( $query->posts ) )
$post_ids = $query->posts; // just the post IDs
Vous avez maintenant les identifiants et vous pouvez écrire:
foreach ( $post_ids as $post_id )
echo get_the_post_thumbnail( $post_id, 'post-thumbnail' );
Pas de frais généraux, votre code est déjà plus rapide et plus facile à lire.
La syntaxe
Notez comment j'ai aligné le =
? Cela aide à comprendre le code, car l'esprit humain est spécialisé dans la reconnaissance des formes. Soutenez cela et nous pouvons faire des choses incroyables. Créez un gâchis et nous sommes coincés très rapidement.
C'est aussi la raison pour laquelle j'ai supprimé endwhile
et endif
. La syntaxe alternative est désordonnée et difficile à lire. De plus, cela rend le travail dans un IDE beaucoup plus difficile: le pliage et le saut du début à la fin d'une expression sont plus faciles avec des accolades.
Les valeurs par défaut
Votre $args
tableau contient des champs que vous utilisez partout. Créez un tableau par défaut et écrivez ces champs une seule fois :
$args = array(
'post_type' => 'product',
'posts_per_page' => 100,
'fields' => 'ids',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'slug',
)
)
);
Encore une fois, notez l'alignement. Et notez aussi comment j'ai changé la posts_per_page
valeur.
Ne demandez jamais-1
. Que se passe-t-il lorsqu'il y a un million de messages correspondants? Vous ne voulez pas tuer votre connexion à la base de données à chaque exécution de cette requête, n'est-ce pas? Et qui devrait lire tous ces messages? Fixez toujours une limite raisonnable.
Il ne vous reste plus qu'à changer le champ $args[ 'tax_query' ][ 'terms' ]
. Nous couvrirons cela dans un instant.
2. Trouvez toutes les expressions répétitives et créez des routines
Nous avons déjà nettoyé du code répétitif, maintenant la partie difficile: l'évaluation des paramètres POST. De toute évidence, vous avez créé des étiquettes à la suite de certains paramètres. Je suggère de les renommer en quelque chose de plus facile à comprendre, mais pour l'instant nous allons travailler avec votre schéma de nommage.
Séparez ces groupes des autres, créez un tableau que vous pourrez gérer ultérieurement séparément:
$groups = array(
'fashion-follower' => array(
'q1' => 'party',
'q2' => 'clothes',
'q3' => 'shopping',
'q4' => FALSE,
'q5' => 'sunbathing',
'q6' => 'mini',
),
'the-homemaker' => array(
'q1' => 'drink',
'q2' => 'candles',
'q3' => 'house',
'q4' => 'diy',
'q5' => FALSE,
'q6' => FALSE,
)
);
Pour remplir le terms
champ manquant dans votre tableau par défaut, vous parcourez le
$groups
tableau jusqu'à ce que vous trouviez une correspondance:
function get_query_term( $groups )
{
foreach ( $groups as $term => $values )
{
if ( compare_group_values( $values ) )
return $term;
}
return FALSE;
}
function compare_group_values( $values )
{
foreach ( $values as $key => $value )
{
// Key not sent, but required
if ( empty ( $_POST[ $key ] ) and ! empty ( $value ) )
return FALSE;
// Key sent, but wrong value
if ( ! empty ( $_POST[ $key ] ) and $_POST[ $key ] !== $value )
return FALSE;
}
// all keys matched the required values
return TRUE;
}
J'ai séparé même le parcours de la liste de termes et la comparaison des valeurs, car ce sont des opérations différentes. Chaque partie de votre code ne devrait faire qu'une seule chose, et vous devez maintenir le niveau d'indentation à plat pour une meilleure lisibilité.
Maintenant que nous avons toutes les pièces, collons-les ensemble.
3. Organisation: séparez le modèle de la vue
Quand j'ai écrit modèle et vue , j'avais quelque chose en tête: l'approche MVC. Il signifie Model View Controller , un modèle bien connu pour organiser les composants logiciels. La partie manquante jusqu'à présent était le contrôleur, nous verrons comment nous l'utiliserons plus tard.
Vous avez dit que vous ne connaissiez pas grand-chose à PHP, j'espère donc que vous en savez plus sur la sortie. :) Commençons par ça:
class Thumbnail_List
{
protected $source;
public function set_source( Post_Collector_Interface $source )
{
$this->source = $source;
}
public function render()
{
$post_ids = $this->source->get_post_ids();
if ( empty ( $post_ids ) or ! is_array( $post_ids ) )
return print 'Nothing found';
foreach ( $post_ids as $post_id )
echo get_the_post_thumbnail( $post_id, 'post-thumbnail' );
}
}
Agréable et simple: nous avons deux méthodes: une pour définir la source de nos identifiants de publication, une pour rendre les vignettes.
Vous vous demandez peut-être ce que Post_Collector_Interface
c'est. Nous y arrivons dans un instant.
Maintenant, la source de notre point de vue, le modèle.
class Post_Collector implements Post_Collector_Interface
{
protected $groups = array();
public function set_groups( Array $groups )
{
$this->groups = $groups;
}
public function get_post_ids()
{
$term = $this->get_query_term();
if ( ! $term )
return array();
return $this->query( $term );
}
protected function query( $term )
{
$args = array(
'post_type' => 'product',
'posts_per_page' => 100,
'fields' => 'ids',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => $term
)
)
);
$query = new WP_Query( $args );
if ( empty ( $query->posts ) )
return array();
return $query->posts;
}
protected function get_query_term()
{
foreach ( $this->groups as $term => $values )
{
if ( compare_group_values( $values ) )
return $term;
}
return FALSE;
}
protected function compare_group_values( $values )
{
foreach ( $values as $key => $value )
{
// Key not sent, but required
if ( empty ( $_POST[ $key ] ) and ! empty ( $value ) )
return FALSE;
// Kent sent, but wrong value
if ( ! empty ( $_POST[ $key ] ) and $_POST[ $key ] !== $value )
return FALSE;
}
// all keys matched the required values
return TRUE;
}
}
Ce n'est plus si trivial, mais nous avions déjà la plupart des pièces. Les protected
méthodes (fonctions) ne sont pas accessibles de l'extérieur, car nous n'en avons besoin que pour la logique interne.
Les public
méthodes sont simples: la première obtient notre $group
tableau par le haut, la seconde renvoie un tableau d'ID de publication. Et encore une fois, nous rencontrons ce douteux Post_Collector_Interface
.
Une interface est un contrat . Il peut être signé (implémenté) par les classes. Exiger une interface, comme le fait notre classe Thumbnail_List
, signifie: la classe attend une
autre classe avec ces méthodes publiques.
Construisons cette interface. C'est vraiment simple:
interface Post_Collector_Interface
{
public function set_groups( Array $groups );
public function get_post_ids();
}
Ouais, c'est tout. Code facile, n'est-ce pas?
Ce que nous avons fait ici: nous avons rendu notre vision Thumbnail_List
indépendante d'une classe concrète alors que nous pouvons toujours nous fier aux méthodes de la classe que nous avons obtenue $source
. Si vous changez d'avis plus tard, vous pouvez écrire une nouvelle classe pour récupérer les ID de publication ou en utiliser une avec des valeurs fixes. Tant que vous implémentez l'interface, la vue sera satisfaite. Vous pouvez même tester la vue maintenant avec un objet factice:
class Mock_Post_Collector implements Post_Collector_Interface
{
public function set_groups( Array $groups ) {}
public function get_post_ids()
{
return array ( 1 );
}
}
Ceci est très utile lorsque vous souhaitez tester la vue. Vous ne voulez pas tester les deux classes concrètes ensemble, car vous ne verriez pas d'où vient une erreur. L'objet simulé est trop simple pour les erreurs, idéal pour les tests unitaires.
Maintenant, nous devons combiner nos classes en quelque sorte. C'est là que le contrôleur entre en scène.
class Thumbnail_Controller
{
protected $groups = array(
'fashion-follower' => array(
'q1' => 'party',
'q2' => 'clothes',
'q3' => 'shopping',
'q4' => FALSE,
'q5' => 'sunbathing',
'q6' => 'mini',
),
'the-homemaker' => array(
'q1' => 'drink',
'q2' => 'candles',
'q3' => 'house',
'q4' => 'diy',
'q5' => FALSE,
'q6' => FALSE,
)
);
public function __construct()
{
// not a post request
if ( 'POST' !== $_SERVER[ 'REQUEST_METHOD' ] )
return;
// set up the model
$model = new Post_Collector;
$model->set_groups( $this->groups );
// prepare the view
$view = new Thumbnail_List;
$view->set_source( $model );
// finally render the tumbnails
$view->render();
}
}
Le contrôleur est la seule partie vraiment unique d'une application; le modèle et la vue peuvent être réutilisés ici et là, même dans des parties complètement différentes. Mais le contrôleur existe uniquement pour ce seul but, c'est pourquoi nous mettons le $group
ici.
Et maintenant, vous devez faire une seule chose:
// Let the dogs out!
new Thumbnail_Controller;
Appelez cette ligne partout où vous avez besoin de la sortie.
Vous pouvez trouver tout le code de cette réponse dans cet essentiel sur GitHub .