HTML mit PHP intelligent verknüpfen

Musstest du schon einmal eine PHP-Webseite erstellen? Wie bist du dabei vorgegangen? Wahrscheinlich hast du dir zunächst eine HTML-Struktur vorbereitet und danach die PHP-Variablen oder Werte aus deiner Datenbank eingefügt.

Den Header und Footer hast du dann wie üblich in eigene Dateien ausgelagert.

 

Es gibt eine Menge verschiedener Herangehensweisen, wie die PHP-Variablen in einer HTML-Struktur ausgegeben werden können.

Sehr viele Content Management Systeme bauen ihren Inhalt ebenfalls auf einer HTML-Struktur auf und verbinden diese stark mit dem PHP-Algorithmus. Wenn du schon einmal mit einem WordPress- oder ModX-Template gearbeitet hast weißt du wovon ich schreibe.

Bei kleineren Projekten kann das durchaus ausreichen. Aber was, wenn mehrere Entwickler an einem riesigen Projekt arbeiten?

 

In den letzten Wochen habe ich mir ein anderes Konzept für die Aufbereitung von strukturierten Inhalten überlegt, um die Struktur klar vom Algorithmus zu trennen, nachdem mir das ständige Suchen nach einer bestimmten Struktur einfach zu viel Zeit in Anspruch genommen hatte.

Wenn du schon einmal mit Typo3 gearbeitet hast, wird dir dieses Konzept vielleicht bekannt vorkommen.

In diesem Beitrag möchte ich dir meine Idee näher bringen. (Vorsicht: Du solltest bereits Erfahrungen mit PHP gesammelt haben)

Falls dir die Vererbung in PHP noch nicht gängig ist, findest du am Ende des Beitrags eine kleine Einführung. Ich gehe nicht detailliert darauf ein, jedoch erhältst du einen Einblick in die Objekt Orientierte Programmierung mit PHP.

Die Idee: Verwendung von Strukturen und Platzhaltern

Die Grundidee ist relativ einfach erklärt. Für meinen Algorithmus verwende ich HTML-Dateien in denen verschiedene Platzhalter vorhanden sind.

Der PHP-Code beinhaltet eine Array, die aus den Platzhaltern und deren zu austauschenden Werte besteht.

Diese Art zu entwickeln hat mehrere Vorteile:

  • Man kann PHP-Klassen verwenden, die sich um unterschiedliche Bestandteile der Webseite kümmern
  • Die Programmstruktur ist wesentlich einfacher aufgebaut, da es einen Ordner im Projekt gibt, der sich nur um die HTML-Strukturen kümmert und einen, der sich ausschließlich um die Logik kümmert
  • In WordPress kann man es externen Programmierern erleichtern die HTML-Strukturen zu bearbeiten, ohne das Webseiten-Template anzufassen
  • Die HTML-Strukturen mit dessen Platzhaltern können in CMS-Unabhängigen Systemen auch von Nicht-Programmierern bearbeitet werden, da man nur HTML-Kenntnisse benötigt
  • Platzhalter sind einfach erweiterbar, auch von externen Programmierern (Ebenfalls in WordPress-Projekten)
  • Die HTML-Elemente bleiben atomar und können sehr einfach in verschiedenen Ansichten wiederverwendet werden

Vorbereitung einer HTML-Struktur

Eine Struktur kann mithilfe einer einfachen HTML-Datei erstellt werden. Diese beinhaltet die Struktur inklusive Platzhalter.

Als Entwickler muss man sich für eine Platzhalter-Struktur entscheiden. Ich verwende gerne einen Key innerhalb zweier Prozentzeichen: %KEY%

Die HTML-Struktur kann zum Beispiel so aussehen:

<div %CLASS%>
	<img src="%IMAGE%" />
	<%HEADLINE_TAG%>%HEADLINE%</%HEADLINE_TAG%>
	%CONTENT%
</div>

Das ist ein sehr rudimentäres Beispiel. Unser Inhalt wird von einem <div>-Tag umschlossen. Zudem kann dieses umschließende Element eine Klasse besitzen, die von einem PHP-Code erstellt und mit dem Platzhalter %CLASS% ersetzt wird. Ich verwende nicht class='%CLASS%', da es auch vorkommen kann, dass das Attribut nicht benötigt wird. Andernfalls würde ein leeres Attribut class='' gesetzt werden.

Innerhalb des Elements gibt es ein Bild, eine Überschrift und den Inhalt, wobei die Überschrift von einem <h>-Tag umschlossen wird. Den Platzhalter %HEADLINE_TAG% kannst du auch entfernen und einen fixen Wert eintragen.

Da ich überwiegend WordPress-Entwickler bin, denke ich bei dem "H-Tag"-Platzhalter an einen Shortcode. Über die Attribute dieses Shortcodes kann ein Redakteur das HTML-Tag wählen. Dadurch wird das Element ein wenig dynamischer und anpassbarer.

Ein Platzhalter muss nicht nur eine einzelne Zeichenkette abbilden. Du kannst auch eine Struktur innerhalb einer anderen Struktur durch einen Platzhalter austauschen lassen, wodurch du du zum Beispiel in einer index.html den Header und Footer hinzufügen kannst.

Platzhalter für die Struktur definieren

Die Platzhalter werden als assoziative Array erstellt, damit wir den Platzhalter als Index verwenden können.

Der Wert des Array-Items stellt den Platzhalter dar, wodurch der Wert in der Array ersetzt werden soll.

Dank dieser Struktur können Frontend-Entwickler die Platzhalter jederzeit Verschieben, ohne den Backend-Entwickler zu konsultieren. Jedoch müssen die Backend-Programmierer beauftragt werden, falls neue Platzhalter benötigt werden.

<?php
	
	$placeholders = array(
		'CLASS'		=> 'content_container',
		'IMAGE'		=> '<img src="path/to/image.jpg" />',
		'HEADLINE'	=> 'Eine Überschrift',
		'HEADLINE_TAG'	=> 'h3',
		'CONTENT'	=> '<p>Lorem ipsum dolor sit amet</p>'
	);
	
?>

Die Platzhalter werden später aus der Datenbank entnommen. Die Array oben soll nur als Beispiel dienen.

Im nächsten Schritt müssen wir die Platzhalter nur noch durch eine foreach-Schleife jagen, damit sie ausgetauscht werden.

 

Die Umsetzung der notwendigen Funktionen

Damit der Algorithmus für jede Struktur und alle möglichen Platzhalter funktioniert, benötigen wir ein paar wesentliche Funktionen, die wir im Anschluss als PHP-Klasse umsetzen werden.

Zunächst erkläre ich dir aber den funktionellen Aufbau des Programms.

Ersetzen der Platzhalter

Wie bereits beschrieben, benötigen wir für das Austauschen der Platzhalter nur eine Schleife. Durch die Funktion str_replace werden die Platzhalter durch die tatsächlichen Werte ersetzt.

<?php

function replace_strings( $structure, $replacements ) {
	
	// Durchläuft jeden einzelnen Platzhalter aus der Array "$replacements" und ersetzt die Vorkommnisse in der Variable "$structure"
	foreach( $replacements as $placeholder => $replacement ) {
		
		// Die Prozent-Zeichen kannst du auch durch andere, eindeutige Zeichen ersetzen. Bearbeite die entsprechenden Stellen auch in deiner Struktur!
		$placeholder = "%$placeholder%";
		$structure = str_replace( $placeholder, $replacement, $structure );
		
	}
	
	return $structure;
	
}

?>

Die HTML-Struktur laden

Nun benötigen wir eine Funktion, die die Struktur aus einer Datei lädt. Du kannst auch einen Fallback innerhalb der Funktion angeben, falls die Funktion "file_get_contents" nicht auf dem Server funktioniert oder die Datei nicht existiert.

<?php

function get_container_structure() {
	
	// Sollte es die Datei "structure.html" geben, wird der Inhalt daraus unsere Content-Container Struktur
	$structure = "";
	$structure_file_path = "path/to/structure.html";
	if( file_exists( $structure_file_path ) ) {
		$structure = file_get_contents( $structure_file_path );
	}
	
	// Das ist ein Fallback, falls es unsere Struktur nicht gibt. Du kannst das Laden der Datei auch komplett entfernen, wenn du möchtest.
	// Eine Alternative wäre hier eine Fehlermeldung auszugeben, dass die Datei nicht geladen werden konnte.
	if( empty( $structure ) ) {
		ob_start();
		?>
			<div %CLASS%>
				<img src="%IMAGE%" />
				<%HEADLINE_TAG%>%HEADLINE%</%HEADLINE_TAG%>
				%CONTENT%
			</div>
		<?php
		$structure = ob_get_clean();
	}
	
	// Damit andere Entwickler Änderungen an der Struktur vornehmen können, ohne unseren Code anzufassen, stellt WordPres die Funktion "appyly_filters" zur Verfügung
	$structure = apply_filters( 'edit_container_structure', $structure );
	
	return $structure;
	
}

?>

Verwende ein Caching-Tool! Dadurch muss der Algorithmus nicht bei jedem einzelnen Aufruf der Webseite neu ausgeführt werden. Das Google Pagespeed Modul kannst du einfach auf deinem Webserver installieren und konfigurieren, um deine Inhalte zu cachen.

Vorbereitung der Platzhalter

Die Platzhalter kannst du nach belieben und pro Element bestimmen. Im nachfolgendem Beispiel verwende ich WordPress-Funktionen, um an die Text-Bausteine zu gelangen.

Du kannst bei einem unabhängigen System auch eine SQL-Abfrage starten, um die Daten in deinem PHP-Script vorzubereiten.

<?php

function get_container_replacements() {
	
	// Der nachfolgende Code ist für WordPress geeignet. Solltest du ein anderes CMS verwenden, kannst du die Platzhalter nach Belieben bearbeiten.
	global $post;
	$container_replacements = array(
		'CLASS'			=> get_classes( array( 'content_container', 'has_image' ) ),
		'IMAGE'			=> get_the_post_thumbnail_url( $post->ID, 'full' ),
		'HEADLINE'		=> $post->post_title,
		'HEADLINE_TAG'		=> 'h3',
		'CONTENT'		=> $post->post_excerpt
	);
	
	// Damit andere Entwickler weitere Platzhalter vorbereiten können, ohne unseren Code anzufassen, stellt WordPres die Funktion "appyly_filters" zur Verfügung
	$container_replacements = apply_filters( 'edit_container_replacements', $container_replacements );
	
	return $container_replacements;
	
}

?>

Aufbereitung der CSS-Klassen

Mit einer Mini-Funktion zur Erstellung des Attributs "class" bist du an kein bestimmtes Element gebunden. Du kannst durch eine einfache Array alle notwendigen Klassen angeben.

Ich finde diese Art der Klassen-Aufbereitung sehr schön, da ich einfach nur eine Array angeben muss. Diese Daten können auch einfach zwischengespeichert, von anderen Entwicklern manipuliert oder weiterverarbeitet werden.

<?php

function get_classes( array $classes = array() ) {
	
	// Erstellt einen String aus der Array und fügt diesen in ein Attribut "class" ein
	$classes = trim( join( " ", $classes ) );
	return "class='$classes'";
	
}

?>

Nicht benötigte Platzhalter entfernen

Sollten nicht alle Platzhalter in der $replacements-Array angegeben werden, die in der HTML-Struktur vorkommen, werden die Platzhalter 1 zu 1 im HTML-Code ausgegeben.

Damit das nicht geschieht, können alle Platzhalter die dem System fremd sind, nach dem ersetzen gelöscht werden.

Solltest du eine andere Platzhalter-Struktur als ich verwenden (%KEY%), musst du das RegEx in der Funktion preg_replace anpassen.

<?php

function clean_placeholders( string $structure = "" ) {
	
	// Räumt alle Platzhalter auf, die durch das Ersetzen nicht überschrieben wurden
	return preg_replace( "/\%(.*)\%/gU", '', $structure );
	
}

?>

Meine Regular Expressions plane ich immer mit dem Tool Regex101. Damit kann ich genau überprüfen, welche Bestandteile der Struktur ausgewählt werden, bevor ich meinen Code teste.

Setze die Funktionen zusammen

Nachdem die wichtigsten Funktionen zusammengesetzt wurden, benötigen wir noch eine Funktion die alles zusammensetzt und ausgeben kann.

Zuerst wird die Struktur und die Platzhalter in Variablen gespeichert. Danach wenden wir die Funktion "replace_strings()" an, um die Platzhalter in der Struktur auszutauschen. Den Rückgabewert sichern wir in einer Variable, bevor wir den "return" darauf anwenden. Dadurch haben wir später noch die Möglichkeit Filter anzuwenden.

Bevor das HTML-Element geliefert wird, sollen jedoch alle nicht-umgesetzten Platzhalter gelöscht werden. Dies geschieht durch unsere Funktion "clean_placeholders()".

<?php

function get_content_container() {
	
	// Erhalte die HTML-Struktur des Containers
	$container_structure = get_container_structure();
	// Erhalte alle Platzhalter des Containers
	$container_replacements = get_container_replacements();
	
	// Ersetze alle Platzhalter
	$parsed_container = replace_strings(
		$container_structure,
		$container_replacements
	);
	
	return clean_placeholders( $parsed_container );
	
}

?>
 

Eine Klasse als Vorlage erstellen

Damit wir diese Funktionen nicht immer wieder für verschiedene Elemente aufbauen müssen und damit wir eine bessere Übersicht erhalten, bereiten wir uns aus diesen Funktionen eine Klasse auf.

Die Parent-Klasse "Structure" enthält alle wichtigen Funktionen, die wir immer wieder verwenden können.

Eine Child-Klasse (als Beispiel "Container") verwendet die Funktionen der Parent-Klasse und fügt die individuellen Elemente "Platzhalter" und "Struktur" ein.

Die Eltern-Klasse

Die Eltern-Klasse beinhaltet alle Funktionen, die immer wieder benötigt werden. Damit du dich hier zurechtfindest, habe ich die Funktionsnamen aus dem obigen Beispiel nicht geändert. Du kannst sie natürlich nach belieben anpassen.

Folgende Funktionen benötigt unsere Parent-Klasse:

  • Der Konstruktor bereitet die wichtigen Variablen vor. Damit sind die Struktur und die Platzhalter gemeint.
  • Die Funktion zur Rückgabe des umgesetzten HTML-Elements "get_content_container()"
  • Die Funktion zum Austauschen der Platzhalter "replace_strings()"
  • Eine Funktion zum Erhalt der Platzhalter "get_container_replacements()". Diese wird später von der Child-Klasse überschrieben. Du kannst auch eine abstrakte Funktion daraus erstellen.
  • Die abstrakte Funktion "get_container_structure()". Diese muss in der Child-Klasse erstellt werden.
  • Eine Funktion "get_container_structure_from_file()" hilft beim Erhalt der Struktur aus einer Datei. Der Pfad wird im Konstruktor der Parent-Klasse angegeben.
  • Die Funktion "get_classes()" bereitet die übergebene Array als HTML-Attribut "class" auf und gibt diese zurück.
  • Zuletzt die Funktion "clean_placeholders()", die alle Platzhalter einer HTML-Struktur entfernt. Sie sollte erst nach der Funktion "replace_strings()" aufgerufen werden.
<?php
	
	abstract class Structure {
		
		protected $structure_file_path;
		protected $replacements;
		function __construct( string $structure_file_path = "", array $replacements = array() ) {
			
			$this->structure_file_path = $structure_file_path;
			$this->replacements = $replacements;
			
		}
		
		public function get_content_container() {
			
			$container_structure = $this->get_container_structure();
			$container_replacements = $this->get_container_replacements();
			
			$parsed_container = $this->replace_strings(
				$container_structure,
				$container_replacements
			);
			
			return $this->clean_placeholders( $parsed_container );
			
		}
		
		protected function replace_strings( string $structure, array $replacements = array() ) {
			
			foreach( $replacements as $placeholder => $replacement ) {
				
				$placeholder = "%$placeholder%";
				$structure = str_replace( $placeholder, $replacement, $structure );
				
			}
			
			return $structure;
			
		}
		
		protected function get_container_replacements() {
			
			$container_replacements = $this->replacements;
			return $container_replacements;
			
		}
		
		abstract protected function get_container_structure();
		
		protected function get_container_structure_from_file() {
			
			$structure = "";
			if( !empty( $this->structure_file_path ) && file_exists( $this->structure_file_path ) ) {
				$structure = file_get_contents( $this->structure_file_path );
			}
			
			return $structure;
			
		}
		
		protected function get_classes( array $classes = array() ) {
			
			// Erstellt einen String aus der Array und fügt diesen in ein Attribut "class" ein
			$classes = trim( join( " ", $classes ) );
			return "class='$classes'";
			
		}
		
		protected function clean_placeholders( string $structure = "" ) {
			
			return preg_replace( "/\%(.*)\%/gU", '', $structure );
			
		}
		
	}
	
?>

Die Kind-Klasse

Die nachfolgende Kind-Klasse kannst du als Vorlage für alle weiteren Elemente verwenden. Wichtig ist, dass du die Platzhalter als Array und die HTML-Struktur vorbereitest bevor du die Funktion testest.

Der Pfad der HTML-Struktur wird an die Eltern-Klasse übergeben. Genauso wie die Rückgabe der Funktion "get_container_replacements()", die die Platzhalter-Array zurückgibt.

Die Struktur soll durch einen WordPress-Filter von einem externen Programmierer bearbeitet werden können. Deshalb wird die Funktion "get_container_replacements()" nicht in der Eltern-Klasse erstellt. Durch die eigenständige Funktion können wir einen individuellen Filter-Aufruf "edit_container_replacements" definieren.

<?php
	
	class Container extends Structure {
		
		function __construct() {
			
			parent::__construct( 'path/to/container.html', $this->get_container_replacements() );
			
		}
		
		protected function get_container_replacements() {
			
			global $post;
			$container_replacements = array(
				'CLASS'			=> $this->get_classes( array( 'content_container', 'has_image' ) ),
				'IMAGE'			=> get_the_post_thumbnail_url( $post->ID, 'full' ),
				'HEADLINE'		=> $post->post_title,
				'HEADLINE_TAG'		=> 'h3',
				'CONTENT'		=> $post->post_excerpt
			);
			
			$container_replacements = apply_filters( 'edit_container_replacements', $container_replacements );
			
			return $container_replacements;
			
		}
		
		protected function get_container_structure() {
			
			$structure = $this->get_container_structure_from_file();
			if( !empty( $structure ) ) {
				
				return $structure;
				
			}
			
			$structure = apply_filters( 'edit_container_structure', $structure );
			
			return $structure;
			
		}
		
	}
	
?>

Ein Element aus der Kind-Klasse erhalten

Damit dein Element auf deiner Webseite erscheint, muss diese noch auf deiner eigentlichen Seite platziert werden.

Bevor du das Element verwenden kannst, musst du eine neue Variable (im nachfolgenden Beispiel "$container") erstellen in der das Object "Container" definiert ist.

Mit einem "echo" und dem Funktions-Aufruf "get_content_container()" wird dann das umgesetzte HTML-Konstrukt auf deiner Webseite ausgegeben.

<?php
	
	$container = new Container();
	echo $container->get_content_container();
	
?>

Beispiel für das atomare PHP herunterladen

Damit du den Aufbau der Ordner-Struktur meines Skripts richtig verstehst, habe ich dir alles in einer ZIP-Datei vorbereitet.

Du findest in dieser Datei eine index.php, die die Container-Klasse erstellt. Der Ordner "structures" beinhaltet alle HTML-Strukturen die du auch nach Belieben in Unterordner packen kannst. Im Ordner "inc" findest du die PHP-Klassen.

Beispiel herunterladen

Fazit

Durch das "Aufbrechen" der verschiedenen Webseiten-Bestandteile und Elemente werden Strukturen von der Logik strikt getrennt.

Somit können große Teams Aufgaben auch wesentlich besser aufteilen, indem man ein Teil des Teams für die Erstellung der HTML-Strukturen und CSS-Stile einteilt und ein anderes Team ausschließlich für die Programmierung.

Diese saubere Trennung der Webseiten-Bestandteile führt zu einer Optimierung der Kerntätigkeiten und somit eine Fokusierung der einzelnen Mitarbeiter. Zudem resultiert diese Trennung in einer besseren Übersichtlichkeit des Programmcodes, dadurch können neue Mitarbeiter schneller in ein bestehendes Projekt einsteigen.

 

Hat dir mein Beitrag gefallen? Schreibe mir in den Kommentaren, wie du in deinen Projekten vorgehst!

 

Codepalm
Atomare Webseiten-Struktur mit HTML und PHP