Archiv der Kategorie: Meta

Quo vadis custom fields?

Im Jahr 2013 haben wir hier kurz darüber berichtet, dass man Custom Fields (Post Meta) besser nutzbar machen und umfangreiche Funktionalität dazu in den Core geben möchte. Es gab Bestrebungen, das Handling, Aussehen und die Funktionalität in „Richtung“ Advanced Custom Fields (ACF) zu treiben.

Mit etwas mehr als einer Million aktiven Installationen weltweit gehört ACF zu den beliebtesten Plugins und dürfte das führende Post Meta Plugin sein.
Warum?
Weil es die Metadaten aufwertet und sich unsagbar viele Dinge damit umsetzen lässt.

Das blieb dem Core-Entwicklerteam natürlich nicht verborgen und deswegen gab es auch schon im Jahr 2013 diesen Feature-as-a-Plugin-Ansatz, den wir in einem Blogpost kurz thematisiert haben.

Leider ist daraus nichts geworden – das Projekt ist eingeschlafen.

Helen Hou-Sandí, ein relativ neues Mitglied im Core-Entwicklerteam, hat sich dieser Sache nun angenommen und haucht der Idee neues Leben ein, Metadaten stärker in den Vordergrund zur rücken.

Durch den Erfolg der WP (JSON) API wird WordPress immer mehr zum Framework oder zur Grundlage für WebApps. Was auf der Hand liegt, weil man sich dadurch die Datenbankabstraktion, Benutzerverwaltung, Medienverwaltung usw usf spart.

Die JSON API ist eeextremst Gold wert – aber sie deckt nicht alles ab? Was nicht? GENAU! Custom Fields sind derzeit nicht zufriedenstellend implementiert.

 

Daten leben  nicht nur vom vordergründigen Inhalt alleine, sondern auch von den Metadaten und genau da hakt es ein wenig bei WordPress.

Zwei Eingabefelder alleine reichen im Jahr 2015 nicht mehr, um Metainformationen zu speichern.

Deswegen ist ACF ja so genial. Responsive Images, Slider, rudimentäre Webshopfunktionalität, globale Texte, Suchkriterien, Sortierkriterien, Front-End-Editing, Tag-, Category-, Termimages, zusätzliche Termoptions, rudimentäre Übersetzungen, flexible Inhalte usw usf.
Alles, was man sich an Funktionalität und verbundenen Daten wünscht und aufgrund der Tabellenstruktur der Post-Meta-Tabelle noch einigermaßen performant mit Custom Fields lösbar ist, lässt sich mit ACF leicht realisieren.

Was sich leicht realisieren lässt, wird auch von Entwicklern dankend angenommen und verwendet – dann soll so eine Funktionalität aber in den Core, um die Weiterentwicklung zu sichern. (Man sieht es beim Ausscheiden von Sergej Müller aus dem WordPress Universum, dass wir zu Abhängig von einzelnen Personen sind und diese dann auch noch zu wenig finanzieren.)

Automattic macht das eh ziemlich gut, und angelt sich die bekannteren Entwickler. (Ja! Es geht um die Entwickler! Die Plugins stehen alle unter der GPL und können von jedem geforkt werden.)
Durch den Schritt, WooCommerce zu kaufen, wandert ein weiteres, sehr stark verwendetes Plugin in „Richtung“ Core. WooCommerce wird voraussichtlich nicht direkt in den Core aufgenommen werden sondern wahrscheinlich das JetPack Plugin bereichern. Dennoch ist es für uns WordPress-Entwickler wichtig, dass WooCommerce unter der Obhut des Core-Entwicklerteams steht, die Weiterentwicklung gesichert ist und nicht die Gefahr besteht, eingestellt zu werden.

Uns als Entwickler kommen solche Schritte sehr entgegen, weil dadurch eine Planungssicherheit entsteht.

Daher ist es auch ziemlich unverständlich, warum man Elliot Condon, den Mann hinter ACF, nicht anstellt oder ACF kauft. Elliot wird vielleicht persönliche Gründe haben, davon Abstand zu nehmen.

Schade ist es aber, dass so ein Deal anscheinend nicht zustande kommt.

Dennoch geht hier etwas weiter. Das Core-Team ist dran, fängt aber bei Null an. ACF oder Elliot mit im Team zu haben wäre ein Raketenstart für die Verbesserung des Meta Handlings. Das spielt’s leider nicht, daher werden derzeit kleinere Brötchen gebacken.

Mehr Infos dazu gibt es hier:

https://make.wordpress.org/core/2015/05/27/metadata-api-project-reborn-the-new-fields-api-project/
https://make.wordpress.org/core/2015/05/27/metadata-api-project-reborn-the-new-fields-api-project/

 

https://make.wordpress.org/core/components/options-meta/
https://make.wordpress.org/core/components/options-meta/

 

Wir werden sehen, ob sich zwei Jahre später mehr tut und Erfolge erzielt werden, wenn es um Meta Handling im Core geht. Das Vorhaben ist ja schon einmal gescheitert – ich wünsche Helen daher mehr Erfolg bei diesem Versuch. Im Optimalfall können wir dann kompliziertere Daten- und Beziehungsstrukturen im Backend in Core-Mentalität abbilden und per JSON auslesen. Out of the box.

 

 

 

 

Sicherheitsrisiko durch fehlende Info im WordPress Codex (add_query_arg)

Seit Kurzem ist eine Sicherheitslücke bekannt, die dann auftritt, wenn man die Funktionen

add_query_arg()

und

remove_query_arg()

nicht richtig verwendet.

Problem

In der bisherigen Dokumentation wurde suggeriert, dass diese Funktionen die URLs escapen – also unsichere Zeichen aus der URL entfernen.

Dem war aber nicht so.

Daher beide Funktionen absichern, wenn diese mit Usereingaben verwendet, oder wenn damit potentiell unsichere URLs weiterverarbeitet werden.

Lösung:

Unbedingt folgende Funktonen zum Absichern verwenden:

esc_url() oder

esc_url_raw()

Wobei esc_url_raw() nur dort verwendet werden sollte, wo das „&“ Zeichen nicht ersetzt werden muss (speichern in die Datenbank, Redirect oder HTTP-Abfrage mit zB wp_remote_get()).

 

Weitere Infos:

https://wordpress.org/news/2015/04/wordpress-4-1-2/
https://wordpress.org/news/2015/04/wordpress-4-1-2/

https://make.wordpress.org/plugins/2015/04/20/fixing-add_query_arg-and-remove_query_arg-usage/
https://make.wordpress.org/plugins/2015/04/20/fixing-add_query_arg-and-remove_query_arg-usage/

https://www.golem.de/news/cross-site-scripting-zahlreiche-wordpress-plugins-verwenden-funktion-fehlerhaft-1504-113636.html

http://wptavern.com/xss-vulnerability-affects-more-than-a-dozen-popular-wordpress-plugins
http://wptavern.com/xss-vulnerability-affects-more-than-a-dozen-popular-wordpress-plugins

http://wptavern.com/xss-vulnerability-what-to-do-if-you-buy-or-sell-items-on-themeforest-and-codecanyon
http://wptavern.com/xss-vulnerability-what-to-do-if-you-buy-or-sell-items-on-themeforest-and-codecanyon

Vorsicht beim Setzen von Terms mit wp set object terms()

Um gleich mit der Tür in’s Haus zu fallen:

Warum?

Weil nicht überprüft wird, ob die Taxonomy des Terms mit dem Objekt verknüpft ist.
Es wird zB nicht überprüft, ob eine Kategorie der eingebauten Taxonomy ‚category‘ mit dem Beitragposttype ‚Post‘ verbunden ist.
Ob es daher überhaupt erlaubt ist, zB einem Beitrag eine Kategorie zuzuweisen.

Trotzdem wird das Term zum Objekt gespeichert!!

Ok, das Beispiel ist recht sinnlos weil wir ja wissen, dass Beiträge ganz einfach in Kategorien eingereiht werden können. Das Beispiel dient nur der Veranschaulichung.

Viel interessanter wird es beim Zuweisen von Custom Taxonomy Terms, also den selbst erstellten „Tags“ und „Kategorien“.

wp_set_object_terms() überprüft nämlich nicht, ob der Beitrag den ich gerade „tagge“ auch wirklich mit der Custom Taxonomy verbunden ist.
Genau das wird problematisch, wenn man  Geschäftslogik mit eigenen Kategorien oder Tags löst.
Denn ich kann mit wp_set_object_terms() zB eine Seite ohne Probleme (und ohne Fehlermeldung) out-of-the-box einen Tag oder eine Kategorie zuweisen.

Lösung:

Vor dem Speichern mit wp set object terms() einfach überprüfen, ob der „Post“ (also das Objekt) eh mit der entsprechenden Custom Taxonomy verknüpft ist.

Wie finde ich das heraus?

Lösung mit der globalen wp_taxonomies Variable:

  global $wp_taxonomies;
  $alle_taxonomie_objekte   = $wp_taxonomies;
  $zugewiesenen_taxonomien  = $alle_taxonomie_objekte['category']->object_type;
  /*
  Array
  (
      [0] => post
      [1] => my_custom_post_type_wpent
  )
  */

Es gibt eine globale Variable, die alle Taxonomien mit den diversen Informationen bereithält. Wir sehen in diesem Beispiel, dass die normale WordPress Kategorie mit den Beiträgen (‚posts‘) und einem Custom Post Type (‚my_custom_post_type_wpent‘) verknüpft ist.
Aber eben nicht mit dem ‚Page‘ Post Type aka „Seiten“.

Lösung mit get_object_taxonomies()

Den oben beschriebenen Weg können wir abkürzen, wenn wir die Funktion get_object_taxonomies() verwenden. Damit wird genau das oben gezeigte Array geholt. Im WP Codex gibt es dafür ein schönes Beispiel:

   $taxonomy_names = get_object_taxonomies( 'post' );
   print_r( $taxonomy_names);

Gibt uns folgendes zurück:

Array
(
    [0] => category
    [1] => post_tag
    [2] => post_format
)

 

Alternativ mit wp_get_object_terms()

Man könnte auch direkt mit wp_get_object_terms() alle Terms abfragen, die zu einem Post gehören.

 wp_get_object_terms( 123, 'my_custom_taxonomy_wpent' );

Ist die Taxonomy (hier „my_custom_taxonomy_wpent“) nicht mit dem Post 123 verknüpft, wird ein wp_error zurückgegeben.
Als Fehlermeldung bekommt man den Hinweis  „invalid_taxonomy“ zurück und kann darauf reagieren.

 Wie kommt es dazu?

Die Funktion wp_set_object_terms() ist in der Datei „taxonomy.php“ enthalten.

Es wird überprüft ob der übergebene Term existiert:
https://github.com/WordPress/WordPress/blob/4.1-branch/wp-includes/taxonomy.php#L2991

if ( !$term_info = term_exists($term, $taxonomy) ) {

 

Schauen wir uns die Funktion weiter näher an so sehen wir, dass zweimal die Funktion wp_get_object_terms() aufgerufen wird.
Diese Funktion liefert in unserem Fall ja einen Fehler zurück. Doch leider zu spät, da das Term schon gespeichert wurde. Außerdem wird gar nicht auf wp_error überprüft.

https://github.com/WordPress/WordPress/blob/4.1-branch/wp-includes/taxonomy.php#L2979

https://github.com/WordPress/WordPress/blob/4.1-branch/wp-includes/taxonomy.php#L3051

In beiden Fällen bekommt jetzt eine Variable ein wp_error Objekt zugewiesen. Keine der Variablen wird auf diesen Umstand hin überprüft.

 

Die Speicherung eines Terms, der eigentlich gar nicht mit einem Objekt (Post, Page, CPT) über die Taxonomy verknüpft ist, geht problemlos über die Bühne.

 

Informatives:

Check ob Term besteht
http://codex.wordpress.org/Function_Reference/term_exists

http://codex.wordpress.org/Function_Reference/term_exists

 

Check ob es die Taxonomy gibt
https://codex.wordpress.org/Function_Reference/taxonomy_exists
https://codex.wordpress.org/Function_Reference/taxonomy_exists

 

Holt alle Taxonomien eines Posts (Objektes)
http://codex.wordpress.org/Function_Reference/get_object_taxonomies
http://codex.wordpress.org/Function_Reference/get_object_taxonomies

 

wp_set_object_terms() auf Github
https://github.com/WordPress/WordPress/blob/4.1-branch/wp-includes/taxonomy.php#L2950
https://github.com/WordPress/WordPress/blob/4.1-branch/wp-includes/taxonomy.php#L2950

 

wp_get_object_terms() im Codex
http://codex.wordpress.org/Function_Reference/wp_get_object_terms
http://codex.wordpress.org/Function_Reference/wp_get_object_terms

 

wp_set_object_terms() im Codex
https://codex.wordpress.org/Function_Reference/wp_set_object_terms
https://codex.wordpress.org/Function_Reference/wp_set_object_terms

 

Check ob der Post einen gewissen Term hat
http://codex.wordpress.org/Function_Reference/has_term
http://codex.wordpress.org/Function_Reference/has_term

 

 

Wien hat sein Wordcamp – am 11. April ist es soweit

Wien hat sein Wordcamp!

Hamburg (seit 2008!), Paris,  Mailand, Birmingham, Barcelona, Jena, Cardiff, Bukarest, Utrecht, Griechenland, Kilkenny, Kopenhagen,  Berlin, Manchester, Sofia, Belgien, Stockholm, Lodz, Köln,  Oslo,  Edinburgh, Sevilla, Lissabon, Bologna, Bratislava, Lancaster, Leiden , Malaga, Sofia, London, Prag, Zürich, Timisoara, Mallorca, Warschau, durften u.a. schon Wordcamps auf europäischem Boden begrüßen.

http://central.wordcamp.org/schedule/past-wordcamps/
http://central.wordcamp.org/schedule/past-wordcamps/

In Österreich laufen die Uhren ein bisschen langsamer, aber nun ist es endlich soweit:

Am

11. April 2015

von 09.00 bis 18.00 Uhr

steigt das erste Wordcamp Wien/Österreich!

Veranstaltungsort ist die Uni Wien,Fakultät für Informatik, Währingerstrasse 29, 1090 Wien

http://vienna.wordcamp.org/2015/
http://vienna.wordcamp.org/2015/

Organisiert wird das Wordcamp anscheinend von den Machern des Wiener WP Meetups.

Das Wiener Meetup richtet sich eher international aus, daher ist die Vortragssprache meist Englisch. Was für das Publikum Sinn macht.
Was die Vernetzung aber nicht leichter macht.
Leider gibt es in Österreich sehr wenige Veranstaltungen, die sich dezidiert mit WP beschäftigen. Österreich ist da leider anders als zb Deutschland, Tschechien oder die Slowakei, wo die Community viel stärker vernetzt ist.

Daher ist es eine Wohltat endlich ein großes, offizielles Vernetzungstreffen in Wien erleben zu dürfen.

Wir sind natürlich Sponsor dieses Events und werden vor Ort sein.

Wer dabei sein will sollte hurtig handeln, denn von den 350 Tickets sind nur mehr noch gut 90 (Stand 18.02.2015) erhältlich.

http://vienna.wordcamp.org/2015/tickets/
http://vienna.wordcamp.org/2015/tickets/

 

https://twitter.com/wpvienna
https://twitter.com/wpvienna

 

http://wpvienna.com/
http://wpvienna.com/

 

.concat() 2015

Am 7. März 2015 gibt es in Österreich eine recht interessante Web Development Veranstaltung mit dem Namen .concat().

Zu finden unter:

https://conc.at/

Interessant vor allem wegen der anwesenden Speaker wie

Douglas Crockford (dem „Erfinder“ von JSON),
Lena Reinhard von Hood.ie und natürlich
Vitaly Friedman (den man eher nicht näher beschreiben muss ).

Warum wir dafür Werbung machen?
Einerseits weil wir solche Vernetzungstreffen in einem kleinen Land wie Österreich verdammt gut finden.

Andererseits weil wir im Moment sehr beschäftigt sind, was sich in der Frequenz der neuen Blogartikel niederschlägt, aber dort vor Ort sein werden.

Wer immer also Lust und Laune hat uns kennenzulernen -> ab auf die .concat() 2015. Wir sind dort zwar keine Speaker aber wir freuen uns auf interessante Gespräche rund um Webentwcklung, WordPress Entwicklung und sonstigem PC/Internet Kram.

 

Wir haben übrigens die Order ID 23. Wenn das kein Zeichen ist!

 

 

 

Quick Tip: Slug nicht für Werte verwenden, mit denen man arbeiten will

Ich erlebe es in letzter Zeit häufiger, dass Entwickler wichtige Werte in Slugs von Kategorien oder Custom Taxonomies speichern.

Werte, mit denen später weitergearbeitet werden soll.
Die für Abfragen, Abhängigkeiten oder Verbindungen gebraucht werden.

Also zb den Wert von Steuersätzen (zb 20%, 19%, 10%, 0%) als Slug.
Mit diesen Steuersätzen sollen natürlich Berechnungen angestellt werden und daher wird darauf vertraut, dass der Slug den Steuersatz (noch dazu als STRING!) enthält.

Das ist eine ganz schlechte Idee, da Plugins oder andere Funktionalität in die Term/Tag Erstellung eingreifen und damit die Werte verfälschen kann.

Auch besteht die Möglichkeit, dass WordPress den Slug selbstständig ändert, wenn es ihn schon gibt.

Die bessere Variante ist, solche Werte in eigene Tabellen auszulagern.

 

 

Kategorie Bilder mit ACF – Speicherort in der Datenbank

Mit ACF (Advanced Custom Fields) lassen sich viele Dinge einfach im Code umsetzen, anstatt dafür Plugins verwenden zu müssen.

Kategorie Bilder können mit ACF so zb sehr einfach gelöst werden.

Da es keine termmeta Tabelle in der Datenbank gibt könnte man sich jetzt fragen:
Wo speichert ACF diese Information hin?

Die Antwort: In die Optionstabelle!

Diese Information ist dann wichtig, wenn man nicht die von ACF vorgegebenen Möglichkeiten verwenden will, um diese Daten auszulesen.

Hat man zb ein ACF Feld mit dem Namen „category_image“ erstellt und speichert man zur Kategorie mit der ID 14 das Bild „meinkategoriebild.jpg“, so gibt es folgenden Eintrag:

option_name: category_14_category_image
option_value: meinkategoriebild.jpg (oder meinkategoriebild oder die ID des Attachments aus der Mediathek, je nach Setting)

Mit folgendem Code in der Kategorietemplatedatei komme ich nun an diesen Eintrag ran:

$current_cat = get_query_var( 'cat' );
$bg_image = get_option( 'category_' . $current_cat . '_category_image' );

Unterschied zwischen wpdb prefix und base_prefix

Wir dürfen ab und zu Feuerwehr spielen und WordPress Code anderer Entwickler reparieren, der nicht (mehr) so will wie es ursprünglich angedacht war.

Oft sind es minimale Dinge, Codestellen die man sehr leicht übersieht, die Probleme verursachen und so eine schöne Funktionalität unbrauchbar macht.

Bei einem unserer letzten Aufträge gab es Fehler bei der Speicherung in Tabellen, die von einem Plugin erstellt wurden.

Das Problem war, dass $wpdb->prefix bzw $wpdb->base_prefix nicht richtig eingesetzt wurde.

 $wpdb->base_prefix

$wpdb->base_prefix liefert das in der wp-config.php gespeicherte Präfix zurück. Dort wird es  in der Variable $table_prefix gespeichert:

<?php

$table_prefix  = 'wppre_';

?>

Rufe ich nun $wpdb->base_prefix auf, so bekomme ich den Wert ‚wppre_‚ zurück.
Das macht so lange keine Probleme, so lange ich mich nicht in einer Multisite Umgebung befinde. Denn dort bekommen die Tabellen nicht nur den $table_prefix sondern auch die Blog ID vor den Tabellennamen gestellt.

In einer Multisite Umgebung würde die Tabelle ‚Posts‘ zb so heißen:

wppre_11_posts

Damit ich den gesamten Präfix, inklusive der Blog ID, bekomme muss ich $wpdb->prefix verwenden.

$wpdb->prefix

$wpdb->prefix liefert das vollständige Präfix einer WordPress Tabelle in Multisite Umgebungen. Ich bekomme damit nicht nur den in der wp-config.php gespeicherten Präfix sondern den kompletten String inklusive Blog ID. In unserem Beispiel eben „wppre_11_„.

Will ich also bei einer Multisite selbst auf eine Tabelle zugreifen, so muss ich prefix und nicht base_prefix verwenden!

 

Überschreiben/ersetzen bereits vorhandener (gettext) Übersetzung

Eine schnelle Möglichkeit um übersetzte, aber nicht passende, Übertragungen ins Deutsche zu verändern bietet uns der Filter ‚gettext‘:

add_filter( 'gettext', 'uebersetzung_ueberschreiben_wpent', 10, 3 );

function uebersetzung_ueberschreiben_wpent( $translations, $text, $domain ){

    if ( $domain == 'plugin_text_domain' && $text == 'cucumber' ) {
		$translations = 'Gurkerl';
	}

	return $translations;	

}

Zur Erklärung der einzelnen Variablen hier ein Auszug aus dem WordPress Code:

return apply_filters( 'gettext', $translations, $text, $domain );

/*@param string $translations Übersetzter Text
 *@param string $text         Text der übersetzt werden soll
 *@param string $domain       Text domain. Eindeutige Erkennung / Gruppierung
 */

Das Codeschnippsel funktioniert natürlich auch mit unübersetzten Begriffen, wenn diese in die entsprechenden WordPress Übersetzungsfunktionen verpackt wurden. So kann man schnell und einfach einzelne Worte in die gewünschte Sprache übersetzen. Aber

Achtung Falle:

Dieser Filter wird bei allen Übersetzungen ausgeführt! Das kann extrem performanceschädigend sein, wenn man die komplette Funktion bei jeder Übersetzung durchlaufen lässt. Daher ist zumindest die Abfrage des Kontexts, der Plugin Text Domain also der Bezeichnung der „Herkunft“ des zu übersetzenden Wortes, anzuraten. Man könnte auch einen Schritt weitergehen, wenn man die Übersetzung zb nur für bestimmte Seiten benötigt. Dann kann man  die diversen WordPress Funktionen oder im Notfall auch über die $GLOBALS Variable verwenden, um die Ausführung des Filters einzugrenzen.

http://codex.wordpress.org/Plugin_API/Filter_Reference/gettext

http://codex.wordpress.org/Plugin_API/Filter_Reference/gettext

https://core.trac.wordpress.org/browser/tags/3.8.1/src/wp-includes/l10n.php#L85

https://core.trac.wordpress.org/browser/tags/3.8.1/src/wp-includes/l10n.php#L85

Quick Tip: wp-config.php außerhalb des Webverzeichnisses

Nach der Installation von WordPress liegt die wp-config.php direkt im Webverzeichnis und kann aufgerufen werden. Wenn alles richtig konfiguriert ist, stellt das kein Problem dar und es kommt nur eine weiße Seite.

Fehler können jedoch immer passieren, und dann liegen plötzlich die Zugangsdaten zur Datenbank frei her. Aaron Adams führt das auf WordPress Answers umfassend aus, das hier zu wiederholen würde den Rahmen für einen Quick Tip sprengen.
http://wordpress.stackexchange.com/questions/58391/is-moving-wp-config-outside-the-web-root-really-beneficial/74972#74972

Dabei ist es so einfach: WordPress sucht automatisch ein Verzeichnis über dem eigenen wenn es die wp-config.php nicht dort findet wo es sie erwartet. Damit ist ist man in vielen Fällen schon aus dem Webverzeichnis raus und deutlich sicherer.

Ist man aufgrund der Verzeichnis-Struktur gezwungen, die wp-config.php woanders abzulegen, so reicht eine kleine Dummy-Datei, die die richtige lädt (der Pfad in der letzten Zeile muss natürlich angepasst werden):

<?php

/** Absolute path to the WordPress directory. */
if ( ! defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/');

/** Location of your WordPress configuration. */
require_once(ABSPATH . '../phpdocs/wp-config.php');

?>

Empfehlenswert ist diese Dummy-Datei immer, denn manche Plugins (wie zum Beispiel Adminer!!) funktionieren nicht richtig, wenn die wp-config.php nicht da liegt wo sie normalerweise liegt. Das lässt sich mit der Dummy-Datei verhindern.