Aggiungere il metabox "Attributi pagina" e i template di pagina alla schermata di modifica degli articoli?
(Nota del moderatore: Il titolo originale era "Come posso aggiungere il selettore 'Attributi pagina' e/o 'Attributi pagina > Template' all'editor degli articoli")
Attualmente WordPress permette l'assegnazione di un "template" solo alle Pagine (cioè post_type=='page'
). Vorrei estendere questa funzionalità anche agli Articoli (cioè post_type=='post'
).
Come posso aggiungere il metabox "Attributi pagina" e più specificamente, il selettore dei template all'editor degli articoli?
Presumo che si tratti di codice da inserire nel mio functions.php
del tema.
AGGIORNAMENTO: Sono riuscito ad aggiungere il menu a discesa dei template precaricati al mio editor di articoli, semplicemente aggiungendo l'html della select box al mio meta box personalizzato esistente. Ecco il codice che sto usando...
add_meta_box('categorydiv2', __('Opzioni Articolo'), 'post_categories_meta_box_modified', 'post', 'side', 'high');
Ed ecco la funzione che scrive le opzioni e la select box dei template...
//aggiunge il box delle categorie personalizzato
function post_categories_meta_box_modified() {
global $post;
if( get_post_meta($post->ID, '_noindex', true) ) $noindexChecked = " checked='checked'";
if( get_post_meta($post->ID, '_nofollow', true) ) $nofollowChecked = " checked='checked'";
?>
<div id="categories-all" class="ui-tabs-panel">
<ul id="categorychecklist" class="list:category categorychecklist form-no-clear">
<li id='noIndex' class="popular-category"><label class="selectit"><input value="noIndex" type="checkbox" name="chk_noIndex" id="chk_noIndex"<?php echo $noindexChecked ?> /> noindex</label></li>
<li id='noFollow' class="popular-category"><label class="selectit"><input value="noFollow" type="checkbox" name="chk_noFollow" id="chk_noFollow"<?php echo $nofollowChecked ?> /> nofollow</label></li>
</ul>
<p><strong>Template</strong></p>
<label class="screen-reader-text" for="page_template">Template Articolo</label><select name="page_template" id="page_template">
<option value='default'>Template Predefinito</option>
<option value='template-wide.php' >Nessuna Sidebar</option>
<option value='template-salespage.php' >Pagina Vendite</option>
</select>
</div>
<?php
}
E infine, il codice per catturare i valori selezionati al salvataggio...
function save_post_categories_meta($post_id) {
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return $post_id;
$noIndex = $_POST['chk_noIndex'];
$noFollow = $_POST['chk_noFollow'];
update_post_meta( $post_id, '_noindex', $noIndex );
update_post_meta( $post_id, '_nofollow', $noFollow );
return $post_id;
}
Ora, credo che tutto ciò che resta da fare sia (1) catturare il template selezionato e aggiungerlo ai post meta per questo articolo e (2) modificare index.php e single.php in modo che usi il template scelto.

Mi dispiace essere il portatore di cattive notizie, ma WordPress integra la funzionalità dei Modelli di Pagina solo per il tipo di contenuto "page", almeno nella versione 3.0 (potrebbe cambiare nelle versioni future, ma non sono a conoscenza di iniziative specifiche per modificarlo. Quindi questo è uno dei rari casi in cui sto cercando di capire come aggirare il problema senza modificare il core.)
La soluzione che ho trovato è sostanzialmente copiare il codice rilevante dal core di WordPress e modificarlo secondo le nostre esigenze. Ecco i passaggi (i numeri di riga si riferiscono alla versione 3.0.1):
Copiare la funzione
page_attributes_meta_box()
dalla riga 535 di/wp-admin/includes/meta-boxes.php
e modificarla secondo necessità.Implementare un hook
add_meta_boxes
per aggiungere la metabox creata al punto #1.Copiare la funzione
get_page_templates()
dalla riga 166 di/wp-admin/includes/theme.php
e modificarla secondo necessità.Copiare la funzione
page_template_dropdown()
dalla riga 2550 di/wp-admin/includes/template.php
e modificarla secondo necessità.Aggiungere un Modello di Articolo al tuo tema.
Implementare un hook
save_post
per abilitare il salvataggio del nome del modello di articolo al momento del salvataggio.Implementare un hook
single_template
per abilitare il caricamento del modello di articolo per i post associati.
Ora procediamo!
1. Copiare la funzione page_attributes_meta_box()
Come primo passaggio, devi copiare la funzione page_attributes_meta_box()
dalla riga 535 di /wp-admin/includes/meta-boxes.php
e ho scelto di rinominarla post_template_meta_box()
. Poiché hai chiesto solo i modelli di pagina, ho omesso il codice per specificare un post genitore e per specificare l'ordine, semplificando molto il codice. Ho anche scelto di utilizzare postmeta per questo anziché riutilizzare la proprietà page_template
per evitare potenziali incompatibilità causate da accoppiamenti involontari. Ecco il codice:
function post_template_meta_box($post) {
if ( 'post' == $post->post_type && 0 != count( get_post_templates() ) ) {
$template = get_post_meta($post->ID,'_post_template',true);
?>
<label class="screen-reader-text" for="post_template"><?php _e('Modello Articolo') ?></label><select name="post_template" id="post_template">
<option value='default'><?php _e('Modello Predefinito'); ?></option>
<?php post_template_dropdown($template); ?>
</select>
<?php
} ?>
<?php
}
2. Implementare un hook add_meta_boxes
Il passo successivo è aggiungere la metabox utilizzando l'hook add_meta_boxes
:
add_action('add_meta_boxes','add_post_template_metabox');
function add_post_template_metabox() {
add_meta_box('postparentdiv', __('Modello Articolo'), 'post_template_meta_box', 'post', 'side', 'core');
}
3. Copiare la funzione get_page_templates()
Ho pensato che avesse senso differenziare tra modelli di pagina e modelli di articolo, da qui la necessità di una funzione get_post_templates()
basata su get_page_templates()
dalla riga 166 di /wp-admin/includes/theme.php
. Invece di utilizzare il marcatore Template Name:
utilizzato dai modelli di pagina, questa funzione utilizza un marcatore Post Template:
come puoi vedere sotto.
Ho anche filtrato l'ispezione di functions.php
(non sono sicuro di come get_page_templates()
abbia mai funzionato correttamente senza questo, ma vabbè!) e l'unica cosa rimasta è cambiare i riferimenti alla parola page
in post
per una migliore leggibilità durante la manutenzione:
function get_post_templates() {
$themes = get_themes();
$theme = get_current_theme();
$templates = $themes[$theme]['Template Files'];
$post_templates = array();
if ( is_array( $templates ) ) {
$base = array( trailingslashit(get_template_directory()), trailingslashit(get_stylesheet_directory()) );
foreach ( $templates as $template ) {
$basename = str_replace($base, '', $template);
if ($basename != 'functions.php') {
// non consentire file di template in sottocartelle
if ( false !== strpos($basename, '/') )
continue;
$template_data = implode( '', file( $template ));
$name = '';
if ( preg_match( '|Post Template:(.*)$|mi', $template_data, $name ) )
$name = _cleanup_header_comment($name[1]);
if ( !empty( $name ) ) {
$post_templates[trim( $name )] = $basename;
}
}
}
}
return $post_templates;
}
4. Copiare la funzione page_template_dropdown()
Allo stesso modo, copia page_template_dropdown()
dalla riga 2550 di /wp-admin/includes/template.php
per creare post_template_dropdown()
e cambiala semplicemente per chiamare get_post_templates()
invece:
function post_template_dropdown( $default = '' ) {
$templates = get_post_templates();
ksort( $templates );
foreach (array_keys( $templates ) as $template )
: if ( $default == $templates[$template] )
$selected = " selected='selected'";
else
$selected = '';
echo "\n\t<option value='".$templates[$template]."' $selected>$template</option>";
endforeach;
}
5. Aggiungere un Modello di Articolo
Il passo successivo è aggiungere un modello di articolo per il test. Utilizzando il marcatore Post Template:
menzionato al punto #3, copia single.php
dal tuo tema in single-test.php
e aggiungi il seguente header di commento (assicurati di modificare qualcosa in single-test.php
per distinguerlo da single.php
):
/**
* Post Template: Mio Modello di Test
*/
Dopo aver completato i passaggi da #1 a #5, puoi vedere la tua metabox "Modelli di Articolo" apparire nella pagina di modifica dell'articolo:
(fonte: mikeschinkel.com)
6. Implementare un hook save_post
Ora che hai sistemato l'editor, devi effettivamente salvare il nome del file del modello di articolo in postmeta quando l'utente clicca "Pubblica". Ecco il codice per farlo:
add_action('save_post','save_post_template',10,2);
function save_post_template($post_id,$post) {
if ($post->post_type=='post' && !empty($_POST['post_template']))
update_post_meta($post->ID,'_post_template',$_POST['post_template']);
}
7. Implementare un hook single_template
Infine, devi fare in modo che WordPress utilizzi effettivamente i tuoi nuovi modelli di articolo. Puoi farlo agganciando single_template
e restituendo il nome del modello desiderato per gli articoli a cui è stato assegnato:
add_filter('single_template','get_post_template_for_template_loader');
function get_post_template_for_template_loader($template) {
global $wp_query;
$post = $wp_query->get_queried_object();
if ($post) {
$post_template = get_post_meta($post->ID,'_post_template',true);
if (!empty($post_template) && $post_template!='default')
$template = get_stylesheet_directory() . "/{$post_template}";
}
return $template;
}
E questo è tutto!
NOTA che non ho tenuto conto dei Tipi di Contenuto Personalizzati, solo di post_type=='post'
. Secondo me, gestire i tipi di contenuto personalizzati richiederebbe di differenziare tra i diversi tipi di contenuto e, sebbene non sia particolarmente difficile, non l'ho affrontato qui.

Fantastico! Sono andato a dormire con un codice quasi completo nel mio editor con lo stesso approccio di copiare le funzioni predefinite di WordPress (era completo, ma non l'avrei pubblicato visto che non l'avevo testato). :)

@sorich87 - Conosci il vecchio detto, "Chi dorme non piglia pesci!" Scherzi a parte, sto SOLO scherzando. C'è davvero solo un modo ragionevole per farlo funzionare, quindi non c'è da meravigliarsi se il tuo codice sarebbe lo stesso!

Mike, continui a stupire. Grazie mille per aver dedicato del tempo a risolvere questo problema.

@Scott B: Nessun problema, felice di aver potuto aiutare. Cerco domande ragionevolmente generiche che potrebbero potenzialmente aiutare molte persone e cerco di rispondere non solo alla persona che fa la domanda ma anche a coloro che potrebbero arrivare dopo.

WordPress ti permette di aggiungere Meta alle Categorie utilizzando un plugin:
Per fare ciò è necessario aggiungere una delle varie estensioni che aggiungono meta alle categorie (imitando ciò che le pagine ottengono di default), Simple Term Meta svolge bene questo lavoro.
N.B. WordPress 3.x è necessario per estendere le Categorie.
Dopo di che puoi utilizzare:
- add_term_meta
- update_term_meta
- get_term_meta
Utilizza Functions.php per aggiungere metodi che fanno ciò che desideri, ad esempio:
add_action('category_add_form_fields', 'category_metabox_add', 10, 1);
function category_metabox_add($tag) { ?>
<div class="form-field">
<label for="image-url"><?php _e('URL Immagine') ?></label>
<input name="image-url" id="image-url" type="text" value="" size="40" aria-required="true" />
<p class="description"><?php _e('Questa immagine sarà la miniatura mostrata nella pagina della categoria.'); ?></p>
</div>
<?php }
add_action('created_category', 'save_category_metadata', 10, 1);
function save_category_metadata($term_id)
{
if (isset($_POST['image-url']))
update_term_meta( $term_id, 'image-url', $_POST['image-url']);
}
Chiamare i nuovi campi nei temi è semplice:
<?php echo get_term_meta(get_query_var('cat'), 'image-url', true); ?>
Maggiori dettagli ed esempi: http://www.wphub.com/adding-metadata-taxonomy-terms/
