Aggiungere il metabox "Attributi pagina" e i template di pagina alla schermata di modifica degli articoli?

10 ott 2010, 20:40:15
Visualizzazioni: 34K
Voti: 14

(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.

2
Commenti

@Scott B: Beh, ho scritto tutta la mia risposta prima di vedere che anche tu stavi lavorandoci, e sembra che tu abbia preso una direzione leggermente diversa rispetto alla tua domanda originale con le opzioni no follow e no index. Spero che quello che ho fatto abbia ancora valore per te. Se non è così, magari potrà essere utile ad altri.

MikeSchinkel MikeSchinkel
11 ott 2010 02:14:37

Sì, hai risposto alla domanda. Ho preso una strada leggermente diversa una volta realizzato che non avevo bisogno di analizzare la directory e potevo inserire i valori manualmente per i miei template specifici. Probabilmente avrò ancora bisogno di prendere in prestito parte del tuo codice per far sì che WP utilizzi il template corretto assegnato al post.

Scott B Scott B
11 ott 2010 19:36:46
Tutte le risposte alla domanda 2
7
15

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):

  1. Copiare la funzione page_attributes_meta_box() dalla riga 535 di /wp-admin/includes/meta-boxes.php e modificarla secondo necessità.

  2. Implementare un hook add_meta_boxes per aggiungere la metabox creata al punto #1.

  3. Copiare la funzione get_page_templates() dalla riga 166 di /wp-admin/includes/theme.php e modificarla secondo necessità.

  4. Copiare la funzione page_template_dropdown() dalla riga 2550 di /wp-admin/includes/template.php e modificarla secondo necessità.

  5. Aggiungere un Modello di Articolo al tuo tema.

  6. Implementare un hook save_post per abilitare il salvataggio del nome del modello di articolo al momento del salvataggio.

  7. 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:

Come appariva la Metabox dei Modelli di Articolo in WordPress 3.0
(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.

11 ott 2010 02:11:33
Commenti

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 sorich87
11 ott 2010 10:57:00

@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!

MikeSchinkel MikeSchinkel
11 ott 2010 12:08:41

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

Scott B Scott B
11 ott 2010 19:33:53

@sorich87 - Grazie per averci lavorato. Apprezzo davvero lo sforzo.

Scott B Scott B
11 ott 2010 19:34:22

@MikeSchinkel: :) era quasi esattamente lo stesso. @Scott B: prego!

sorich87 sorich87
11 ott 2010 19:47:04

@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.

MikeSchinkel MikeSchinkel
11 ott 2010 23:12:22

Qualcuno sa se esiste una soluzione migliore ora nel 2016?

JasonDavis JasonDavis
7 lug 2016 08:59:47
Mostra i restanti 2 commenti
0

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/

14 set 2013 17:27:02