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