C’est à la fois une question sur "comment faire cela" et "je devrais le faire".
J'ai le site ACF-heavy, où je voudrais faire les permaliens basés sur l'un des champs ACF (appelons-le foo
). Si le champ foo
- a la valeur 123
, alors je voudrais que le permalien vers cette page soit http://example.org/s123
(le s
permet d'éviter la collision avec les post-id dans le permalien). Si cette URL est utilisée, alors il devrait l'appeler http://example.org/s123-1
et ainsi de suite.
Le champ ACF est défini sur un type de publication personnalisé. Et le site contient des informations importantes, je préfère donc laisser cette fonctionnalité de côté que d’utiliser un plugin. Il faut donc que ce soit quelque chose qui entre dans le fichier functions.php
-.
Est-il possible de faire cela? Et est-il déconseillé de jouer avec la structure de permalien de WordPress (autre que celle autorisée dans la page de permalink-settings-page)?
Addition
Je peux voir que si vous faites en sorte que les CPT aient des permaliens 'root', ça rompt les permaliens pour les posts et les pages . : - /
... Je ne savais pas que c'était si difficile de laisser un CPT disposer d'un permalien simple/agréable.
Eh bien, vous pouvez le faire de différentes manières ... L’une d’elles serait d’utiliser le filtre parse_request
et de modifier son comportement, mais cela peut facilement gâcher quelque chose.
Une autre solution consisterait à utiliser l'action save_post
et à modifier les articles post_name
afin que WordPress fonctionne normalement, mais le post_name
sera généré en fonction de votre champ personnalisé et non en fonction du titre. C'est la solution que je choisirais. Pourquoi? Dans ce cas, vous pouvez utiliser les fonctions WP pour vous assurer que les liens sont uniques ...
Alors voici le code:
function change_post_name_on_save($post_ID, $post, $update ) {
global $wpdb;
$post = get_post( $post_ID );
$cf_post_name = wp_unique_post_slug( sanitize_title( 's' . get_post_field('foo', $post_ID), $post_ID ), $post_ID, $post->post_status, $post->post_type, $post->post_parent );
if ( ! in_array( $post->post_status, array( 'publish', 'trash' ) ) ) {
// no changes for post that is already published or trashed
$wpdb->update( $wpdb->posts, array( 'post_name' => $cf_post_name ), array( 'ID' => $post_ID ) );
clean_post_cache( $post_ID );
} elseif ( 'publish' == $post->post_status ) {
if ( $post->ID == $post->post_name ) {
// it was published just now
$wpdb->update( $wpdb->posts, array( 'post_name' => $cf_post_name ), array( 'ID' => $post_ID ) );
clean_post_cache( $post_ID );
}
}
}
add_action( 'save_post', 'change_post_name_on_save', 20, 3 );
Ce n'est pas le plus joli, car les champs ACF sont sauvegardés après la publication. Vous devrez donc écraser le post_name
une fois que la publication est déjà enregistrée. Mais cela devrait fonctionner correctement.
Et il y a la deuxième partie de votre question: Comment faire des URL CPT sans slug CPT ...
WordPress utilise Rewrite Rules pour analyser la demande. Cela signifie que si la demande correspond à l'une des règles, elle sera analysée à l'aide de cette règle.
La règle pour les pages est l'une des dernières règles permettant d'attraper la plupart des demandes qui ne correspondaient à aucune règle antérieure. Donc, si vous ajoutez votre CPT sans slug, la règle des pages ne sera pas activée ...
Une façon de résoudre ce problème consiste à enregistrer CPT avec un slug, puis à modifier le comportement de leurs liens et de leurs WP. Voici le code:
function register_mycpt() {
$arguments = array(
'label' => 'MyCPT',
'public' => true,
'hierarchical' => false,
...
'has_archive' => false,
'rewrite' => true
);
register_post_type('mycpt', $arguments);
}
add_action( 'init', 'register_mycpt' );
Maintenant, les URL de ces publications ressemblent à celles-ci:
http://example.com/mycpt/{post_name}/
Mais nous pouvons facilement changer cela en utilisant le filtre post_type_link
:
function change_mycpt_post_type_link( $url, $post, $leavename ) {
if ( 'mycpt' == $post->post_type ) {
$url = site_url('/') . $post->post_name . '/';
}
return $url;
}
add_filter( 'post_type_link', 'change_mycpt_post_type_link', 10, 3 );
Maintenant, les URL seront correctes, mais ... Elles ne fonctionneront pas. Ils seront analysés à l'aide de la règle de réécriture des pages et provoqueront une erreur 404 (car aucune page ne contient une telle URL). Mais nous pouvons résoudre ce problème aussi:
function try_mycpt_before_page_in_parse_request( $wp ) {
global $wpdb;
if ( is_admin() ) return;
if ( array_key_exists( 'name', $wp->query_vars ) ) {
$post_name = $wp->query_vars['name'];
$id = $wpdb->get_var( $wpdb->prepare(
"SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND post_name = %s ",
'mycpt', $post_name
) );
if ( $id ) {
$wp->query_vars['mycpt'] = $post_name;
$wp->query_vars['post_type'] = 'mycpt';
}
}
}
add_action( 'parse_request', 'try_mycpt_before_page_in_parse_request' );
C’est peut-être une simplification exagérée de ce que je lis, mais plutôt que d’utiliser des champs ACF pour contrôler le lien permanent, pour modifier le lien permanent dans l’URL, la chose la plus simple à faire est de modifier le lien permanent dans la page de modification de cet article/cette page, que de le faire par programme.
Si cela est plus compliqué, vous voudrez peut-être consulter l'API WP_Rewrite et créer une logique personnalisée avec cela.
De plus, vous pouvez réécrire la structure permalink dans la déclaration CPT