WordPress Theme Options

Nov 10 2011 Published by under Allgemein, Code, Code-Snippet, PHP, Snippets, Themes, Wordpress

flattr this!

Manchmal ist es von Nöten, dass man dem User Optionen für das eigene Theme anbietet. Dies kann aus Design-Gründen, zum Beispiel für verschiedene Backgrounds oder auch eine Kategorieauswahl, zur Darstellung der Artikel in einer im Design integrierten Box.
In diesem Post möchte ich euch einen guten Weg aufzeigen, eure eigene Options-Seite für euer Theme zu bauen. Diese Seite wird ein Text-Feld beinhalten sowie eine Auswahl an verschiedenen Kategorien für eine Auflistung in einer Box. Der Clou an der Sache ist, dass wir alle Daten dieser Options-Page in einem einzigen Datenbank-Eintrag speichern.

 

Als allererstes erstellen wir eine Funktion, in welcher WordPress gesagt wird, dass wir nun eine neue Options-Page erstellen. Dadurch müssen wir uns nicht groß um die Speicherung der Daten kümmern.

//functions.php

//die funktion
function ctheme_options_init(){
  //Registrieren der Options "ctheme_theme", die Speichervariable in der Tabelle "ctheme_theme_options" und eine Validierungs-Funktion ("ctheme_options_validate", dazu später mehr)
  register_setting('ctheme_theme', 'ctheme_theme_options', 'ctheme_options_validate');
}

add_action('admin_init', 'ctheme_options_init');

 

Damit auch etwas dargestellt werden kann, benötigen wir eine do_page-Funktion. In dieser könnt ihr eine externe Datei inkludieren, um eine bessere Übersicht zu behalten. Ich schreibe es für dieses Tutorial direkt mit hinein.

<?php function ctheme_options_do_page(){
?>
<div class="wrap">
  <h2>cTheme Theme Optionen</h2>

  <form action="options.php" method="post">
    <?php //Schreibt verschiedene hidden Inputs
    settings_fields('ctheme_theme'); ?>
    <?php //Hier werden die gespeicherten Optionen abgefragt. Wir erinnern uns, dass wir alles in einem Eintrag speichern!
    $options = get_option('ctheme_theme_options'); ?>

    <table class="form-table">
      <tbody>
        <tr valign="top">
          <th scope="row">Titel der Box</th>
          <td><input type="text" value="" name="" id="" /></td>
        </tr>
        <tr>
          <th scope="row">Kategorie für die Auflistung in der Box</th>
          <td>Hier stehen dann die Kategorien..</td>
        </tr>
      </tbody>
    </table>

    <p class="submit"><input class="button-primary" type="submit" value="<?php _e('Save Changes') ?>" /></p>

    </form>
  </div>
<?php } ?>

Da wir alle Daten nur in einem Datenbankeintrag speichern, müssen wir die vom User eingegeben Daten selbst validieren.

function ctheme_options_validate($input){
	$input['boxtitle'] = ( $input['boxtitle'] == '' ) ? 'Standard-Box' : $input['boxtitle'];
	$input['categorylist'] = ( is_array( $input['categorylist'] ) ) ? $input['categorylist'] : array();
	return $input;
}

Nun müssen wir die Werte noch änderbar machen. Fangen wir mit der Input-Box an:

<tr valign="top">
  <th scope="row">Titel der Box</th>
  <td><input type="text" value="<?php echo $options['boxtitle']; ?>" name="ctheme_theme_options[boxtitle]" id="ctheme_theme_options_boxtitle" /></td>
</tr>

Wie Ihr seht, verwenden wir hier als name-Attribute den $options-Name als Array. (Hm, ist der Satz denn jetzt verständlich?)

Machen wir uns nun an die Auswahl der Kategorien. Dazu brauchen wir zwei Funktionen: Die eine listet alle Kategorien rekursive auf. Dafür ist es notwendig zu prüfen, ob die aktuelle Kategorie in der Schleife eine Unter-Kategorie hat, die zweite Funktion.

/***************
* list subcategories
* @categories wp-get_categories-Array
* @categoryId choosen category
* @label label to save in options
* @options the options
*******************/
function ctheme_options_listcategory( $categories, $categoryId, $label, &$options ) {
        //alle kategorien durchgehen, um die gewünschten Kategorien zu erhalten...
        // 0 gibt z.B. alle Top-Kategorien aus, 8 z.B. nur die, welcher eine Sub-Kategorie der Top-Kategorie 8 ist
	foreach( $categories as $category ):
                //Hat diese Kategorie die gewünschte ID?
		if( $category->category_parent == $categoryId ):
		?>
			<li>
				<input name="ctheme_theme_options[<?php echo $label; ?>][]" type="checkbox" value="<?php echo $category->term_id; ?>" <?php if(@in_array($category->term_id, $options[$label])) { echo 'checked="checked"'; } ?> /> <?php echo $category->name; ?>
				<?php
                                //Ruft nun die 2. Funktion auf, um zu prüfen, ob diese Kategorie weitere Kategorien enthält
                                if($subcats = ctheme_options_hassubcategory($categories, $category->term_id)): ?>
					<ul style="padding-left:20px; margin-bottom:14px;">
						<?php
                                                //Sollte dies der Fall sein, rufe ctheme_options_listcategory erneut auf
                                                ctheme_options_listcategory( $categories, $category->term_id, $label, $options ); ?>
					</ul>
				<?php endif; ?>
			</li>
	<?php endif;
	endforeach;
}

/* check, if the given categoryid is in the category-array */
function ctheme_options_hassubcategory( $categories, $categoryId ){
	$hasSubcategory = false;

	foreach( $categories as $category ) {
		if( $category->category_parent == $categoryId) {
			$hasSubcategory = true;
			break;
		}
	}

	return $hasSubcategory;
}

In unserer do_page-Funktion können wir die Kategorie-Funktion nun einfach mit dem Label, welchen wir in der Validierungs-Funktion angegeben haben, aufrufen.

<tr>
  <th scope="row">Kategorie für die Auflistung in der Box</th>
  <td>
    <?php
        //Alle Kategorien von WordPress mit hide_empty=0 abfragen... Wir benötigen alle Kategorien für die Optionen
        $allCategories = get_categories('hide_empty=0');

        ctheme_options_listcategory( $allCategories, 0, categorylist, $options );
    ?>
  </td>
</tr>

Als letztes müsst ihr die Options-Seite noch an die Theme-Navigation im Admin-Bereich hängen:

//register options page
add_action('admin_menu', 'ctheme_menu');

function ctheme_menu(){
	add_theme_page('cTheme Optionen', 'Optionen', 'edit_theme_options', 'ctheme-options', 'ctheme_options_do_page');
}

5 responses so far

  • Max sagt:

    Gutes Tutorial…

    wie kann man die Daten dieser Options-Page mit einem eindeutigen ID speichern?

    • fpalme sagt:

      Hallo Max,

      was für eine “eindeutige ID” möchtest du denn Speichern?

      Theoretisch kannst du dir einfach ein hidden-Field in das Formular dazu packen:

      <form action="options.php" method="post">
          <?php //Schreibt verschiedene hidden Inputs
          settings_fields('ctheme_theme'); ?>
      <input type="hidden" value="DeineEindeutigeID" name="ctheme_theme_options[deineID]" />

      Oder du schreibst Sie in die Validierungs-Funktion der Options-Page:

      function ctheme_options_validate($input){
          $input['boxtitle'] = ( $input['boxtitle'] == '' ) ? 'Standard-Box' : $input['boxtitle'];
          $input['categorylist'] = ( is_array( $input['categorylist'] ) ) ? $input['categorylist'] : array();
      	$input['deineId'] = 'ID-123';
      	return $input;
      }

      Grüße,
      Florian Palme

  • Abed sagt:

    Hallo,

    wie kann man mehrere Formulare speichern? etwas ähnliches wie bei einem plugin “contact form 7″ da kann man ein neues Formular erstellen, die erstellten Formulare werden nebeneinander angezeigt..

  • Abed sagt:

    also ich habe folgenden Code geschrieben, wie du oben beschrieben hast. Nun möchte ich mit einem Button “neues Formular” ein neue Formular erstellen und schliesslich die Formulardaten speicheren. das Problem ist, wenn ich auf “save Change” Button anklicke, werden die alte Daten in datenbank überschrieben.

    Wie kann man mehrere Formularedaten erstellen und in Datenbank speichern, ohne dass die alten Daten ersetzt werden?

    <?php
    /**
     * @package test
     * @version 1.0
     */
    /*
    Plugin Name: Test
    Plugin URI: http://www.test.de
    Description:
    Author: das ist nur ein Test
    Version: 1.0.0
    Author URI:
    */
    class test{
    
     function __construct() {
        add_action('admin_init', array( &$this, 'admin_init' ) );
        add_action('admin_menu', array( &$this, 'options_add_menu'));
    
      }
    
       function admin_init() {
        register_setting( 'options', 'options', array(&$this,'options_validate' ));
        add_settings_section('section', 'General', array(&$this,'general'), 'sf');
        add_settings_field('id', 'ID', array(&$this,'id'), 'sf', 'section');
        add_settings_field('mail', 'Email', array(&$this,'mail'), 'sf', 'section');
        }
    
     function options_add_menu() {
        add_options_page('Test', 'Test', 'manage_options', 'sf', array(&$this,'options_add_page'));
      }
    
      function options_add_page() {
    
     echo    '
    
        ';
      ?>
    
        Test
    
        <input name="Submit" type="submit" value="" />
    
        <?php
      }
        function general() {
        echo 'General Setting ';
      }
        function mail() {
        $options = get_option('options');
        $value   = $options['mail'];
        echo "";
      }
      function id() {
      	$options = get_option('options');
      	$value   = $options['id'];
      	echo "";
      }
    
     }
    
    $test = new test;
    
    ?>
    
    • fpalme sagt:

      Hallo Abed,

      du erwähntest Contact Form 7 im vorherigen Kommentar. Contact Form 7 speichert jedes einzelne Formular in einem Custom Post Type ( WordPress Codex / Post Types ).

      Um bei einer Options-Page mehrere “gleiche” Daten zu speichern, werden die Input-Felder als Array niedergeschrieben:

      <?php //Basierend auf dem Tutorial ?>
      <input type="text" value="" name="ctheme_theme_options[options][0][id]" id="ctheme_theme_options_options_0_id" />
      <input type="text" value="" name="ctheme_theme_options[options][0][mail]" id="ctheme_theme_options_options_0_mail" />

      Über eine JavaScript-Funktion fügst du dann einfach weitere Felder hinzu, wie du es benötigst.

      Darstellen kannst du sie auf der Options-Page nach dem Speichern wie folgt:

      <?php
      foreach( $options['options'] as $index => $option ){
        ?>
          <input type="text" value="<?php echo $option['id']; ?>" name="ctheme_theme_options[options][<?php echo $index; ?>][id]" id="ctheme_theme_options_options_<?php echo $index; ?>_id" />
          <input type="text" value="<?php echo $option['mail']; ?>" name="ctheme_theme_options[options][<?php echo $index; ?>][mail]" id="ctheme_theme_options_options_<?php echo $index; ?>_mail" />
        <?php
      }

      Ich hoffe, ich konnte dir damit weiter helfen..

      Grüße,
      Florian Palme

Hinterlasse eine Antwort