Kategorie: PHP

Bugfix contactform7 do_shortcode with special tags

4. Oktober 2015 - PHP, wordpress

Recently I tried to use contact form 7 to display a contact form which contains a special email tag (e.g. [_post_title] ) in the subject field with do_shortcode().

It simply didn’t work. I tried this fix but without success. The special tag wasn’t resolved, either .

Maybe there are some limitations in the way, WordPress has implemented do_shortcode(). Some information about that is here

Nevertheless, I had to solve my problem and this is my hack:

// this goes inside the loop
$my_post_title=get_the_title( get_the_ID());
ob_start();
echo do_shortcode('[contact-form-7 id="2070" title="Product inquiery"]');
$unresolved=ob_get_contents();
ob_end_clean();
echo preg_replace('/_post_title/',$my_post_title,$unresolved);

As you can see, I had to give up the idea of using the special tag [_post_title] inside contact form 7 and I’m using the string „_post_title“ in my form,  instead.

Then php output buffer and preg_replace will do the work for me.

wordpress: problems with meta boxes, nonces and save_post

10. Juni 2014 - PHP, wordpress

If you have created a nice backend user interface in wordpress with meta boxes that add some input fields for additional information to your post and protected them with nonces, you maybe encounter a strange behaviour:
custom menus cannot be saved anymore, likewise pages, likewise custom posts….

The reason is, that your function specified in the action hook doesn’t stick to the rules:
e.g. if you have written (as in my case 🙂 )

add_action( 'save_post', array( $this, 'saveAllCustomFields' ));

function saveAllCustomFields() {
global $post;

if ( !empty($_POST) && check_admin_referer( 'custom_field_creation','custom_fields' ) ) {
if ( !current_user_can( 'edit_post', $post->ID) )  return;
if ( $post->post_type != 'page' && $post->post_type != 'post' )  return;
$this->saveCustomFields($this->customFields1);
}

}

The nonce, created with

wp_nonce_field( 'custom_field_creation','custom_fields' );

for type ‚post‘ will block any other type of post from beeing saved. They simply dont’t know about it.

Changing saveAllCustomFields to

function saveAllCustomFields() {
global $post;
if (!empty($post) && ($post->post_type == 'post')) {
if ( !empty($_POST) && check_admin_referer( 'custom_field_creation','custom_fields' ) ) {
if ( !current_user_can( 'edit_post', $post->ID) )  return;
$this->saveCustomFields($this->customFields1);
}
}
}

will set them free.

Deutsche Zusammenfassung:

Wenn man ein Backend-Userinterface mit Meta-Boxen und  Zusatzfeldern, die durch Nonces abgesichert werden, schreibt, kann es zu – vielleicht zunĂ€chst nicht auffallenden – Nebenwirkungen kommen. Andere Post-Typen wie Seiten, BenutzermenĂŒs etc. können plötzlich nicht mehr gesichert werden.

Der Grund dafĂŒr liegt in der Funktion, die man beim zustĂ€ndigen Action-Hook ’save_post‘ angegeben hat (hier: saveAllCustomFields)

Man muß genau darauf achten, dass der Nonce nur bei dem Post-Type ĂŒberprĂŒft wird, fĂŒr den man ihn auch erzeugt hat.
Ansonsten werden alle anderen Post-Types ausgesperrt.

Lösung eines jqGrid Performance Problems

7. August 2013 - JavaScript, PHP

jqGrid ist ein auf JavaScript/ jQuery basierendes Modul fĂŒr die komfortable und professionelle Darstellung von HTML-Tabellen. Es gibt eine ganz gute Dokumentation, von der man aber nicht immer erwarten darf, dass sie aktuell ist.

DafĂŒr sind die Entwickler von jqGrid in ihrem Blog und auf stackoverflow.com sehr bemĂŒht, Probleme zu lösen und Beispiele zur VerfĂŒgung zu stellen. Das ist auch oft notwenig, denn jqGrid ist komplex und  besitzt gefĂŒhlte 2 Mio. Optionen.

Beim vorliegenden Fall handelte es sich um eine jqGrid Anwendung, die mit steigender Datenmenge nur noch einen weißen Bildschirm ablieferte.

Der „datatype“ in den Optionen von jqGrid war „local“, d.h. das Grid liest seine Daten von der Seite, auf der es aufgerufen wird. Zur Verringerung der Datenmenge gab es zwei Datumsfelder (von-bis), mit denen die Datenbankabfragen modifiziert werden konnten.

Lösung:

1. Umstellung auf ajax und XML, d.h. die Datenerzeugung und Vorverarbeitung wird auf einer zusĂ€tzlichen Seite (‚get_data_from_server.php‘) gemacht

Die neuen Optionen waren dann:

url:’get_data_from_server.php‘,
datatype: „xml“,
mtype: „POST“, …..

Dadurch spart man sich z.B. die im Falle „local“ notwendigen jQuery/ jqGrid Aufrufe, um die lokalen Daten in die entsprechenden Tabellenelemente zu kopieren:

jQuery(‚#………..‘).jqGrid(‚addRowData‘,….

Bei der Umstellung auf XML muss man etwas aufpassen. XML1.0  erlaubt eine Reihe von Zeichen nicht. Diejenigen, ĂŒber die man in unseren Breiten am hĂ€ufigsten stolpern wird, sind < und &.

Hier hilft es, < und & zu maskieren ( in PHP mit  htmlspecialchars() ) .
Alternativ können solche Daten auch mit CDATA  getagged werden. Die lÀsst der XML Parser auch passieren.

Unangenehm sind aber auch Steuerzeichen von 0x00 bis 0x1f. Hier akzeptiert XML nur 0x09 (HT), 0x0a (LF) und 0x0d (CR).

Steuerzeichen können z.B ĂŒber eine Textbox ins System reinrutschen, in die ein Benutzer einenMS- Word-Text hinein kopiert.

Hier hilft z.B. bei PHP

preg_replace(‚/[\x00-\x08\x0b-\x0c\x0e-\x1f]/‘, ‚ ‚, $string);

oder wieder  CDATA  verwenden.

jqGrid zeigt bei nicht erlaubten Zeichen zwar die Anzahl der DatensÀtze richtig an, stellt sie aber nicht dar.

Also: schaut euch die js Konsolen eures Webrowsers gut an (bei Firefox sollte man den Firebug benutzen)

2. paging: Limitierung auf x DatensÀtze

StandardmĂ€ĂŸig ĂŒbertrĂ€gt jqGrid vier Felder per POST an get_data_from_server.php

– die Sortierreihenfolge ( ab- oder aufsteigend)
– das Feld, nach dem sortiert werden soll (order by)
– die Anzahl der gewĂŒnschten DatensĂ€tze (limit)
– den Offset (mit welchem Datensatz wird begonnen)

Damit kann man sehr einfach die Datenmenge beschrÀnken und dem Benutzer trotzdem die Möglichkeit geben, sich alle DatensÀtze ansehen zu können

In den Optionen kann man z.B. dann folgendes eintragen

rowNum: 10,
rowList:[10,20,100],…

rowNum ist der Standard, rowList erzeugt ein kleines Popup, mit dem der Benutzer die Anzahl der anzuzeigenden DatensÀtze umstellen kann

3. Limitierung auf bestimmte Datumsbereiche

Auch der Datumsbereich lĂ€ĂŸt sich noch in die neue Lösung einbauen. Dazu benutzt man die postData Option von jqGrid:

postData: {
from: function() { return $(„#von“).val(); },
till: function() { return $(„#bis“).val(); },
},…

#von bzw. # bis sind die IDs zweier Eingabefelder, die hier mit jQuery ausgelesen werden.

Damit werden zwei weitere Felder per POST an get_data_from_server.php gesendet, die man z.B. so auswerten kann:

if (isset ( $_POST [„from“] ) && $_POST [„from“] != „“) {
$from = $_POST [„from“] ;
$till = isset ( $_POST [„till“] ) && $_POST [„till“] != „“ ? $_POST [„till“] : $from;
} else {
$from = date ( „Y-m“ );
$till = date ( „Y-m“ );
}

Ostern: tiefergelegt mit PHPs easter_date()

7. Dezember 2012 - PHP

Der neue, mit PHP selbstprogrammierte Jahreskalender ist fertig! Alles sieht schön aus! Aber Ostern und die restliche Bande der beweglichen Feiertage sind leider um einen Tag verschoben…

English Summary: What an Easter egg! When you have finished your self-programmed calender with PHP, you may observe that Easter and all others of  the movable holidays have shifted one day.

Ein Programmierfehler? Wahrscheinlich, aber nicht deiner!

Die meisten beweglichen Feiertage werden mit easter_date() berechnet. Hier liegt das Problem , das HIER  im Abschnitt  „Notes“ beschrieben wird.

Eine Lösung wird ebenfalls vorgeschlagen.

Wenn ihr das Osterdatum aber als Timestamp wie bei easter_date() benötigt, sollte die Lösung etwa so aussehen:

function get_easter_datetime($year) {
$base = new DateTime("$year-03-21");
$days = easter_days($year);
$base->add(new DateInterval("P{$days}D"));
return $base->getTimestamp();
}

oder (Simplify, simplify!)


function get_easter_datetime($year) {
$days = easter_days($year);
return mktime(0, 0, 0, 3, 21+$days,$year);

}