Category: HowTo / Anleitung

Wordpress: Virtuelle Seiten erstellen – Von .htaccess zu Hooks

Worpress ist praktisch, wenn man manuell Seiten (Pages) erstellt und diese im Admin Bereich editieren möchte. Allerdings gibt es keine (mitgelieferte) Möglichkeit “virtuelle Seiten” unterzubringen.

Virtuelle Seiten?!
Nun rede ich hier von virtuellen Seiten, aber was verstehe ich darunter?
Im Prinzip ist die Idee ganz einfach: Der Webseitenbesucher soll keinen Unterschied zwischen einer virtuellen und einer “realen” Seite sehen – allerdings ist die virtuelle Seite nicht in der Wordpress Datenbank abgelegt.

Die Probleme
Aus dieser Aufgabenstellung ergeben sich folgende Probleme:

  1. Umleitung der Anfrage auf ein eigenes php-Skript
  2. Einbinden des Wordpress Layouts
  3. Erweitern der Navigation um die Virtuellen Seiten

Umleitung der Anfrage auf ein eigenes php-Skript
Auszug aus der .htaccess

View Code PLAIN
1
2
3
4
RewriteEngine On
RewriteBase /pfad/zu/meinem/blog/
RewriteRule ^uebung/([\w,=;\-]+)\.html$ ce_exercise.php?id=$1 [L]
RewriteRule ^uebung/?$ ce_exercise.php [L]

In diesem Beispiel werden alle Anfragen auf /uebung, /uebung/, /uebung/xyz-abc-etc.html auf ce_exercise.php umgeleitet. ce_exercise.php bindet dann Wordpress ein und lädt die angeforderte Seite aus der (eigenen) Datenbank.

Einbinden des Wordpress Layouts
Mit

1
2
3
4
5
6
define ( 'WP_USE_THEMES', false );
 
/** hier fehlt noch was! Siehe unten */
 
/** Loads the WordPress Environment and Template */
require ('./wp-blog-header.php');

wird Wordpress eingebunden (angenommen, dass wp-blog-header.php im selben Verzeichnis liegt).
define ( ‘WP_USE_THEMES’, false ); verhindert, dass Wordpress selbstständig wird und Theme Dateien lädt – Das wollen wir ja selbst machen!

Dies alleine reicht allerdings nicht aus, da Wordpress die url analysiert und trotzdem versucht den Inhalt der Seite zu laden. Da die angeforderte Seite virtuell ist wird Wordpress immer davon ausgehen, dass ein 404 (Seite nicht gefunden) vorliegt.

Dies lässt sich wie folgt lösen:

1
2
3
/* confuse wordpress: make it think the url is something else */
preg_match ( '#(.*)/uebung/#', $_SERVER ['REQUEST_URI'], $treffer );
$_SERVER ['REQUEST_URI'] = $treffer [1] . "/uebung/";

Ich gebe zu, diese Lösung ist weder schön noch Zukunftssicher – aber sie funktioniert.

Wichtige Hinweise zu dieser Lösung:

  • Ich verwende “schöne” permalinks mit mod_rewrite
  • Es muss eine Seite angelegt werden, die auf die umgeschriebene url passt. Hier: /uebung/
  • Der Code muss vor require (’./wp-blog-header.php’); stehen!

Der Anfang des php-Skriptes sieht dann so aus:

1
2
3
4
5
6
7
8
9
10
11
error_reporting ( E_ALL );
define ( 'WP_USE_THEMES', false );
 
/* confuse wordpress: make it think the url is something else */
preg_match ( '#(.*)/uebung/#', $_SERVER ['REQUEST_URI'], $treffer );
$_SERVER ['REQUEST_URI'] = $treffer [1] . "/uebung/";
 
$requested_page = isset ( $_GET ['id'] ) ? $_GET ['id'] : "main";
 
/** Loads the WordPress Environment and Template */
require ('./wp-blog-header.php');

Nun können die Wordpress-Funktionen get_header (); get_sidebar (); und get_footer (); aufgerufen werden.

Damit ist das Problem des Layouts gelöst – bleibt noch:

Erweitern der Navigation um die Virtuellen Seiten
Wordpress stellt viele sogenannter “hooks” zur Verfügung, um die Ausgabe von Wordpress Funktionen zu beeinflussen. Diese Hooks werden auf den Resultaten der Wordpress Funktionen ausgeführt, nachdem die Wordpress Funktion fertig ist.

Vereinfacht kann man sich das so vorstellen:

1
2
$reslut = wp_some_funtion();
$result = my_hook( $result );

Die Kunst besteht darin die richtige Wordpress Funktion auszuwählen. Ich hab hier auch einen unschönen aber schnellen und effektiven Weg gewhält: Ich modifiziere die Navigation, nachdem diese als HTML generiert wurde. Konkret: Ich verwende einen Hook auf wp_list_pages.

In meinem Fall möchte ich nur die Navigation der Sidebar beeinflussen und nicht die des Headers. Deshalb wird der Hook erst nach Ausgabe des Headers aufgerufen.

Jetzt bleibt nur noch das Hinzufügen der zusätzlichen Navigationselemente im Hook. Ich suche dazu nach dem Navigationseintrag, der “uebung” enthält und füge danach die virtuellen Seiten ein.

Der gesamte (auf das Wesentliche reduzierte) Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 
error_reporting ( E_ALL );
/* verhindern, dass WP selbständig Themes lädt */
define ( 'WP_USE_THEMES', false );
 
/* confuse wordpress: make it think the url is something else */
preg_match ( '#(.*)/uebung/#', $_SERVER ['REQUEST_URI'], $treffer );
$_SERVER ['REQUEST_URI'] = $treffer [1] . "/uebung/";
 
$requested_page = isset ( $_GET ['id'] ) ? $_GET ['id'] : "main";
 
/** Loads the WordPress Environment and Template */
require ('./wp-blog-header.php');
 
 
get_header ();
 
// hier den eigentlichen Seiteninhalt ausgeben
 
// hier $added_pages_str mit den virtuellen Seiten füllen
 
add_filter ( 'wp_list_pages', 'ce_mod_pages_list', 1, 2 );
 
get_sidebar ();
 
get_footer ();
 
function ce_mod_pages_list($pages_str, $opt) {
	global $added_pages_str, $requested_page;
	$parts = preg_split ( "#</li>#", $pages_str );
	foreach ( $parts as $key => $value ) {
		if (strpos ( $value, "uebung" ) !== false) {
			if ($requested_page != "main") {
				$parts [$key] = str_replace ( "current_page_item", "", $parts [$key] );
			}
			$parts [$key] .= $added_pages_str;
			break;
		}
	}
	return implode ( "</li>", $parts );
}

Schlussbemerkungen

  • ce_ steht für CompuLearn Englisch
  • Das Deutsch / Englisch Chaos in Code und Kommentaren ist ärgerlich aber nicht zu vermeiden.
  • Oje, das ist ja ganz schön viel geworden – Ich hoffe jemand liest das und findet Anwendung dafür.
  • Die Resultate können auf compulearnenglisch.de/uebung besichtigt werden.
  • Fragen und Kommentare wie immer erwünscht.
  • Listen machen alles übersichtlicher ;-)

Wordpress: XML-Sitemap: Zusätzliche Seiten hinzufügen

Auf compulearnenglisch.de/uebung finden sich viele generierte Seiten, die nicht in der Wordpress Datenbank gespeichert sind. Demnach werden diese Seiten nicht automatisch in der Xml-Sitemap aufgenommen.

Ein Blick in die Dokumentation genügt allerdings um das Problem zu lösen:

Adding other pages to the sitemap via other plugins

This plugin uses the action system of WordPress to allow other plugins to add urls to the sitemap. Simply add your function with add_action to the list and the plugin will execute yours every time the sitemap is build. Use the static method “GetInstance” to get the generator and AddUrl method to add your content.

1
2
3
4
5
function your_pages() {
  $generatorObject = &GoogleSitemapGenerator::GetInstance(); //Please note the "&" sign for PHP4!
  if($generatorObject!=null) $generatorObject->AddUrl("http://blog.uri/tags/hello/",time(),"daily",0.5);
}
add_action("sm_buildmap","your_pages");

HowTo: Textersetzung in mehreren Dateien mit Perl (preg) unter Windows und Linux

Neulich stellte sich mir folgendes Problem:
Ich hatte viele Dateien, in denen ich Text ersetzen wollte. Mit einem normalen Editor ist dies schlecht möglich. Abhilfe schafft der Perl Interpreter:

1
2
3
4
5
6
7
8
perl -pi -w -e 's/search/replace/g;' *.html
 
    -e Argument ausführen (execute)
    -i "in-place" editieren
    -w Warnungen ausgeben
    -p "loop"
 
siehe auch perl -h

Beispiel Datum 1

Es soll das Datum von 2008 auf 2009 in allen html-Dateien im aktuellen Verzeichnis aktualisiert werden:

1
perl -pi -w -e 's/2008/2009/g;' *.html

Beispiel Datum 2

Es soll das Datum von 200x auf 2009 in allen html-Dateien im aktuellen Verzeichnis aktualisiert werden:

1
perl -pi -w -e 's/200[0-8]/2009/g;' *.html

Beispiel: Verzeichnisse rekursiv durchsuchen (nur Linux)

1
2
3
4
5
find * | grep -E "\.html$" | xargs perl -pi -w -e 's/search/replace/g;'
 
    find * gibt alle Dateien und Verzeichnisse aus
    grep -E "\.html$" selektiert nur Dateinamen, die auf .html enden
    xargs gibt die Dateinamen als Parameter an Perl weiter

Mini Howto: Proftpd (inetd) port umstellen

Dieses HowTo behandelt das umstellen des Standard Ports (21) von Proftpd auf einen hohen Port, um Portscans zu entgehen.

Voraussetzungen:
Proftpd, über inetd gestartet

Was zu tun ist

Editiere /etc/proftpd/proftpd.conf

1
2
3
4
5
6
7
8
-- suche  --
# Port 21 is the standard FTP port.
Port                            21
 
-- ersetze durch --
# Port 21 is the standard FTP port.
# but i'm using another one
Port                            32132

Editiere /etc/inetd.conf

1
2
3
4
5
-- suche  --
ftp   stream  tcp     nowait  root    /usr/sbin/tcpd /usr/sbin/proftpd
 
-- ersetze durch --
32132   stream  tcp     nowait  root    /usr/sbin/tcpd /usr/sbin/proftpd

Nun noch inetd neu starten

1
/etc/init.d/openbsd-inetd restart

Und zum Schluss eventuell noch das Port-Forwarding im Router aktualisieren, sofern vorhanden.

HowTo: Proftpd-lenny unter debian etch 4.0 / Filezilla ECONNABORTED beheben

Dieser Artikel richtet sich an “debian etch 4.0″-Administratoren, die Proftpd aus den Paketquellen installiert haben und folgendes Problem in Filezilla haben:

Status: Server did not properly shut down TLS connection
Error: Could not read from transfer socket: ECONNABORTED – Connection aborted

Wie im Filezilla Forum zu lesen ist:

ECONNABORTED: It’s the server’s fault!

leider hilft das nicht wirklich weiter.

Die Lösung ist ganz einfach: Proftpd aus den lenny Paketquellen laden und installieren. Dieses HowTo hilft bei der Erstellung eines Proftpd-Paketes.

Vorbereiten des Systems

Für einige der nachfolgenden Befehle muss man root sein. Am besten man wird es jetzt schon.

Zum Bauen von Debian-Paketen sind einige Pakete erforderlich.

1
aptitude install devscripts build-essential fakeroot

Laden und Vorbereiten der Sourcen

Die Sourcen gibt es unter packages.debian.org/lenny/proftpd

1
2
wget http://security.debian.org/debian-security/pool/updates/main/p/proftpd-dfsg/proftpd-dfsg_1.3.1.orig.tar.gz
wget http://security.debian.org/debian-security/pool/updates/main/p/proftpd-dfsg/proftpd-dfsg_1.3.1-17lenny4.diff.gz

Auspacken des tar.gz Archives:

1
tar -xzf proftpd-dfsg_1.3.1.orig.tar.gz

Nun werden die debian-spezifischen Patches angewendet

1
2
cd cd proftpd-dfsg-1.3.1/
zcat ../proftpd-dfsg_1.3.1-17lenny4.diff.gz | patch -p1

Bauen der Pakete

1. Versuch mit debuild

1
debuild

Dieser 1. Versuch wird aller Voraussicht nach fehlschlagen, da andere Pakete fehlen, um Proftpd zu bauen. Die Fehlermeldung ist allerdings hilfreich und verrät welche Pakete noch zu installieren sind. Diese sollten nun nacheinander installiert werden. Zwischendurch immer wieder debuild probieren. Die Liste der fehlenden Pakete sollte mit jedem installierten Paket kleiner werden.
Schließlich startet debuild das Erstellen der Pakete. Dies kann einige Zeit dauern. Nicht die Geduld verlieren.

Es kann sein, dass debuild einige Fehler am Ende ausgibt, dies soll uns aber nicht weiter stören. Wenn alles geklappt hat sollten am Ende folgende Dateien vorhanden sein (je nach System kann die Liste abweichen)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cd ..
ls -al
 
-rw-r--r--  1 root root  195024 2009-11-12 17:19 proftpd_1.3.1-17lenny4_all.deb
-rw-r--r--  1 root root  696556 2009-11-12 17:19 proftpd-basic_1.3.1-17lenny4_i386.deb
drwxr-sr-x 13 root root    4096 2009-11-12 17:19 proftpd-dfsg-1.3.1
-rw-r--r--  1 root root  102934 2009-11-12 17:16 proftpd-dfsg_1.3.1-17lenny4.diff.gz
-rw-r--r--  1 root root     653 2009-11-12 17:16 proftpd-dfsg_1.3.1-17lenny4.dsc
-rw-r--r--  1 root root       0 2009-11-12 17:19 proftpd-dfsg_1.3.1-17lenny4.dsc.asc
-rw-r--r--  1 root root  124074 2009-11-12 17:19 proftpd-dfsg_1.3.1-17lenny4_i386.build
-rw-r--r--  1 root root    1700 2009-11-12 17:19 proftpd-dfsg_1.3.1-17lenny4_i386.changes
-rw-r--r--  1 root root 2662056 2009-02-25 12:55 proftpd-dfsg_1.3.1.orig.tar.gz
-rw-r--r--  1 root root 1254386 2009-11-12 17:19 proftpd-doc_1.3.1-17lenny4_all.deb
-rw-r--r--  1 root root  214058 2009-11-12 17:19 proftpd-mod-ldap_1.3.1-17lenny4_i386.deb
-rw-r--r--  1 root root  203592 2009-11-12 17:19 proftpd-mod-mysql_1.3.1-17lenny4_i386.deb
-rw-r--r--  1 root root  203562 2009-11-12 17:19 proftpd-mod-pgsql_1.3.1-17lenny4_i386.deb

Installieren von Proftpd

Bevor der neue Proftpd installiert wird sollte der alte entfernt werden

1
aptitude remove proftpd

Schließlich kann der neue Proftpd installiert werden

1
dpkg -i *.deb

Nun sollte der selbst gebaute Proftpd seinen Dienst verrichten.

Fragen und Anregungen sind in den Kommentaren gerne willkommen!

Links
Rebuilding Debian packages debian-administration.org/articles/20
Lenny Proftpd Quellen packages.debian.org/lenny/proftpd

Dank
Vielen Dank an Matthias für das “Mini-Papier-HowTo”

Fehler im WordPress Plugin All in “One SEO Pack 1.6.7″ – Rollback Anleitung / Wiederherstellung

wp-logoNach der Installation von All in One SEO Pack 1.6.7 ist es nicht mehr möglich die Konfiguration von “All in One SEO Pack” zu speichern.
Den zugehörigen Thread gibt es hier

Falls die fehlerhafte Version schon installiert wurde empfiehlt sich ein “Rollback” auf die Version 1.6.6.2:

1
2
3
4
5
6
cd wp-content/plugins
wget http://downloads.wordpress.org/plugin/all-in-one-seo-pack.1.6.6.2.zip
rm -r all-in-one-seo-pack
unzip all-in-one-seo-pack.1.6.6.2.zip
rm all-in-one-seo-pack.1.6.6.2.zip
chown -R www-data:www-data all-in-one-seo-pack

Wenn man keinen ssh Zugriff hat einfach per ftp den Ordner “all-in-one-seo-pack” in “wp-content/plugins” löschen. Dann downloads.wordpress.org/…/all-in-one-seo-pack.1.6.6.2.zip lokal entpacken und “all-in-one-seo-pack” hochladen.

Nun noch einmal auf die Plugin-Seite und das Plugin aktivieren. Nun sollte es wieder einwandfrei funktionieren.

HowTo: Eigenes Steuerelement, Eigene Eigenschaften definieren

In Visual Studio ist es möglich im Eigenschaftsfenster selbst definierte Eigenschaften anzeigen zu lassen.

Ich werde dies am Beispiel eines eigenen Buttons erklären, der eine zusätzliche Eigenschaft (WordWrap) erhält.

Legen wir zunächst einen neuen Button an. In diesem Beispiel heißt dieser FlatButton:

View Code CSHARP
1
2
class FlatButton : Button {
}

Bislang hat unser FlatButton alle Eigenschaften eines ‘normalen’ Buttons.

Nun fügen wir unsere eigene Eigenschaft hinzu:

View Code CSHARP
1
2
3
4
5
6
7
8
9
10
class FlatButton : Button {
    bool wordWrap = false;
    [Browsable(true)]
    [Category("Appearance")]
    public bool WordWrap
    {
        get { return wordWrap; }
        set { wordWrap = value; Invalidate(); }
    }
}

[Browsable(true)] gibt an, dass WordWrap im Eigenschaftsfenster angezeigt werden soll.
[Category("Appearance")] lässt WordWrap in der Kategorie Darstellung erscheinen.

Wenn alles geklappt hat sollte nun WordWrap im Eigenschaftsfenster angezeigt werden:
FlatButtonProperties

FlatButton mit WordWrap=true bei geeigneter Implementierung von OnPaint:
FlatButton

Weitergehende Informationen gibt es in der MSDN
system.componentmodel.browsableattribute
system.componentmodel.categoryattribute

C#: Strg+C, Strg+V, Strg+X

In einer benutzerfreundlichen Anwendung sollte der Benutzer wenn möglich Strg+C, Strg+V und Strg+X verwenden können.

Dies ist einfach zu realisieren:

View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
 
class MyForm : Form
{
	protected override void OnKeyDown(KeyEventArgs e)
	{
		if (e.Modifiers == Keys.Control)
		{
			switch (e.KeyCode)
			{
				case Keys.C:
					tryCopy();
					break;
				case Keys.V:
					tryPaste(); 
					break;
				case Keys.X:
					tryCut();
					break;
				case Keys.Delete:
					tryDelete();
					break;
				case Keys.Right:
					tryMoveNext();
					break;
				case Keys.Left:
					tryMovePrevious();
					break;
			}
		}
		base.OnKeyDown(e);
	}
}

Nun noch die tryXY-Funktionen implementieren und fertig ist die Tastaturbedienung des Programms.

HowTo: Subversion Server / svnserve unter debian

subversion_logo_hor-468x64

Es wird die Einrichtung eines Subversion Servers und eines Repositories unter Debian behandelt.

Dieses HowTo setzt voraus, dass man sich mit TortoiseSVN oder einem anderen SVN-Client bereits auskennt.
Weiterlesen »

Debian: Netzwerkkarte austauschen – aus eth0 wird eth1

debian-openlogo-nd-50Wenn man in Debian die Netzwerkkarte oder gleich das ganze Mainboard samt onboard Netzwerk austauscht wird man feststellen, dass das Netzwerk nach dem Tausch der Hardware nicht mehr funktioniert, auch wenn die Netzwerkkarten gleich sind.

Das Problem ist, dass die Netzwerkkarten zwar gleich, aber nicht identisch sind. Jedes Netzwerkgerät hat eine eindeutige MAC-Adresse. Debian erkennt die neue Netzwerkkarte unter der neuen MAC-Adresse und legt einen neuen Netzwerkadapter (eth1) an.

Mit einem

1
grep -R eth1 /etc

ist die verantwortliche Datei schnell gefunden: /etc/udev/rules.d/z25_persistent-net.rules

nach dem Tausch der Netzwerkhardware sollte die Datei ungefähr so aussehen:

1
2
3
4
5
# PCI device ...
SUBSYSTEM=="net", DRIVERS=="?*", ATTRS{address}=="xx:xx:xx:xx:xx:xx", NAME="eth0"
 
# PCI device ...
SUBSYSTEM=="net", DRIVERS=="?*", ATTRS{address}=="xx:xx:xx:xx:xx:xx", NAME="eth1"

Nun einfach das 1. Gerät auskommentieren oder löschen und beim 2. “eth0″ als Namen eintragen:

1
2
3
4
5
6
# auskommentiert: alte Netzwerkkarte!!!
# PCI device ...
#SUBSYSTEM=="net", DRIVERS=="?*", ATTRS{address}=="xx:xx:xx:xx:xx:xx", NAME="eth0"
 
# PCI device ...
SUBSYSTEM=="net", DRIVERS=="?*", ATTRS{address}=="xx:xx:xx:xx:xx:xx", NAME="eth0"

Weitere Änderungen sind nicht notwendig und nach einem Neustart des Systems funktioniert alles wieder wie gewohnt.

WordPress Themes