Archiv der Kategorie: WordPress

WordPress Stichwortsuche mit Treffer-Highlighting

Habt ihr euch auch schon manchmal gewünscht, WordPress würde die Suchergebnisse irgendwie kennzeichnen – zum Beispiel durch eine farbige Hinterlegung der gefundenen Begriffe? Manchmal ist es nämlich gar nicht so leicht herauszufinden, wo im Text sich der gesuchte Begriff (oder die gesuchten Begriffe) verstecken. Das eine durchaus übliche Sache, und ich hab mir mal ein paar Gedanken zu dem Thema gemacht und mich im Inselfisch-Kochbuch an die Umsetzung gemacht. Dabei ist ein Plugin herausgekommen, das sicher noch ein bisschen Optimierungspotential hat, aber so im Prinzip funktioniert die Sache. Wurde eh schon lang wieder einmal Zeit für ein bisschen Spaß auf der Datenbank!

Die Anforderungen

  • Es sollen ein oder mehrere Suchbegriffe (durch Leerzeichen getrennt) eingegeben werden können.
  • Zuerst sollen alle Rezepte ausgegeben werden, bei denen die gesuchten Begriffe schon im Titel vorkommen. Die Treffer werden farbig hinterlegt.
  • Dann sollen noch alle Rezepte nachfolgen, bei denen die Suchbegriffe im Rezepttext = post content vorkommen, auch hier farbig hinterlegt
  • Durch Klick auf den Rezepttitel soll man direkt zum Rezepttext gelangen.

Wir fangen natürlich mit einem Formular an

Das Plugin fängt mit einem einfachen Eingabefeld an:

/*
Plugin Name: Evis Suche mit Highlighting
Plugin URI: http://localhost/wp_ajax/wp-content/plugins/suche
Description: Eigenes Suchmodul mit Highlighting
Version: 1.0
Author: Evi Leu
Author URI: http://www.evileu.de
*/

//Formular als Shortcode einbinden
 function suche_form(){
     
    echo "<h3>Rezeptsuche mit Highlighting</h3>";
    echo "<p>Mehrere Stichworte mit Leerzeichen trennen</p>";
    
    
    echo "<form action='#' method='post'>";
    echo "<input type='text' size='100' name = 'suchstring' >";
    echo "</form>";
    

Der Inhalt des Textfeldes wird übernommen, wenn der Anwender auf Return drückt. Dann legen wir los:

if (isset($_POST['suchstring'])){
    
    //***ein oder mehrere Leerzeichen im String?
    if (strpos($_POST['suchstring']," ")>0){
        
        $suchsql = "";
        $suchsql_content = "";
        //string am leerzeichen trennen
        $strings = explode(" ",$_POST['suchstring']);
        $anzahl = count($strings);
        $ersterstring = $strings[0];
        for ($i=1; $i < $anzahl; $i++){
            //suchstring für post_title zusammenbauen
            $suchsql = $suchsql." AND post_title like '%".$strings[$i]."%' ";
            //suchstring für post_content zusammenbauen
            $suchsql_content = $suchsql_content." AND post_content like '%".$strings[$i]."%' ";
        }    
    }
    //***kein Leerzeichen im String
    else{$ersterstring = $_POST['suchstring'];
        
    }

Was hab ich gemacht? Wenn ein oder mehrere Leerzeichen im Suchstring vorhanden sind, zerlege ich den String mit explode() in ein Array. Dann baue ich mir aus allen vorkommenden Einzelstrings ein SQL-Snippet zusammen, eins für die Abfrage des post_title und eins für die Abfrage des post_content. Man kann die AND-Klauseln einfach hintereinanderhängen, es sollen ja alle Suchstrings gefunden werden. Groß/Kleinschreibung ist egal, der MySQL-Like ist nicht case sensitive. Wenn kein Leerzeichen im Suchbegriff vorkommt, übernehme ich ihn im Ganzen.

Die erste Abfrage geht auf den Titel

Mit dem zusammengebauten SQL-Snippet von oben starte ich die erste Abfrage: Dann gebe ich erstmal aus, wieviele Rezepte mit den Suchbegriffen im Titel gefunden wurden.

global $wpdb; 

    
    /******Suchstring im Titel?****/
    $alleposts = $wpdb->get_results( "SELECT * from ".$wpdb->prefix."posts 
where post_title like '%".$ersterstring."%' ".$suchsql."
    and post_type like 'post' and post_status like 'publish' order by post_title");
    
    $gefunden = $wpdb->num_rows;
    if ($gefunden == 1){
        
        echo $gefunden." Rezept mit ".$_POST['suchstring']." im Titel:";
    }
    if ($gefunden > 1){
        
        echo $gefunden." Rezepte mit ".$_POST['suchstring']." im Titel:";
    }

Dann klappere ich mit einem foreach alle Ergebnisse des ersten Selects ab und mache mit PHP ein paar Ersetzungen für das Highlighting der Suchbegriffe. Dafür benutze ich den str_ireplace, der ist nicht case sensitive. Dabei geht der erste Suchebegriff extra, für alle weiteren steppe ich mit der for-Anweisung durch unser Array von oben.

foreach($alleposts as $einpost){
        
        
        //**** ersten Suchstring im Titel highlighten
        $replace = '<span style="background-color: #FF0;">' . $ersterstring. '</span>'; // create replacement
        $content = str_ireplace( $ersterstring, $replace, $einpost->post_title );
        //***** ersten Suchstring im content highlighten
        $rezepttext = str_ireplace( $ersterstring, $replace, $einpost->post_content );
        
        //****alle weiteren Suchstrings highlighten
        for ($j=1; $j<$anzahl;$j++){
            
            $replace = '<span style="background-color: #FF0;">' . $strings[$j]. '</span>'; // create replacement
            $content = str_ireplace( $strings[$j], $replace, $content );
            $rezepttext = str_ireplace( $strings[$j], $replace, $rezepttext );
        }
        //als Accordeon ausgeben
        echo "<details><summary>".$content."</summary>";
        echo $rezepttext."</details>";
        echo "<hr>";
            
    }

Ganz am Ende benutze ich eine HTML5-Syntax für die Ausgabe des Rezepttitels als anklickbares Detail/Summary Element, auch Accordeon genannt. Das sieht dann so aus:

accordeon

accordeon

Wenn man auf das Dreieckssymbol klickt, wird der Rezepttext eingeblendet — mit Highlighting:

schweinefilet_highlighted

schweinefilet_highlighted

Das funktioniert auch mit mehreren Stichworten (es können beliebig viele sein), ich hab hier mal „butter tomate“ eingegeben:

butter_tomate

butter_tomate

Und jetzt das ganz nochmal auf den Content:

Der SQL ist nur minimal verändert und geht jetzt auf den post_content, das Highlighting funktioniert genauso wie oben, auch die Ausgabe als Accordeon:

//*******Suchstring im Content */
    
    $alleposts = $wpdb->get_results( "SELECT * from ".$wpdb->prefix."posts where 
         post_content like '%".$ersterstring."%' ".$suchsql_content." 
    and post_type like 'post' and post_status like 'publish' order by post_title");
    
    foreach($alleposts as $einpost){
        
        //**** ersten Suchstring highlighten
        $replace = '<span style="background-color: #FF0;">' . $ersterstring. '</span>'; // create replacement
        $rezepttext = str_ireplace( $ersterstring, $replace, $einpost->post_content );
        
        //****alle weiteren Suchstrings highlighten
        for ($j=1; $j<$anzahl;$j++){
            
            $replace = '<span style="background-color: #FF0;">' . $strings[$j]. '</span>'; // create replacement
            $rezepttext = str_ireplace( $strings[$j], $replace, $rezepttext );
        }
        //als Accordeon ausgeben
        echo "<details><summary>".$einpost->post_title."</summary>";
        echo $rezepttext."</details>";
        echo "<hr>";
        //}
        
    }

Das wars schon! Jetzt könnte man höchstens noch anmeckern, dass manche Rezepte zweimal auftauchen, weil sie einmal mit der Suche im Titel und ein zweites Mal mit der Suche im Content gefunden wurden, aber auch dafür sollte es eine Lösung  geben, das ist Feintuning.

Viel Spaß beim Nachbauen! Hier noch ein Beispiel, dass es auch mit mehreren Stichworten funktioniert, ich habe „butter tomate olivenöl hackfleisch knoblauch“ eingegeben:

5_suchworte

5_suchworte

Bemerkung nach Testbetrieb: immer diese Umlauts

Darauf bin ich erst später gekommen: der MySQL-Like ignoriert in der Kollation utf8_general_ci die deutschen Umlaute. So wird zum Beispiel zum Stichwort „huhn“ auch „hühnchen“ gefunden, da ü wird als u behandelt. Das wäre ja soweit noch nicht weiter tragisch, aber der PHP str_ireplace() macht sehr wohl einen Unterschied zwischen Umlauten und aeoui, da fällt das Highlighting auf die Nase… na ja, ich finde das jetzt nicht wirklich schlimm, es ist halt ein kleines Manko. Deswegen jetzt mit der Datenbankkollation rumzuexperimentieren erspare ich mir, das wäre mit Kanonen auf Spatzen geschossen.

Doppelt vorkommende Rezepte ausblenden

Bislang kamen Rezepte, die sowohl im Titel als auch im Content die eingegebenen Begriffe enthielten, doppelt vor. Das läßt sich relativ einfach unterbinden, ich merke mir einfach in einem Array, welche Rezept-IDs bei der Stichwortsuche im Titel schon gefunden wurden, und baue daraus einen String für eine not-in-Klausel. Dafür kommt noch folgender Code nach dem ersten SQL rein:

//merken, welche post ids schon gefunden wurden
    $merken = array();
    
    //Falls ein oder mehrere Rezepte gefunden wurden, IDs merken
    if ($gefunden>0){
        
            $k=0;
            foreach ($alleposts as $einpost){
            $merken[$k] = $einpost->ID;
            $k=$k+1;
            }
        }else{
            //Falls kein Rezept gefunden wurde, Dummy Eintrag mit ID 0
            $gemerkt = "(0)";
            }
    
    //Klammer für den not in aufbauen
    $gemerkt = "(";
    for ($l=0; $l < $gefunden; $l++){
   
    $gemerkt = $gemerkt.$merken[$l].", ";
    
    }
    //Klammer für den "not in" mit Dummy-Eintrag 0 abschliessen
    $gemerkt = $gemerkt."0)";

Den Dummy-Eintrag mit der 0 brauchts, damit der „not in“ nicht auf eine leere Klammer rennt und gar nichts ausgibt. Mit dem jetzt in der Variable $gemerkt gespeicherten String mit den IDs gehe ich in den zweiten SQL, der im Content sucht, und füge noch eine „not in“-Klausel  hinzu:

$alleposts = $wpdb->get_results( "SELECT * from ".$wpdb->prefix."posts where 
         post_content like '%".$ersterstring."%' ".$suchsql_content." 
    and post_type like 'post' and post_status like 'publish' 
and ID not in ".$gemerkt." order by post_title");

Das filtert alle Rezepte heraus, die bereits in der ersten SQL-Abfrage gefunden wurden.

 

Ihre Meinung interessiert mich!

Wie hat Ihnen dieser Artikel gefallen?

sehr gutgutbefriedigendausreichendmangelhaftungenügend

WordPress AJAX Autocomplete für Minimalisten

Ich bin ja bekanntermassen ziemlich hartnäckig, und obwohl ich die Lösung für das Autocomplete-Feld von David Nash toll finde, hats mir doch keine Ruhe gelassen. Das muss doch noch ein bisschen einfacher gehen, dachte ich mir und hab den Codex durchforstet. Zum Thema Using Ajax in Plugins bin ich fündig geworden, da stand doch ein (Codex-unüblich nachvollziehbares) Beispiel drin, über das habe ich mich hergemacht. Das Javascript für den Ajax-Call wird hier nicht als externes Script enqueued, sondern in die Plugin-Datei integriert. Ist aber nicht schlimm, das Script ist nämlich sehr überschaubar – aber jetzt mal der Reihe nach.

Die Vorgabe

Ich möchte gern ein Textfeld, in das ich Suchbegriffe eingeben kann, und das soll mir dann aus der Datenbank alle Post Titles ausgeben, in denen der Suchbegriff vorkommt. Das soll etwa so aussehen:

schoko

schoko

Wir basteln uns ein Plugin

Natürlich brauchen wir dazu wieder ein Formular, und ich werde auch wieder die HTML5-Datalist verwenden. Wir packen das Ganze in ein Plugin, damit wir vom Theme unabhängig sind, und tun Formular und Javascript in einen Shortcode, damit wir das ganze in einem beliebigen Beitrag oder auf einer beliebigen Seite auch ausgeben können.

Zuerst mal nur das Plugin ohne JScript und Ajax-Funktion:

<?php
/*
Plugin Name: WordPressAjax Testplugin
Plugin URI: http://localhost/wp_ajax/wp-content/plugins/wp-ajax
Description: Zum Testen von Ajax mit WordPress
Version: 1.0
Author: Evi Leu
Author URI: http://www.evileu.de
*/


/*************************************************************/
//*********Formular als Shortcode einbinden
 function asuche(){
    
    echo "<input type = 'text' id = 'textfeld' autocomplete = 'off'
 onkeyup = 'myFunction(this.value);' list = 'suchliste'>";
    
    echo "<datalist id='suchliste'>";
    echo "<div id = 'liste'>";
    echo "</div>";    
    echo "</datalist>";
    
 }
 add_shortcode('asuche', 'asuche');

Ich hab hier schon mal den Funktionsaufruf bei onkeyup mit drin, der kriegt als Parameter den Inhalt des Textfeldes mit, Script kommt gleich. Die Verbindung vom Textfeld zur Datalist geht über die id suchliste. Autocomplete = ‚off‘ damit der Browser nicht reinpfuscht. In der Datalist hab ich eine weitere Div mit der id liste angelegt, in die schreibt nachher mein Ajax-Call seine Rückgabewerte.

Das integrierte Javascript

Wie gesagt, das Scripterl ist so kurz, dass man es nicht in eine externe Datei auslagern muss, wir nehmen es in die Funktion asuche mit rein, das sieht dann so aus:

function asuche(){ ?>
     
    <script>
        function myFunction(wert){
              
        var aktwert = wert;
        var data = {
            'action': 'my_action',
            'whatever': aktwert
            
        };

        // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
        // wir sind aber nicht auf den Admin-Pages, deswegen der volle Pfad
        jQuery.post('http://localhost/wp_ajax/wp-admin/admin-ajax.php', data, function(response) {
        //    jQuery.post(ajaxurl, data, function(response) {
            
            document.getElementById("liste").innerHTML = response;
            
        });
        } //*********************End myFunction
        
    </script>
    <?php
...

Was passiert hier? Zuerstmal wird der als Parameter übergebene Wert des Textfeldes auf die Variable aktwert gelegt, diese kommt in die data-Parameter des Ajaxcalls mit rein. Der erste Parameter mit dem ‚action‘ definiert, welche Funktion nachher aufgerufen werden soll, die kommt gleich im Anschluss. Mit dem JQuery.post(…) wird die Anfrage an den admin-ajax.php weitergeleitet und die response definiert. Die macht nichts anderes als die Div mit der id liste mit dem Rückgabewert der aufgerufenen Funktion zu belegen, konkret füllt sie die Options-Liste unserer Datalist.

Was weniger schön ist: die Url zur admin-ajax.php steht hier noch als langer Rattenschwanz mit drin, das könnte man sicher schöner lösen. Wenn man zum Beispiel das JQuery-Script auslagern und per enqueue laden würde, könnte man mit wp_localize_script den Pfad als Variable mitgeben – aber das sind jetzt schon Feinheiten.

Damit der Funktionsaufruf klappt: Add Action

Ich habs zweimal drin, sowohl für die Admin-Ansicht als auch für nicht eingeloggte User:

add_action( 'wp_ajax_my_action', 'my_action' );
add_action( 'wp_ajax_nopriv_my_action', 'my_action' );

Jetzt fehlt uns noch die tatsächliche Funktion, die den Übergebenen Parameter aktwert entgegennimmt und und die passenden  Werte aus der Datenbank abruft.

Die PHP-Funktion

Da wir uns im Kontext von WordPress bewegen, brauchen wir keinen externen Datenbankzugriff mit mysqli oder PDO, sondern können wie gewohnt mit dem $wpdb-Objekt arbeiten. Die Funktion sieht so aus:

function my_action() {
    global $wpdb; 

    $whatever = $_POST['whatever'];
    
    /**********************************************/
    $alleposts = $wpdb->get_results( "SELECT * from ".$wpdb->prefix."posts 
where post_title like '%".$whatever."%' 
    and post_type like 'post' and post_status like 'publish'");
    foreach($alleposts as $einpost){
        
        echo "<option>".$einpost->post_title."</option>";
}
    /**********************************************/
    
    
    wp_die(); // this is required to terminate immediately and return a proper response
} //**********End function my_action

Unsere übergebene Variable whatever wird nicht anders verarbeitet, als ob sie aus einem Formular direkt käme, dafür sorgt der Call mit dem jQuery.post(…). Der Rest ist wirklich simpel, ich suche mir aus der Tabelle wp_posts alle Einträge, die unseren Suchbegriff matchen, gebe die gefundenen Post Titel mit der Foreach-Schleife aus und klebe noch die Option-Tags für unsere Datalist dran. Fertig ist unser Autocomplete-Feld!

suchwort_back

suchwort_back

Nachtrag: JS ausgelagert und Pfad übergeben

Wie ich oben schon angemerkt habe, ist es nicht so ideal dass im Javascript der volle Pfad zur admin-ajax.php steht. Das geht auch besser. Das Script kommt aus der Plugin-Datei raus, ich nenne es mal wp_ajax.js, und es sieht so aus:

function myFunction(wert){
                
        var aktwert = wert;
        var data = {
            'action': 'my_action',
            'whatever': aktwert
            };

        // der volle Pfad zur admin-ajax.php liegt auf my_ajaxurl
        jQuery.post(my_ajaxurl, data, function(response) {
                    
            document.getElementById("liste").innerHTML = response;
            
        });
        } //*********************End myFunction

Die Variable my_ajaxurl kriegt ihren Wert über wp_localize_script, das geht in einem Aufwasch mit dem Einbinden der externen Javascript-Datei, dazu stellt man folgenden Code an den Anfang des Plugins:

/*********Externes Script einbinden und Pfad zur admin-ajax.php übergeben*/
function mysite_js() {
      
    wp_enqueue_script('mysite-js', plugins_url().'/wp_ajax/wp_ajax.js', array('jquery'), false, false);
    
    wp_localize_script( 'mysite-js', 'my_ajaxurl', admin_url( 'admin-ajax.php' ) );
 
   }
add_action('wp_enqueue_scripts', 'mysite_js');

Dann kann das JS aus der Plugindatei raus, das sorgt für mehr Übersicht und ist wesentlich eleganter gelöst.

Was ich jetzt noch gern hätte

Wenn man einen Rezepttitel angewählt und auf Return gedrückt hat, möchte ich gerne das gewählte Rezept anzeigen lassen. Aber dazu muss ich mir noch ein, zwei Gedanken machen, meine bisherige Lösung mit der angehängten Rezept-ID ist nämlich eine ziemliche Krücke, das müsste eleganter gehen. Ich geh mal forschen…. und dafür gibts dann einen neuen Beitrag.

Ihre Meinung interessiert mich!

Wie hat Ihnen dieser Artikel gefallen?

sehr gutgutbefriedigendausreichendmangelhaftungenügend

WordPress Autocomplete AJAX deutsch – Übersetzung des Tutorials von David Nash

Übersetzung des Tutorials von David Nash

Wie ich im vorigen Artikel schon erwähnt hatte, hat David Nash in seinem Blog ein tolles Tutorial über Autocomplete (Auto-Vervollständigen) mit Hilfe von AJAX in WordPress geschrieben. Ich habe von David die Erlaubnis, es zu übersetzen und auf dieser Seite zur Verfügung zu stellen. Das mache ich doch mit dem grössten Vergnügen – viel Spaß beim Nachbauen, und viel Erfolg!

Einleitung

Dies wurde für ein Projekt mit einer umfangreichen Datenbank realisiert, mit ca. 14.000 eingetragenen Geschäftsadressen. Es gibt eine Anmeldungsseite, auf der die Benutzer auswählen können, für welche Firma sie arbeiten. 14.000 sind viel zu viele Optionen für ein SELECT (drop-down) Feld, und ich wollte auch nicht so viel Last auf der MySQL Datenbank erzeugen.

Meine Lösung: ein Autocomplete-Textfeld, das die WordPress-Datenbank ausliest.

Ich gehe schrittweise vor, und stelle sicher dass jeder Schritt korrekt läuft, ehe ich den nächsten beginne. Hier ist das schrittweise Vorgehen:

Front-End JavaScript

Wir benutzen ein Child-Theme, weil wir ein Premium-Theme anpassen. In die functions.php kommt folgender Code, um die JavaScript-Datei zu laden:

Wir legen im Child-Theme Verzeichnis die Datei /js/mysite.js an, die sieht so aus:

Wenn man jetzt irgendeine Seite auf der Site neu lädt, kommt „jQuery loaded“ in einer JavaScript-Alertbox, das funktioniert also. Man hätte auch console.log(‘hello’) benutzen und die Developer Console in Chrome überpüfen können.

Als nächstes habe ich mir jQuery-autocomplete heruntergeladen. Ich hätte auch das jQuery-UI autocomplete benutzen können, aber ich benutze es sonst nicht und belasse die Sache lieber leichtgewichtig.

Aus dem Download kopiere ich mir die Dateien jquery.auto-complete.css und jquery-autocomplete.js nach /js/ – das selbe Unterverzeichnis, in dem mysite.js liegt.

Dann wird die functions.php angepasst um die Bibliothek zu laden:

function mysite_js() {

wp_enqueue_script('autocomplete', get_stylesheet_directory_uri().'/js/jquery.auto-complete.js', array('jquery')); 

wp_enqueue_script('mysite-js', get_stylesheet_directory_uri().'/js/mysite.js', array('jquery', 'autocomplete')); 

wp_enqueue_style('autocomplete.css', get_stylesheet_directory_uri().'/js/jquery.auto-complete.css');
}

add_action('wp_enqueue_scripts', 'mysite_js');

Jetzt die Seite neu laden, und sicherstellen dass die Library in der Chrome Developer Console unter dem „Sources“-Tab auftaucht.

Der AJAX Code

Als nächstes wird die mysite.js upgedatet, um etwas sinnvolles zu tun:

jQuery(document).ready(function($) { 

$('#company_works_at').autoComplete({
source: function(name, response) {

$.ajax({
type: 'POST',
dataType: 'json',
url: '/wp-admin/admin-ajax.php',
data: 'action=get_listing_names&name='+name,
success: function(data) {

response(data);

}

});

}
});
});

Dabei ist #company_works_at das Textfeld auf der Registrierungsseite, das den Autocomplete bekommen soll. Ich bin dabei der Dokumentation auf der Autocomplete-Seite gefolgt – die Source-Funktion braucht ein „response“-Callback um zu funktionieren, dies ist die „success“-Funktion im Aufruf von jQuery $.ajax().

Das PHP, das die AJAX Daten von WordPress schickt

In der functions.php kommt Folgendes hinzu:

//get listings for 'works at' on submit listing page

add_action('wp_ajax_nopriv_get_listing_names', 'ajax_listings');
add_action('wp_ajax_get_listing_names', 'ajax_listings');

function ajax_listings() {

global $wpdb; //get access to the WordPress database object variable

//get names of all businesses

$name = $wpdb->esc_like(stripslashes($_POST['name'])).'%'; //escape for use in LIKE statement

$sql = "select post_title 

 from $wpdb->posts 

 where post_title like %s 

 and post_type='job_listing' and post_status='publish'"; 

$sql = $wpdb->prepare($sql, $name);

$results = $wpdb->get_results($sql); 

//copy the business titles to a simple array

$titles = array();

foreach( $results as $r )

$titles[] = addslashes($r->post_title); 

echo json_encode($titles); //encode into JSON format and output 

die(); //stop "0" from being output

}

Das JavaScript, das den AJAX Call absetzt schickt die Daten in „name“. Ich benutze stripslashes() damit Namen mit Apostrophen etc. auch funtionieren. Ich benutze esc_like() aus Sicherheitsgründen. Das ‚%‘ am Ende bewirkt, dass nur auf die führenden Buchstaben gematcht wird. Wenn zum Beipsiel ein Benutzer „The“ eingibt möchte ich „The Best Business“ sehen, und nicht „Not the best business“. Aber wenn „Not“ einegegeben wird, möchte ich „Not the best business“ sehen.

Update: Wenn man alle Posts sehen will, das „and post_type=‚job_listing'“ aus dem $sql oben entfernen.

Testen, ob es funktioniert

Ich klicke auf das Autocomplete-Feld, tippe drei Buchstaben und bekomme eine ziemlich rasche Reaktion. Es schlägt mehrere Firmen vor, aus denen der Benutzer auswählen kann.

Dies ist nur ein Textfeld, und es erlaubt es dem Benutzer auch einen Namen einer Firma einzugeben, die nicht in der Datenbank ist. Wenn man möchte könnte man mehr Restriktionen anlegen, und statt dem Text auch die ID der Firma speichern. Man könnte dann auch in einem anderen Template einen Link auf die Firma einfügen.

Das war’s – so sollte es es klappen

Soweit das Tutorial von David Nash. Hier noch einmal der Link zu seinem Blog. Es lohnt sich, dort auch einmal durch die Kommentare durchzuschauen, da sind noch viele wertvolle Tipps drin.

 

 

Ihre Meinung interessiert mich!

Wie hat Ihnen dieser Artikel gefallen?

sehr gutgutbefriedigendausreichendmangelhaftungenügend

WordPress und AJAX für Autocomplete – eine erste Annäherung

Einleitung

Ich hab mich kürzlich in einem Projekt mal ein bisschen mit den Grundlagen von AJAX beschäftigt, und finde es bietet wirklich faszinierende und in der Praxis gut anwendbare Möglichkeiten. Besonders g’wandt ist die Möglichkeit, zum Suchen bestimmter Datenbankeinträge ein Autocomplete oder Auto-Vervollständigen einzubauen. Der Benutzer tippt ein paar Buchstaben (in der Regel drei) in ein Textfeld ein, und man holt via AJAX die gematchten Einträge aus der Datenbank. Das, so hab ich mir gedacht, hätte ich gerne für eine komfortable Suche nach Rezepten im Inselfisch-Kochbuch, das sind nämlich mittlerweile über dreihundert und somit zuviel für ein Dropdown-Feld. Das könnte in etwa so aussehen:

form_leer

form_leer

Man stellt ein kleines Formular zur Verfügung, in das der Benutzer Text eingeben kann. Sobald in der Datenbank passende Einträge gefunden werden, werden diese als Auswahlliste angezeigt. Ich geb mal sal ein, hier ist das Ergebnis:

suche_sal

suche_sal

Das ist doch schon mal ganz schick, oder? Und nicht über die Nummern (#152) wundern, die brauchen wir später noch. Wenn der Benutzer einen Eintrag ausgewählt hat und auf Return drückt, soll dann das Rezept angezeigt werden, aber bis dahin ist es noch ein Stückchen weit. WordPress stellt nämlich eine ganz eigene Logik für die Verwendung von AJAX zur Verfügung, und die ist ein bisschen widerborstig. Aber professionelle Hilfe ist geboten:

Super Tutorial zum Thema

…von David Nash: https://davidnash.com.au/create-an-auto-complete-field-in-wordpress/

David erklärt wirklich Step by Step und fantastisch nachvollziehbar, auf was es ankommt. Das kann sich wirklich jeder selber reinziehen, das funktioniert direkt auf Anhieb.

Benötigtes Helferlein: jquery autocomplete

Kann man sich hier herunterladen: https://goodies.pixabay.com/jquery/auto-complete/demo.html

Man braucht nur die beiden Dateien jquery.auto-complete.css und jquery-autocomplete.js.

Kleine Ergänzungen zu Davids Tutorial

Das Eingabeformular

Um das Ganze auch ausprobieren zu können, braucht man natürlich ein Eingabeformular. Ich hab eins als Shortcode angelegt, da sieht in meiner functions.php so aus:

 function auto_form(){
    
    echo "<h3>Beispiel Rezeptsuche Autocomplete</h3>";
    
    echo "<form action='#' method='post'>";
    echo "<input type='text' size='40' name = 'auswahl' id = 'rezepte_auswahl'>";
    
    echo "</form>";
    
        
    if (isset($_POST['auswahl'])){
    echo "Vielen Dank! Ihre Auswahl :".$_POST['auswahl']."<br>";
    
   
    } //end if isset
 }
 add_shortcode('a_form', 'auto_form');

Wichtig ist hier die id des Eingabefeldes, die wird dann in unserer js-Datei referenziert:

jQuery(document).ready(function($) {    
    
    $('#rezepte_auswahl').autoComplete({
        source: function(name, response) {
            $.ajax({
                type: 'POST',
                dataType: 'json',
                url: '/wordpress/wp-admin/admin-ajax.php',
                data: 'action=get_listing_names&name='+name,
                success: function(data) {
                    response(data);
                }
            });
        }
    });
 
});

Wichtig ist hier auch die URL der admin-ajax.php, die muss man gegebenenfalls anpassen.

Nachtrag: ich hab mir eine andere Lösung ergooglet

Man kann mithilfe der WordPress-Funktion wp_localize_script() den Pfad zum Admin-Verzeichnis als Variable an das Script übergeben. Dazu ergänzt man die function mysite_js() wie folgt:

function mysite_js() {
    wp_enqueue_script('autocomplete', get_stylesheet_directory_uri().'/js/jquery.auto-complete.js', array('jquery'), false, false);
    
    wp_enqueue_script('mysite-js', get_stylesheet_directory_uri().'/js/mysite.js', array('jquery', 'autocomplete'), false, false);
    
    wp_localize_script( 'mysite-js', 'my_ajaxurl', admin_url( 'admin-ajax.php' ) );
 
    wp_enqueue_style('autocomplete.css', get_stylesheet_directory_uri().'/js/jquery.auto-complete.css');
 
}
add_action('wp_enqueue_scripts', 'mysite_js');

Dann kann man im Script mysite.js für die URL einfach die Variable my_ajaxurl einsetzen:

jQuery(document).ready(function($) {    
    
    $('#rezepte_auswahl').autoComplete({
        source: function(name, response) {
            $.ajax({
                type: 'POST',
                dataType: 'json',
                url: my_ajaxurl,
                //url: '/wordpress/wp-admin/admin-ajax.php',
                data: 'action=get_listing_names&name='+name,
                success: function(data) {
                    response(data);
                }
            });
        }
    });
 
});

Das aber nur als kleiner Tipp am Rande.

Ich hole mir noch die Post-ID

Dazu passe ich die Funktion ajax_listings() ein bisschen an:

function ajax_listings() {
    global $wpdb; //get access to the WordPress database object variable
 
    //get names of all businesses
    $name = $wpdb->esc_like(stripslashes($_POST['name'])).'%'; //escape for use in LIKE statement
    
    $sql = "select post_title, ID 
        from $wpdb->posts 
        where post_title like %s 
        and post_type='post' and post_status='publish'";
 
    $sql = $wpdb->prepare($sql, $name);
    
    $results = $wpdb->get_results($sql);
 
    //copy the business titles to a simple array
    $titles = array();
    foreach( $results as $r )
        $titles[] = addslashes($r->post_title." #".$r->ID);
        
    echo json_encode($titles); //encode into JSON format and output
    
    die(); //stop "0" from being output
}

In den Select kommt noch die ID mit rein, und die hänge ich in der Foreach-Schleife auch noch mit an die Ausgabe dran, mit einem # vorneweg.

Extrahieren der ID im Formular

Wenn der Benutzer einen Listeneintrag ausgewählt und auf Return gedrückt hat, soll ja etwas passieren: nämlich das gewählte Rezept ausgegeben werden. Das „Return-Drücken“ erwischt man mit einem If (ISSET…), dann zerlege ich mir die entsprechende Variable und hole mir nur die Zahl nach dem #.

function auto_form(){
    echo "<a name='form'></a>"; 
    echo "<h3>Beispiel Rezeptsuche Autocomplete</h3>";
    
    echo "<form action='#form' method='post'>";
    echo "<input type='text' size='40' name = 'auswahl' id = 'rezepte_auswahl'>";
   
    echo "</form>";
    
        
    if (isset($_POST['auswahl'])){
    echo "Vielen Dank! Ihre Auswahl :".$_POST['auswahl']."<br>";
    
    //***********Action
    $text = strstr($_POST['auswahl'], '#');
    $text=substr($text,1); 
    echo "Ich bin die Nummer ".$text;
    ///*****end Action
    } //end if isset
 }

Jetzt liegt die ID des gewählten Rezeptes auf der Variablen $text, mit der arbeiten wir weiter und geben einfach den post_content aus:

global $wpdb;
    $sql = "select post_content, ID 
        from $wpdb->posts 
        where ID like ".$text." 
        ";
    
    $results = $wpdb->get_results($sql);
    
    foreach ($results as $r){echo $r->post_content;}

Damit wird das Rezept angezeigt, sobald der Benutzer seine Auswahl getroffen und auf Return gedrückt hat:

salatbowle

salatbowle

Man könnte natürlich auch einen Link zum Rezept einbauen, aber ich lasse es mal so, dann muss der Benutzer nicht woanders hin wechseln, wenn er noch ein Rezept suchen möchte.

Man könnte auch noch die Suche ein bisschen in der Funktionalität verändern, wenn man zum Beispiel nicht nur nach Einträgen suchen möchte, die mit der eingegebenen Zeichenfolge beginnen, sondern alle, in denen die Zeichenfolge enthalten ist. Dann kann man in der function ajax_listings() die Suchvariable einfach anpassen und die Wildcard % noch vornedran setzen:

$name = '%'.$wpdb->esc_like(stripslashes($_POST['name'])).'%';

Das findet z.B. alle Einträge mit salat im Titel, auch nicht unpraktisch:

instring_salat

instring_salat

Alles in allem: eine superpraktische Funktionalität, und dank des grossartigen Tutorials von David Nash einfach umzusetzen. Gefällt mir ausserordentlich gut!

Kleiner Tipp am Ende:

Wenn es zwischendurch so aussieht, als ob WordPress die eigentlich geladenen js-Scripts nicht mehr kennt – Browsercache löschen!

 

Ihre Meinung interessiert mich!

Wie hat Ihnen dieser Artikel gefallen?

sehr gutgutbefriedigendausreichendmangelhaftungenügend

WordPress, Joomla und Drupal: Theme-Erstellung im Vergleich

Also, ich hab ja kürzlich das Anlegen eigener Templates/Themes in allen drei CMS ein bisschen angerissen und die Basics zusammengeschrieben. Da bietet es sich an ein Resumee zu ziehen, was ich hiermit versuche. Mein völlig subjektiver Winner ist:

Joomla – so einfach kann es sein

Sobald man den Zusammenhang der definierenden XML-Datei templateDetails.xml und den Modulpositionen in der index.php überrissen hat, kann man schon richtig loslegen. Kein Gewühle in unverständlichem PHP-Code, kein umständliches Einbinden externer Skripte. Dadurch, dass man in Joomla über die Kategorien und Module im Backend nahezu unendliche Konfigurationsmöglichkeiten hat, ist es gar nicht notwendig tiefer in die Template-Logik einzusteigen, man kann fast alles über die Administrationsoberfläche einstellen. Dabei kann man sich allerdings auch ganz schön verzetteln – eine gute Doku ist hier wirklich unabdingbar, sonst kann man nie nachvollziehen warum, wie und weshalb wer an welchen Schräubchen gedreht hat.

Was ein bisschen übersichtlicher sein könnte: die Modulzuordnung in der Admin-Oberfläche. Da fehlt eine Möglichkeit, sich nur die Modulpositionen eines bestimmten Templates anzeigen zu lassen (oder ich hab sie nicht gefunden). So wie es ist muss man sich bei der Modulpositionierung durch eine fusselige Liste aller Templates mit allen Modulpositionen durchscrollen, da sind Fehlklicks vorprogrammiert.

Das wird allerdings beinahe ausgeglichen durch die hervorragende Möglichkeit, sich die Modulpositionen auf der Webseite anzeigen zu lassen. Das geht, indem man im Browser an die URL den Parameter ?tp=1 anhängt, das sieht dann z. B. so aus: http://localhost/jsite/?tp=1, damit kriegt man einen anschaulichen Überblick, wo man auch gleich erkennt wenn am css noch was nicht stimmt.

joomla_tp

joomla_tp

Alles in allem ist die Erstellung eines eigenen Templates in Joomla ein recht vergnüglicher Prozess, das Positionieren der benötigten Module geht recht flott von der Hand und die Feineinstellungsmöglichkeiten über die Adminoberfläche sind sehr weitreichend, ohne dass man in den Templatecode eingreifen muss. Ich kann auch jedem die kurze und knackige Joomla-Dokumentation zum Thema ein einfaches Template erstellen empfehlen, damit geht echt ein Schnellstart!

Ein guter zweiter Platz: Drupal mit Views

Ohne Views geht nämlich nahezu gar nichts, wenn man seine Inhalte auch übersichtlich ausgeben möchte. A propos Inhalte: die selbstdefinierten Inhaltstypen sind eine der grossen Stärken von Drupal, wenn man die vernünftig nutzt spart man sich einen Haufen Template-Gefiddel. Ein eigenes Template anzulegen ist jetzt eigentlich auch nicht weiter schwierig, wenn man als Vorlage die generische page.tpl.php nutzt und keine Scheu davor hat, darin Elemente herumzuschubsen und umzugruppieren. Auch in Drupal kommt einem eine Vorschau der Template-Elemente zu Hilfe, unter Struktur->Blöcke->Blockregionen veranschaulichen kann man schnell überprüfen ob das Layout passt:

blockregionen

blockregionen

Da man alle Views auch als Blöcke definieren und ins Layout einpassen kann, ist man in der Ausgabe der gewünschten Daten nahezu unendlich flexibel, da bleibt so gut wie kein Wunsch offen. Besonders die Multiblog-Funktionalität über die unterschiedlichen Inhaltstypen und Taxonomien ist easy in der Realisierung und macht es einem leicht, die Seite sauber zu strukturieren.

Ich hätte mir höchstens eine einfachere Möglichkeit des Seitendesigns gewünscht als die page.tpl.php anzupassen, die ist doch ein bisschen unübersichtlich und tendiert zum div-Wildwuchs. Und noch etwas, was wirklich nervt: man kommt bei der Template-Entwicklung nicht darum herum, ständig den Cache zu leeren, weil man seine Änderungen sonst im Zweifelsfall erstmal nicht sieht. Das kostet Zeit und nervt, da wäre es wünschenswert, wenn man eine Möglichkeit hätte so etwas wie einen Entwicklermodus einzuschalten, in dem das Caching abgeschaltet werden kann.

Das gute alte WordPress auf Rang drei

Da merkt man halt schon, dass die Software etwas in die Jahre gekommen ist. Mit einem einfachen Seitenaufbau mit einem Kopfbereich, einer Inhaltszone mit ein paar statischen Seiten, einem Blog und einer Sidebar ist man recht schnell dabei, aber wenn man mehr will, gehts gleich ans Eingemachte. Entweder man arbeitet sich selber in die WordPress-API ein (und die ist eine Wissenschaft für sich) oder man verläßt sich auf die Funktionalitäten zusätzlicher Plugins. Von denen gibt es zwar unzählige für jeden Zweck und Geschmack, aber ich kauf nicht so gern die Katze im Sack, und die meisten Plugins sind grottenschlecht bis gar nicht dokumentiert. Da hat man leicht mal eins installiert, das einem die ganze Site lahmlegt oder unerklärliche Fehlfunktionen auslöst, und dann hat man das Gfrett herauszufinden wer denn jetzt wirklich der schwarze Peter war.

Auch eine komfortable Datenbank-Abfragemöglichkeit wie Drupals Views oder eine fein differenzierte Einstellmöglichkeit nahezu aller Parameter für die Anzeige wie in Joomla sucht man vergebens, man muss sich im Zweifelsfall selber in die vorhandenen Theme-Dateien einarbeiten und sie nach eigenem Bedarf anpassen, und eigene Plugins und Widgets entwickeln. Das war vor ein paar Jahren noch akzeptabel, jetzt aber laufen die beiden jüngeren CMS dem alten WordPress da um Längen den Rang ab.

Nur einen nicht so leicht zu schlagenden Vorteil hat WordPress: für kleinere, einfachere Webseiten ist es immer noch das Anwenderfreundlichste, am Leichtesten zu bedienende CMS auf dem Markt. Start Blogging – das ist kein leerer Werbespruch, das ist nach wie vor WordPress‘ grosse Stärke! Für den Einzelunternehmer, Handwerker, Arzt oder Anwalt, der seine Firma mit einer Visitenkarte im Web vorstellen möchte, ist WordPress nach wie vor die ideale Lösung. Auch für mittlere Benutzergruppen wie Vereine, kleinere Behörden und soziale Dienstleister ist es ideal, weil kostengünstig in der Realisierung und leicht zu pflegen. Der Markt für WordPress als „kleine“ Lösung für den Webauftritt ist riesengross und wird es aller Voraussicht nach noch lange bleiben.

Ihre Meinung interessiert mich!

Wie hat Ihnen dieser Artikel gefallen?

sehr gutgutbefriedigendausreichendmangelhaftungenügend

Noch mehr Widget-Bastelei: ein eigenes Dropdown-Feld

Ich hab im vorigen Artikel etwas geschummelt und mir ein fertiges Konstrukt für das Dropdown-Feld mit den Kategorien ergooglet, das ging so:

<p>
    <label for="<?php echo $this->get_field_id( 'select' ); ?>">Kategorie auswählen:</label>
    <?php wp_dropdown_categories( array( 'show_option_none' =>' ','name' => $this->get_field_name( 'select' ), 'selected' => $select ) ); ?>
  </p>

Wer unbedingt genaueres dazu wissen möchte, kanns im Codex bei wp_dropdown_categories nachschauen, ich spar mir das, weil es der volle Overkill mit ungefähr 20 Parametern ist, und die Source-Beispiele auch nicht gerade zur Erhellung beitragen.

Dropdown-Felder in Widgets braucht man aber immer wieder, und ich stelle hier eine realtiv einfache Methode vor, wie man sie sich selbst zusammenbastelt.

Das Anwendungsbeispiel

Ich möchte im Widget ein Dropdown-Feld haben, in dem man einen Post Type wählen kann, die Optionen sollen Post, Page und Custom Type heissen. Dazu erweitern wir den Widget-Code aus dem vorigen Artikel um ein Feld namens „posttype“, ich markiere hier mal in rot wo man da überall eingreifen muss:

    function form($instance)
  {
    $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) );
    $title = $instance['title'];
    
    $instance = wp_parse_args( (array) $instance, array( 'posttype' => '' ) );
    $select = $instance['posttype'];
?>
  <p><label for="<?php echo $this->get_field_id('title'); ?>">Titel: <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo attribute_escape($title); ?>" /></label></p>
  
   <--! HIER KOMMT DAS DROPDOWN HIN-->
   
       
<?php
  }
 function update($new_instance, $old_instance)
  {
    $instance = $old_instance;
    
    $instance['title'] = $new_instance['title'];
    $instance['posttype'] = $new_instance['posttype'];
    
    return $instance;
  }

Dann kommt in die function form() folgende Konstruktion für das Dropdown-Feld, ich markiere grün wo man da eigene Werte einträgt:

<p>Post Type auswählen
   <select id="<?php echo $this->get_field_id('posttype'); ?>" name="<?php echo $this->get_field_name('posttype'); ?>" class="widefat" style="width:100%;">
    <option <?php selected( $instance['posttype'], 'Post'); ?> value="Post">Post</option>
    <option <?php selected( $instance['posttype'], 'Page'); ?> value="Page">Page</option> 
    <option <?php selected( $instance['posttype'], 'Custom Type'); ?> value="Custom Type">Custom Type</option>   
    </select>
   </p>

Das erzeugt uns im Widget das Dropdown-Feld mit den drei möglichen Werten:

dropdown_drei_werte

dropdown_drei_werte

Für die Ausgabe modifizieren wir jetzt nur noch die function widget() ein bisschen:

 function widget($args, $instance)
  {
    extract($args, EXTR_SKIP);
 
    echo $before_widget;
    
    $title = $instance['title'];
    $posttype = $instance['posttype'];
     
    // WIDGET CODE KOMMT HIERHIN
    echo "<h3>".$title."</h3>";
    
    echo "Post Type= ".$posttype."<br>";
    
    echo $after_widget;
  }

Fertig! Ausgabe:

posttype_ausgabe

posttype_ausgabe

Nicht besonders spektakulär, aber ausbaufähig. Ich denke, das kann man immer wieder mal brauchen, wenn der User aus einer vorgegebenen Liste eine Auswahl treffen soll.

Kleine Ergänzung: ein numerisches Feld geht auch

Das geht ganz einfach, indem man den type des Textinput-Felds auf number stellt, der Rest bleibt wie vorher:

<p><label for="<?php echo $this->get_field_id('anzahl'); ?>">Anzahl: <input id="<?php echo $this->get_field_id('anzahl'); ?>" 
name="<?php echo $this->get_field_name('anzahl'); ?>" type="number" value="<?php echo attribute_escape($anzahl); ?>" /></label></p>

Schon klappts:

numerisch

numerisch

 

Ihre Meinung interessiert mich!

Wie hat Ihnen dieser Artikel gefallen?

sehr gutgutbefriedigendausreichendmangelhaftungenügend

Widget-Basteln macht Spaß: ein Widget mit Benutzereingaben

Das, so gebe ich ehrlich zu, ist zusammengeklaut und abgekupfert und herausgegooglet. Da aber das Widgetbasteln in WordPress erstens Spaß macht und zweitens vielfältige Einsatzmöglichkeiten bietet, beschreibe ich hier doch mal recht ausführlich meinen Weg zum eigenen Widget mit Benutzereingaben. Das Meiste hab ich aus dieser Anleitung hier bei makuseof.com gelernt, da wird einem das funktionale Gerippe eines WordPress-Widgets vorgelegt. Ebenfalls sehr aufschlussreich ist diese Anleitung hier bei wpmudev.

Die Vorgabe: ein Featured Category Widget

Ich hab mir eine relativ einfach Aufgabe gestellt. Mein Widget soll ausgeben, wieviele Rezepte bisher veröffentlich wurden, und dann soll man noch eine Featured Category anwählen können, für die dann ebenfalls die Anzahl der Rezepte ausgegeben wird, also so in der Art:

Rezepte insgesamt 317

56 davon Vegetarisch

Dann hätte ich noch gern einen frei wählbaren Titel für das Widget. Das hört sich simpel an, war aber in der Realisieung nicht ohne, nicht zuletzt weil der Codex zu den Widget-Funktionalitäten sehr lückenhaft und umständlich ist. Aber wir fangen mal ganz vorne an, und sehen wie weit wir kommen.

Anlegen der Widget-Datei

Man erzeugt im Plugins-Verzeichnis seiner WordPress-Installation ein neues php-File mit dem Namen des Widgets, z. B. mein-tolles-widget.php. Die kriegt jetzt erstmal den klassischen Plugin-Header:

/*
Plugin Name: Top Category Widget
Plugin URI: http://evileu.de/wordpress
Description: Gibt die Gesamtzahl der veröffentlichten Rezepte und die Anzahl der Beiträge einer frei wählbaren Kategorie an
Author: Evi Leu
Version: 1.0
Author URI: http://evileu.de
*/

Dann passiert Folgendes:

class FeaturedCategoryWidget extends WP_Widget
{
  function FeaturedCategoryWidget()
  {
    $widget_ops = array('classname' => 'FeaturedCategoryWidget', 'description' => 'Zeigt die Anzahl der Rezepte einer frei wählbaren Kategorie an' );
    $this->WP_Widget('FeaturedCategoryWidget', 'Featured Kategorie', $widget_ops);
  }

Eine neue Instanz der Klasse WP_Widget wird angelegt und mit unseren eigenen Benennungen versehen, ich hab die mal fett und rot markiert. Dann kommt noch etliches andere, was später erklärt wird, und am Ende der Datei wird noch per add_action das Widget aktiviert:

add_action( 'widgets_init', create_function('', 'return register_widget("FeaturedCategoryWidget");') );?>

Das reicht aus, damit das Testwidget in den zur Verfügung stehenden Plugins angezeigt wird und aktiviert werden kann. Macht aber noch keinen Sinn, es tut ja noch nichts.

Das Formular für die Benutzereingaben

Dafür brauchts eine Funktion namens form($instance), die sieht so aus, meine Ergänzungen in rot:

 function form($instance)
  {
    $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) );
    $title = $instance['title'];
    
    $instance = wp_parse_args( (array) $instance, array( 'select' => '' ) );
    $select = $instance['select'];
    
    
?>
  <p><label for="<?php echo $this->get_field_id('title'); ?>">Titel: <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo attribute_escape($title); ?>" /></label></p>
  
   <p>
    <label for="<?php echo $this->get_field_id( 'select' ); ?>"><?php _e( 'Select category', 'textdomain' ); ?>:</label>
    <?php wp_dropdown_categories( array( 'show_option_none' =>' ','name' => $this->get_field_name( 'select' ), 'selected' => $select ) ); ?>
  </p>

Damit werden zwei Felder für die Benutzereingaben angelegt. Das erste für den Titel hab ich aus dem Beispiel von makuseof.com übernommen. Das zweite Feld für das Auswahlfeld hab ich mir zusammengegooglet, das stellt eine Dropdown-Liste aller Kategorien zur Verfügung und belegt die Variable $select mit der ID (numerisch) der gewählten Kategorie.

Jetzt kommt noch eine Funktion, die uns die vorher gewählten Werte aus dem Formular zur Verfügung stellt, auch die hab ich einfach übernommen:

function update($new_instance, $old_instance)
  {
    $instance = $old_instance;
    $instance['title'] = $new_instance['title'];
    $instance['select'] = $new_instance['select'];
    return $instance;
  }

Und jetzt kommt endlich die tatsächliche Funktionalität des Widgets. Da werden zuerst noch die beiden Variablen $title und $select gesäubert, aber dann kanns losgehen

function widget($args, $instance)
  {
    extract($args, EXTR_SKIP);
 
    echo $before_widget;
    
    $title = empty($instance['title']) ? ' ' : apply_filters('widget_title', $instance['title']);
    $select    = empty( $instance['select'] ) ? '' : esc_attr( $instance['select'] );
    
   
    // WIDGET CODE KOMMT HIER
    
    
    echo $after_widget;
  }

Der tatsächliche OpCode des Widgets ist sehr straightforward:

echo "<h3>".$title."</h3>";
    echo "Rezepte insgesamt: ".wp_count_posts()->publish."<br>";
    
    global $wpdb;
    $alleposts = $wpdb->get_results( "SELECT * from ".$wpdb->prefix."term_taxonomy where term_id = ".$select."");
    
    foreach($alleposts as $einpost){
        
        echo $einpost->count;
    }
    
    echo " davon ".get_the_category_by_ID($select);

Ich geb erstmal den vom Benutzer eingegebenen Titel als h3 aus, danach die Gesamtzahl der veröffentlichten Posts=Rezepte. Dann kommt eine kleine Datenbankabfrage, ich hol mir aus der wp_term_taxonomy die Anzahl der zur aktuellen Kategorie (ID liegt auf der Variablen $select) vorhandenen Beiträge, die steht da nämlich praktischerweise drin, da muss man nicht lang rummachen. Das wars! Unser Widget hat jetzt ein Eingabefeld für den Titel und eine Dropdownliste zur Auswahl der Kategorie:

widget_mit_dropdown

widget_mit_dropdown

Der Output ist unspektakulär, aber es funktioniert wie geplant:

widget_output

widget_output

Kurzer Blick auf die Datenbank

Wer übrigens wissen möchte, wo die Benutzereingaben gespeichert werden, das ist ein bisschen frustelig. Die werden nämlich serialized abgespeichert, in der wp_options. Sucht da nach einem Eintrag mit dem Namen widget_[name eures widgets]. Im Feld option_value steht dann sowas:

a:2:{i:2;a:2:{s:5:“title“;s:12:“Alle Rezepte“;s:6:“select“;s:2:“29″;}s:12:“_multiwidget“;i:1;}

Der gesamte Code als ZIP

Weil die Schachtelung doch ein wenig kompliziert ist, kommt hier noch der gesamte Code des Widgets als ZIP-Archiv: category-widget

Ihre Meinung interessiert mich!

Wie hat Ihnen dieser Artikel gefallen?

sehr gutgutbefriedigendausreichendmangelhaftungenügend

Ein eigenes WordPress-Theme 2: Widget-fähige zweite Sidebar einbinden

Also, das war jetzt einfacher als ich dachte, deswegen kommts hier heute noch rein. Ich hatte ja in meinem dreispaltigen Template ursprünglich eine statische linke Seitenleiste definiert, und mit einer eigenen kleinen Funktion zur Anzeige der 10 neuesten Rezepte gefüllt, das sah in der index.php so aus:

<div id = "sidebar-left">
    
    <h2>Die neuesten Rezepte</h2>
        <ul>
            <?php $liste = wp_get_recent_posts();
            
            foreach($liste as $item){
                echo '<li><a href="' . get_permalink($item["ID"]) . '">' . $item["post_title"].'</a> </li>';
            }    
            ?>
        </ul> 
 
  </div> <!-- sidebar-left-->

Natürlich gibts aber das Widget „Neueste Beiträge“ schon, und das wollen wir auch nutzen, indem wir die linke Sidebar widgetfähig machen.

Eine neue Datei für die linke Sidebar anlegen

Die heißt sidebar-links.php (oder sidebar-xy.php) und enthält folgenden Code:

<div id="sidebar" class="widget-area">
<?php dynamic_sidebar( 'sidebar-2' ); ?>

</div><!-- #sidebar .widget-area -->

Damit WordPress nun auch eine dynamische Sidebar namens sidebar-2 kennt, kommt folgender Eintrag in die functions.php, dabei passt man den name, die id und die description an:

register_sidebar( array (
        'name' => __( 'Linke Sidebar'),
        'id' => 'sidebar-2',
        'description' => __( 'Widgets in der linken Sidebar anordnen.'),
        'before_widget' => '<aside id="%1$s" class="widget %2$s">',
        'after_widget' => "</aside>",
        'before_title' => '<h3 class="widget-title">',
        'after_title' => '</h3>',
    ) );

In der index.php ersetzt man nun den gesamten Code der statischen Sidebar durch den Aufruf:

<div id = "sidebar-left">
    
    <?php get_sidebar('links'); ?>
 
  </div> <!-- sidebar-left-->

Tückisch ist hier das kleine Wörtchen „links“, das muss genauso heissen wie man es oben im Namen der sidebar-links.php (oder sidebar-xy.php) definiert hat.

Das wars aber auch schon, unsere linke Sidebar taucht jetzt in der Widget-Verwaltung auf und kann bestückt werden:

widgets_linke_sidebar

widgets_linke_sidebar

Ein eigenes Widget erstellen: kurz und knackig

Ich habe hier bei blog.unkonsorten.com die ultimative Kurzanleitung zum Erstellen eines eigenen Widgets gefunden, die möchte ich euch nicht vorenthalten( Beim Code kopieren auf die „“ und “ aufpassen, die muss man korrigieren).

Damit es etwas Interessanteres ausgibt als „Hallo Welt“ habe ich mal die Anzahl der veröffentlichten Rezepte eingebaut, die kriegt man so :

function widget_sidebar() {
// Hier kann man eigenen Code einfuegen
echo "<h3>Rezepte insgesamt: ".wp_count_posts()->publish."</h3>";
}

Das wars auch schon – Have fun with Widgets!

Ihre Meinung interessiert mich!

Wie hat Ihnen dieser Artikel gefallen?

sehr gutgutbefriedigendausreichendmangelhaftungenügend

Sag niemals nie: ein einfaches WordPress-Theme erstellen

Ich hab ja am Anfang dieses Blogs steif und fest behauptet, ich werd hier nie nix zur Erstellung eines eigenen Themes erzählen, weil es a) Zillionen von Themes für jeden Zweck und Geschmack schon gibt und b) Hunderte von hervorragenden Tutorials zum Thema bereits existieren. Aber wenn ich schon die Theme-Erstellung für Drupal und Joomla behandelt habe, darf WordPress eigentlich nicht fehlen, schon aus Gründen der Vergleichbarkeit.

Das tolle Tutorial von Christian Strang

Mit eins der besten Tutorials zur Erstellung eines eigenen WordPress-Themes ist das von Christian Strang auf Lernen hoch 2, und statt bei ihm abzuschreiben kann ich nur jedem ans Herz legen, es durchzuarbeiten und selber zu sehen und zu staunen, wie ausführlich er alles erklärt und wie hervorragend nachvollziehbar die ganze Sache ist. Ich gehe mal davon aus, dass jeder ein eigenes Theme nach Christians Anleitung hinkriegt, und setze nur noch ein paar Kleinigkeiten obendrauf.

Die Vorlage: dreispaltig (wenns geht) mit grossem Headerbild

Das Theme-Layout soll ganz schlicht werden, mal sehen wie weit wir damit kommen:

scribble

scribble

Wenn man sich durch Christians Tutorial durchgearbeitet hat, sollte man jetzt ungefähr dieses Layout erreicht haben:

tutorial_layout

tutorial_layout

Hier wird nur eine (die rechte) Sidebar genutzt, und die ist auch nach Christians Vorlage Widget-fähig, das ist die WordPress-Vorgabe und am einfachsten zu realisieren.

Eine zweite Sidebar

Ich hätte aber gern auch noch eine linke Sidebar, in die sollen meine neuesten Rezepte rein. Das geht nicht weiter kompliziert und auch ohne Widget. Ich füge in der index.php vor die div für den content noch eine div sidebar-left ein und nutze die WordPress-Funktion wp_get_recent_posts(), um mir die neuesten Beiträge ausgeben zu lassen. Das machen wir gleich mit Link zum Beitrag, dafür gibts den get_permalink():

 <div id = "sidebar-left">
    
    <h2>Die neuesten Rezepte<7h2>
        <ul>
            <?php $liste = wp_get_recent_posts();
            
            foreach($liste as $item){
                echo '<li><a href="' . get_permalink($item["ID"]) . '">' . $item["post_title"].'</a> </li>';
            }    
            ?>
        </ul> 
 
  </div> <!-- sidebar-left-->

In der style.css habe ich die divs für sidebar-left, main und sidebar-right nebeneinander positioniert:

#main       {width: 600px; padding: 20px; float: left;}

#sidebar-left   {width: 200px; padding: 10px;float: left;}

#sidebar-right   {width: 200px; padding: 10px;float: left;}

Die Ausgabe ist schon ganz passabel:

die_neuesten_rezepte

die_neuesten_rezepte

Ein Header-Bild wär jetzt noch schön

Dafür gibt es die sehr komfortable Funktionalität

add_theme_support( 'custom-header' );

Diese Zeile kommt in die functions.php

Dann gibt man ihr noch ein paar Argumente mit:

$args = array(
 'width'         => 1260,
 'height'        => 350,
 'default-image' => get_template_directory_uri() . '/images/header.jpg',
 'uploads'       => true,
 );
 add_theme_support( 'custom-header', $args );

Die width und heigth Angaben tauchen dann im Customizer als empfohlene Größe auf, das kann sich jeder selbst einstellen wie es zu seinem Layout paßt. In der header.php wird jetzt folgender Code an oberster Stelle nach der öffnenden div für den wrapper folgender Code eingesetzt:

<img src="<?php header_image(); ?>" 
    height="<?php echo get_custom_header()->height; ?>" width="<?php echo get_custom_header()->width; ?>" alt="" />

Jetzt noch das Header-Bild hochladen und ggf. zuschneiden, dann sollte es auch schon sichtbar sein:

headerbild

headerbild

Ich hab mir gleich noch das Blau des Himmels rausgemessen und in der style.css als background-color für die div header gesetzt, damit das schön zusammenpasst.

Jetzt fehlen mir eigentlich nur noch ein paar Schriftformatierungen, die mach ich in einem Rutsch:

#navlist li
{
font-family:    Times;
font-variant:small-caps;
font-size:      25px;
display: inline;
list-style-type: none;
padding-right: 20px;

}

body {
  margin: 0;
  padding: 0;
  font-family: Helvetica;
  font-size: 14px;    
  font-weight: normal;
  line-height: 24px;
  color: #43473b;
}


h1, h2, h3, h4, h5, h6 {
  font-family: Times;
  font-weight: normal;
  color: #43473b;
}

h1 { font-size: 45px; font-variant:small-caps;}
h2 { font-size: 30px; font-variant:small-caps;}
h3 { font-size: 22px; font-variant:small-caps;}

a { color: #43473b; 
    text-decoration: none;
}
a:hover { color: #fc737b; 
        }

Fertig ist mein Übungsstheme!

finish

finish

Jetzt wärs natürlich schick, wenn die linke sidebar auch Widgetfähig wäre, aber man kanns auch übertreiben… ich geh mal gucken, vielleicht finde ich da noch was dazu.

 

 

Ihre Meinung interessiert mich!

Wie hat Ihnen dieser Artikel gefallen?

sehr gutgutbefriedigendausreichendmangelhaftungenügend

Von Joomla nach WordPress umziehen – der Vollständigkeit halber

Ich habe drüben im Drupal-Blog ausführlich beschrieben, wie man Inhalte aus Drupal in WordPress-Beiträge überführt, nachzulesen hier. Das selbe machen wir jetzt noch mit Joomla, und zwar möchte ich die Beiträge aus einer bestimmten Kategorie nach WordPress exportieren. Meine ausgewählte Kategorie sind natürlich die Rezepte, mit der Kategorie-ID 8 (im Zweifelsfall nachschlagen in der Tabelle #__categories).

Wie kommen wir an Titel und Inhalt der Rezepte?

Aus der Tabelle #__content. Die holen wir uns nach Access rüber und schauen sie mal näher an.

content

content

Die id und den title nehmen wir mit, den alias lassen wir aus. Dann brauchen wir noch den introtext und den fulltext (beide!), weil Joomla den Beitragstext in diese beiden Felder aufteilt, sobald man einen Weiterlesen-Tag eingefügt hat. Das sieht man hier im Screenshot oben bei den ids 4 bis 8, so sieht das dann aus.

Den state müssen wir filtern, -2 bedeutet „marked for deletion“, 1 ist veröffentlicht, wir nehmen nur die 1er. Und die catid filtern wir auch, auf die 8 für Rezepte. (Bei mir ist noch ein Haufen Schrott vom Testen mit drin, ich nehm mal noch die Datensätze 9-47 raus). Übrig bleibt die folgende Tabelle:

content_gefiltert

content_gefiltert

Die specken wir noch ab, die Felder introtext und fulltext werden zu einem Feld namens bodytext zusammengefügt, die catid und der state fliegen raus.

Jetzt fehlen noch die Tags für die Kategorien

Kleine Erinnerung: ich hatte die Rezeptkategorien aus WordPress auf Joomla-Tags ohne Schachtelung abgebildet. Die holen wir uns jetzt wieder zurück, und zwar aus der Tabelle #__tags.

tags

tags

Der erste Eintrag für root fliegt raus, vom Rest übernehmen wir id und title. Parent_id ist überall leer, weil nicht geschachtelt, published = 1 passt auch. Um jetzt die Tags den Rezepten (hier in der Tabelle id_title_bodytext) zuzuordnen, verknüpfen wir über die Tabelle contentitem_tag_map. Beim Importieren nach Access darauf achten, dass content_item_id und tag_id als Integer rüberkommen! Das sieht dann so aus:

tags_beziehungen

tags_beziehungen

Darüber basteln wir uns eine Abfrage, in der zunächst mal jedes Rezept so oft vorkommt, wie es Tags zugeordnet hat:

abfrage_tags

abfrage_tags

Kurzer Blick über die Tabelle: ich habe zu keinem Rezept mehr als 2 Tags zugeordnet, aber das passt schon, ist korrekt.

Zuordnen der Tags zu WordPress-Kategorien

Dafür zieht man sich alle gültigen Tags aus der #–tags ab und importiert sie als Kategorien nach WordPress, wie das geht habe ich in diesem Artikel unter Schritt 1: Anlegen der Kategorien in WordPress im Drupal-Blog ausführlich beschrieben.

Dann habe ich mir die entstandene Tabelle wp_terms nach Access rübergeholt:

wp_terms

wp_terms

Hier kann ich jetzt über den name des Terms auf den title des tags verknüpfen, weil die Schreibweise identisch ist:

join_term_name

join_term_name

Damit bekomme ich die WordPress-Kategorie-IDs zu den Rezepten.

term_id

term_id

Das hatten wir so ähnlich schonmal, jedes Rezept taucht jetzt so oft auf, wie es Kategorien/Tags hat. Jetzt Gruppieren wir noch, und nehmen den ersten und letzten Wert der Term-ID. Diese sind bei den Datensätzen gleich, die nur eine Kategorie zugeordnet haben, das ist schon richtig so.

ersterwert_letzterwert

ersterwert_letzterwert

So, das wars. Diese Tabelle kann man nach WordPress importieren, und zwar genau so wie ich es in diesem Artikel beschrieben habe:

DRUPAL NACH WORDPRESS: BEITRÄGE MIT KATEGORIEN ERZEUGEN

Dabei muss man wahrscheinlich noch eine kleine Abfrage einbauen, was passieren soll wenn erster und letzte Wert der term_id gleich sind, aber prinzipiell funktioniert die Sache so einwandfrei, die Beiträge werden in WordPress angelegt und mit Kategorien versehen.

Ihre Meinung interessiert mich!

Wie hat Ihnen dieser Artikel gefallen?

sehr gutgutbefriedigendausreichendmangelhaftungenügend