<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://wiki.stephanschlegel.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=84.155.186.35</id>
	<title>Wikizone - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.stephanschlegel.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=84.155.186.35"/>
	<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Spezial:Beitr%C3%A4ge/84.155.186.35"/>
	<updated>2026-05-06T13:57:32Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.35.14</generator>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=UIkit_Theme_mit_Sass_erstellen&amp;diff=24870</id>
		<title>UIkit Theme mit Sass erstellen</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=UIkit_Theme_mit_Sass_erstellen&amp;diff=24870"/>
		<updated>2020-11-15T13:48:45Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Theme Datei erstellen z.B. site.scss&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sass&amp;quot;&amp;gt;&lt;br /&gt;
// 1. Your custom variables and variable overwrites.&lt;br /&gt;
$global-link-color: #DA7D02;&lt;br /&gt;
&lt;br /&gt;
// 2. Import default variables and available mixins.&lt;br /&gt;
@import &amp;quot;uikit/src/scss/variables-theme.scss&amp;quot;;&lt;br /&gt;
@import &amp;quot;uikit/src/scss/mixins-theme.scss&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// 3. Your custom mixin overwrites.&lt;br /&gt;
@mixin hook-card() { color: #000; }&lt;br /&gt;
&lt;br /&gt;
// 4. Import UIkit.&lt;br /&gt;
@import &amp;quot;uikit/src/scss/uikit-theme.scss&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 https://getuikit.com/docs/sass&lt;br /&gt;
&lt;br /&gt;
Todo&lt;br /&gt;
&lt;br /&gt;
The compiled CSS will then have your custom value. But not only has the global link color changed. Many components make use of the @global-* variables to infer their own colors, and just adapt them slightly. That way you can rapidly create a theme by just changing some global variables.&lt;br /&gt;
&lt;br /&gt;
== Inverse Komponenten abschalten ==&lt;br /&gt;
Disable inverse component&lt;br /&gt;
The Inverse component includes additional styles to implement the flexible inverse behaviour. If your project does not make use of these styles, you can leave them out when compiling Sass. This allows smaller file sizes of the compiled CSS. To do so, search for Sass variables containing color-mode (e.g. $inverse-global-color-mode), and set them to none.&lt;br /&gt;
&lt;br /&gt;
To disable the inverse styles completely, set:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sass&amp;quot;&amp;gt;&lt;br /&gt;
$inverse-global-color-mode: none;&lt;br /&gt;
You can also disable the inverse mode for specific components:&lt;br /&gt;
&lt;br /&gt;
// Card&lt;br /&gt;
$card-primary-color-mode: none;&lt;br /&gt;
$card-secondary-color-mode: none;&lt;br /&gt;
&lt;br /&gt;
// Navbar&lt;br /&gt;
$navbar-color-mode: none;&lt;br /&gt;
&lt;br /&gt;
// Off-canvas&lt;br /&gt;
$offcanvas-bar-color-mode: none;&lt;br /&gt;
&lt;br /&gt;
// Overlay&lt;br /&gt;
$overlay-primary-color-mode: none;&lt;br /&gt;
&lt;br /&gt;
// Section&lt;br /&gt;
$section-primary-color-mode: none;&lt;br /&gt;
$section-secondary-color-mode: none;&lt;br /&gt;
&lt;br /&gt;
// Tile&lt;br /&gt;
$tile-primary-color-mode: none;&lt;br /&gt;
$tile-secondary-color-mode: none;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Komplexere Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sass&amp;quot;&amp;gt;&lt;br /&gt;
The entry point for the Sass compiler is site.scss. Here you compile all source files in the following order:&lt;br /&gt;
&lt;br /&gt;
// site.scss&lt;br /&gt;
&lt;br /&gt;
// 1. Your custom variables and variable overwrites.&lt;br /&gt;
@import &amp;quot;theme/accordion.scss&amp;quot;;&lt;br /&gt;
@import &amp;quot;theme/alert.scss&amp;quot;;&lt;br /&gt;
@import &amp;quot;theme/align.scss&amp;quot;;&lt;br /&gt;
// ... import all&lt;br /&gt;
&lt;br /&gt;
// 2. Import default variables and available mixins.&lt;br /&gt;
@import &amp;quot;uikit/src/scss/variables.scss&amp;quot;;&lt;br /&gt;
@import &amp;quot;uikit/src/scss/mixins.scss&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// 3. Your custom mixin overwrites.&lt;br /&gt;
@import &amp;quot;theme/accordion-mixins.scss&amp;quot;;&lt;br /&gt;
@import &amp;quot;theme/alert-mixins.scss&amp;quot;;&lt;br /&gt;
@import &amp;quot;theme/align-mixins.scss&amp;quot;;&lt;br /&gt;
// ... import all&lt;br /&gt;
&lt;br /&gt;
// 4. Import UIkit&lt;br /&gt;
@import &amp;quot;uikit/src/scss/uikit.scss&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now you can compile site.scss and the resulting CSS will include all your customizations.&lt;br /&gt;
&lt;br /&gt;
NOTE You can further extend this setup by replacing part &amp;quot;4.&amp;quot; with single import statements from the UIkit source. You can then omit some components you do not use to produce smaller CSS. Just copy from src/scss/components/_import.scss and make sure to preserve the correct import order.&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=UIkit_Theme_mit_Sass_erstellen&amp;diff=24869</id>
		<title>UIkit Theme mit Sass erstellen</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=UIkit_Theme_mit_Sass_erstellen&amp;diff=24869"/>
		<updated>2020-11-15T12:51:55Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: Die Seite wurde neu angelegt: „Theme Datei erstellen z.B. site.scss  &amp;lt;syntaxhighlight lang=&amp;quot;sass&amp;quot;&amp;gt; // 1. Your custom variables and variable overwrites. $global-link-color: #DA7D02;  // 2. Im…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Theme Datei erstellen z.B. site.scss&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sass&amp;quot;&amp;gt;&lt;br /&gt;
// 1. Your custom variables and variable overwrites.&lt;br /&gt;
$global-link-color: #DA7D02;&lt;br /&gt;
&lt;br /&gt;
// 2. Import default variables and available mixins.&lt;br /&gt;
@import &amp;quot;uikit/src/scss/variables-theme.scss&amp;quot;;&lt;br /&gt;
@import &amp;quot;uikit/src/scss/mixins-theme.scss&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// 3. Your custom mixin overwrites.&lt;br /&gt;
@mixin hook-card() { color: #000; }&lt;br /&gt;
&lt;br /&gt;
// 4. Import UIkit.&lt;br /&gt;
@import &amp;quot;uikit/src/scss/uikit-theme.scss&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=UIkit&amp;diff=24868</id>
		<title>UIkit</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=UIkit&amp;diff=24868"/>
		<updated>2020-11-15T12:49:36Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Sass Strategie ==&lt;br /&gt;
[[UIkit Theme mit Sass erstellen]]&lt;br /&gt;
&lt;br /&gt;
== Less Strategie ==&lt;br /&gt;
=== UIKit mit Yarn installieren ===&lt;br /&gt;
&lt;br /&gt;
[[Yarn]] ist ein Paketmanager. Wenn dieser installiert ist kann man es einfach hinzufügen. Hinweis: es gibt wohl auch eine npm Version. Nach Recherche scheint Yarn hinsichtlich Müllerzeugung, Sicherheit und Deinstallierbarkeit auf dem Rechner das bessere Instrument sein. &lt;br /&gt;
&lt;br /&gt;
 yarn add uikit&lt;br /&gt;
&lt;br /&gt;
Dann wird in node_modules uikit installiert&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FOLDER	DESCRIPTION&lt;br /&gt;
/src	Contains all Less, JavaScript and image sources.&lt;br /&gt;
/dist	Contains compiled CSS and JS, updated on every release.&lt;br /&gt;
/tests	Contains HTML test files of all components.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ordnerstruktur ===&lt;br /&gt;
&lt;br /&gt;
=== Watcher ===&lt;br /&gt;
&lt;br /&gt;
=== Angepasste Less / CSS Dateien mit dem Customizer ===&lt;br /&gt;
&lt;br /&gt;
== Manuelle Strategie  ==&lt;br /&gt;
=== UIKit Customizer ===&lt;br /&gt;
&lt;br /&gt;
Erzeugt ein Theme CSS Dateien&lt;br /&gt;
&lt;br /&gt;
== UIKit Events ==&lt;br /&gt;
Die UIKit Komponenten stellen Events zur Verfügung die man für eigene Skripte nutzen kann. &lt;br /&gt;
&lt;br /&gt;
=== Beispiele ===&lt;br /&gt;
Slideshow Events&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Using **** JQuery ****&lt;br /&gt;
// Initialize slideshow&lt;br /&gt;
var slideshow = UIkit.slideshow(&amp;#039;#slideshow&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
// Variable with element that fire event&lt;br /&gt;
var $slideItem = $(&amp;#039;#slideshow ul &amp;gt; li&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
$slideItem.on(&amp;#039;beforeitemshow&amp;#039;, function(){&lt;br /&gt;
   UIkit.notification({ message: &amp;#039;Fire Before Item Show&amp;#039;, timeout:1000 });&lt;br /&gt;
});&lt;br /&gt;
$slideItem.on(&amp;#039;itemshown&amp;#039;, function(){&lt;br /&gt;
   UIkit.notification({ message: &amp;#039;Item shown&amp;#039;, timeout:1000 });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Toggle Component Events (Vanilla JS)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html5&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;uk-container&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div class=&amp;quot;uk-grid-expand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;UIKit Toggle Events&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;button id=&amp;quot;toggle&amp;quot; uk-toggle=&amp;quot;target: #target&amp;quot;&amp;gt;THE TRIGGER&amp;lt;/button&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;target&amp;quot;&amp;gt;THE TARGET&amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var ready = (callback) =&amp;gt; {&lt;br /&gt;
  if (document.readyState != &amp;quot;loading&amp;quot;) callback();&lt;br /&gt;
  else document.addEventListener(&amp;quot;DOMContentLoaded&amp;quot;, callback);&lt;br /&gt;
}&lt;br /&gt;
ready(() =&amp;gt; { &lt;br /&gt;
  // get element that fires the events (use the target not the trigger)&lt;br /&gt;
  var ele = document.getElementById(&amp;#039;target&amp;#039;);&lt;br /&gt;
  &lt;br /&gt;
  // catch events and do something &lt;br /&gt;
  ele.addEventListener(&amp;#039;shown&amp;#039;,function(e){&lt;br /&gt;
    UIkit.notification({ message: &amp;#039;shown event fired&amp;#039;, timeout:2000 });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  ele.addEventListener(&amp;#039;hidden&amp;#039;, function(e){&lt;br /&gt;
    UIkit.notification({ message: &amp;#039;hidden event fired&amp;#039;, timeout:2000 });&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
// other events are: beforeshow, show, beforehide, hide&lt;br /&gt;
// Ref: https://getuikit.com/docs/toggle&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Konfigurierbare_Module&amp;diff=24856</id>
		<title>ProcessWire - Konfigurierbare Module</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Konfigurierbare_Module&amp;diff=24856"/>
		<updated>2020-11-07T13:25:08Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ab ProcessWire 2.5.5. kann man Module mit Konfigurationsmöglichkeiten einfacher erstellen. Die Konfigurationsoptionen lagert man in eine extra Datei aus. &lt;br /&gt;
&lt;br /&gt;
 https://processwire.com/blog/posts/new-module-configuration-options/&lt;br /&gt;
 https://processwire.com/api/ref/modules/save-config/&lt;br /&gt;
&lt;br /&gt;
Beispiel Modul &amp;quot;Test&amp;quot; (gibt eine Meldung im Admin bei jeder Seitenladen aus)&lt;br /&gt;
&lt;br /&gt;
* Datei mit dem Namen und Klasse [Modulname]Config erstellen&lt;br /&gt;
* Klasse extends ModulConfig&lt;br /&gt;
* Default Werte über getDefaults() Funktion definieren&lt;br /&gt;
* Inputfelder über getInputfields() Funktion definieren&lt;br /&gt;
&lt;br /&gt;
Test.php&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
class Test extends WireData implements Module {&lt;br /&gt;
  public static function getModuleInfo() {&lt;br /&gt;
    return array(&lt;br /&gt;
     &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Module Test&amp;#039;,&lt;br /&gt;
     &amp;#039;version&amp;#039; =&amp;gt; 1,&lt;br /&gt;
     &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Module for testing/demo purposes.&amp;#039;,&lt;br /&gt;
     &amp;#039;autoload&amp;#039; =&amp;gt; &amp;#039;template=admin&amp;#039;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  public function ready() {&lt;br /&gt;
    if($this-&amp;gt;fullname &amp;amp;&amp;amp; !count($this-&amp;gt;input-&amp;gt;post)) {&lt;br /&gt;
      $msg = &amp;quot;Hi $this-&amp;gt;fullname! &amp;quot;;&lt;br /&gt;
      $msg .= &amp;quot;Your age: $this-&amp;gt;age. &amp;quot;;&lt;br /&gt;
      $msg .= &amp;quot;Favorite color: $this-&amp;gt;color.&amp;quot;;&lt;br /&gt;
      $this-&amp;gt;message($msg);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TestConfig.php&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
class TestConfig extends ModuleConfig {&lt;br /&gt;
  public function getDefaults() {&lt;br /&gt;
    return array(&lt;br /&gt;
      &amp;#039;fullname&amp;#039; =&amp;gt; &amp;#039;&amp;#039;,&lt;br /&gt;
      &amp;#039;color&amp;#039; =&amp;gt; &amp;#039;blue&amp;#039;,&lt;br /&gt;
      &amp;#039;age&amp;#039; =&amp;gt; 40,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  public function getInputfields() {&lt;br /&gt;
    $inputfields = parent::getInputfields();&lt;br /&gt;
&lt;br /&gt;
    $f = $this-&amp;gt;modules-&amp;gt;get(&amp;#039;InputfieldText&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;attr(&amp;#039;name&amp;#039;, &amp;#039;fullname&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;label = &amp;#039;Full Name&amp;#039;;&lt;br /&gt;
    $f-&amp;gt;required = true;&lt;br /&gt;
    $inputfields-&amp;gt;add($f);&lt;br /&gt;
&lt;br /&gt;
    $f = $this-&amp;gt;modules-&amp;gt;get(&amp;#039;InputfieldSelect&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;attr(&amp;#039;name&amp;#039;, &amp;#039;color&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;label = &amp;#039;Favorite Color&amp;#039;;&lt;br /&gt;
    $f-&amp;gt;options = array(&lt;br /&gt;
      &amp;#039;red&amp;#039; =&amp;gt; &amp;#039;Red&amp;#039;,&lt;br /&gt;
      &amp;#039;green&amp;#039; =&amp;gt; &amp;#039;Green&amp;#039;,&lt;br /&gt;
      &amp;#039;blue&amp;#039; =&amp;gt; &amp;#039;Blue&amp;#039;&lt;br /&gt;
    );&lt;br /&gt;
    $inputfields-&amp;gt;add($f);&lt;br /&gt;
&lt;br /&gt;
    $f = $this-&amp;gt;modules-&amp;gt;get(&amp;#039;InputfieldInteger&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;attr(&amp;#039;name&amp;#039;, &amp;#039;age&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;label = &amp;#039;Your Age&amp;#039;;&lt;br /&gt;
    $inputfields-&amp;gt;add($f);&lt;br /&gt;
&lt;br /&gt;
    return $inputfields;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Module_schreiben&amp;diff=24851</id>
		<title>ProcessWire - Module schreiben</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Module_schreiben&amp;diff=24851"/>
		<updated>2020-11-04T21:43:54Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: /* Interessantes - Read On */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Wichtigste Resourcen&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 https://processwire.com/docs/modules/development/ - Guter Ausgangspunkt&lt;br /&gt;
 https://processwire.com/api/ref/module/ - Module API&lt;br /&gt;
 https://processwire.com/api/ref/configurable-module/ - Klasse für Konfigurierbare Module&lt;br /&gt;
 https://processwire.com/docs/modules/types/ - Welche Modultypen gibt es ?&lt;br /&gt;
 https://processwire.com/talk/topic/778-module-dependencies/ - Module die andere Module benötigen&lt;br /&gt;
 https://processwire.com/talk/forum/19-moduleplugin-development/ - Forum zum Thema Module entwickeln&lt;br /&gt;
 http://somatonic.github.io/Captain-Hook/ - Hook Cheatsheet&lt;br /&gt;
 https://processwire.com/blog/posts/new-module-configuration-options/ - Neuere Konfigurationsmöglichkeiten&lt;br /&gt;
 https://processwire.com/docs/start/api-access/ Zugriff auf ProcessWire API Variablen (wire Objekt)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039; Tutorials und Beispiele zum Einstieg &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 https://processwire.com/docs/modules/ - Introduction, Development, Hooks, Types, Pro Modules, Third Party&lt;br /&gt;
 https://github.com/ryancramerdesign/ProcessHello - Modul Skelett Beispiel für eigene Backend (Process) Module&lt;br /&gt;
 https://github.com/ryancramerdesign/FieldtypeMapMarker - Beispiel für ein Fieldtype und Inputfield Modul&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/a-beginners-introduction-to-writing-modules-in-processwire--cms-26862&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Wikiseiten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 [[ProcessWire - Module Snippets]]&lt;br /&gt;
 [[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Weitere Links&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 http://modules.pw/ (Module Creator)&lt;br /&gt;
&lt;br /&gt;
== Wo - Was ? ==&lt;br /&gt;
=== Welche Typen von Modulen gibt es ? ===&lt;br /&gt;
 https://processwire.com/docs/modules/types/&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Fieldtype&amp;#039;&amp;#039;&amp;#039;: Repräsentiert einen Datentyp. Meistens keine Public API, Handelt Daten / Datenbank - [[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Inputfield&amp;#039;&amp;#039;&amp;#039;: Sammelt User Eingaben über ein Formular im Admin Bereich. Im Gegensatz zum Fieldtype geht es hier um das UI im Backend. Das Handling der Daten liegt beim Fieldtype.&lt;br /&gt;
* [[Process Module (ProcessWire)|&amp;#039;&amp;#039;&amp;#039;Process&amp;#039;&amp;#039;&amp;#039; for creating admin processes/applications.]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Textformatter&amp;#039;&amp;#039;&amp;#039; for formatting text.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminTheme&amp;#039;&amp;#039;&amp;#039; for creating themes in the admin.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;WireMail&amp;#039;&amp;#039;&amp;#039; for modules that send email and extend the WireMail class.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tfa&amp;#039;&amp;#039;&amp;#039; for implementing a specific kind of two-factor authentication.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ImageSizerEngine&amp;#039;&amp;#039;&amp;#039; for modules that extend ImageSizerEngine for resizing images.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FileCompiler&amp;#039;&amp;#039;&amp;#039; for modules that extend FileCompilerModule for compilation of files.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FileValidator&amp;#039;&amp;#039;&amp;#039; for modules that extend FileValidatorModule for validation of files.&lt;br /&gt;
&lt;br /&gt;
=== Wie werden Felder in der Datenbank angelegt ? ===&lt;br /&gt;
Dazu nutzt man den Typ &amp;quot;Fieldtype&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Wo rendert man die Ausgabe ? ===&lt;br /&gt;
Bei Ryan Cramers Event Beispiel legt er zwei Klassen Event und EventArray an, die auch die Render Funktionen enthalten.&lt;br /&gt;
&lt;br /&gt;
=== Namenskonventionen ===&lt;br /&gt;
Ein Modulname sollte mit dem Typ den das Modul hat beginnen. Also etwa ProcessMeinAdminModul oder FieldtypeTable. ProcessWire listet das Modul dann in der Entsprechenden Kategorie auf. Wenn man etwas anderes nimmt z.B. LoginRegister dann kommt das Modul unter der neuen Rubrik &amp;quot;Login&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurierbare Module ===&lt;br /&gt;
Das geht seit 2.5.5 mittlerweile sehr einfach mit den neuen configuration-options.&lt;br /&gt;
 https://processwire.com/blog/posts/new-module-configuration-options/&lt;br /&gt;
 [[ProcessWire - Konfigurierbare Module]]&lt;br /&gt;
&lt;br /&gt;
== Spezielle Funktionen in Modulen ==&lt;br /&gt;
&lt;br /&gt;
=== Modulinformation ===&lt;br /&gt;
Das Modul stellt Infos zur Verfügung und nutzt dafür eine von 3 Methoden:&lt;br /&gt;
    getModuleInfo() static method in your module class that returns an array.&lt;br /&gt;
    YourModuleClass.info.php file that populates an $info array.&lt;br /&gt;
    YourModuleClass.info.json file that contains an info object.&lt;br /&gt;
&lt;br /&gt;
Hier werden title, version, summary und weitere Daten hinterlegt. Hier kann man auch angeben ob ein Modul ein Autoload Modul ist.&lt;br /&gt;
&lt;br /&gt;
 https://processwire.com/api/ref/module/&lt;br /&gt;
&lt;br /&gt;
=== init ===&lt;br /&gt;
 public function init(){}&lt;br /&gt;
Initialisiert das Modul. ProcessWire ruft diese Funktion auf, wenn das Modul geladen ist. Bei Autoload Modulen wird es aufgerufen wenn die ProcessWire API bereit ist. Daher ist es ein guter Ort um Hooks einzubinden.&lt;br /&gt;
&lt;br /&gt;
=== ready ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  public function ready() {&lt;br /&gt;
    if($this-&amp;gt;page-&amp;gt;template == &amp;#039;admin&amp;#039;) {&lt;br /&gt;
      $this-&amp;gt;message($this-&amp;gt;hi());&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird in autoload Modulen aufgerufen wenn die API bereit ist. Nützlich für Hooks:&lt;br /&gt;
&lt;br /&gt;
=== execute ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	/**&lt;br /&gt;
	 * This function is executed when a page with your Process assigned is accessed. &lt;br /&gt;
 	 *&lt;br /&gt;
	 * This can be seen as your main or index function. You&amp;#039;ll probably want to replace&lt;br /&gt;
	 * everything in this function. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___execute() {&lt;br /&gt;
		// greetingType and greeting are automatically populated to this module&lt;br /&gt;
		// and they were defined in ProcessHello.config.php&lt;br /&gt;
		if($this-&amp;gt;greetingType == &amp;#039;message&amp;#039;) {&lt;br /&gt;
			$this-&amp;gt;message($this-&amp;gt;greeting); &lt;br /&gt;
		} else if($this-&amp;gt;greetingType == &amp;#039;warning&amp;#039;) {&lt;br /&gt;
			$this-&amp;gt;warning($this-&amp;gt;greeting); &lt;br /&gt;
		} else {&lt;br /&gt;
			$this-&amp;gt;error($this-&amp;gt;greeting); &lt;br /&gt;
		}&lt;br /&gt;
		// generate some navigation&lt;br /&gt;
		$out = 	&amp;quot;&lt;br /&gt;
			&amp;lt;h2&amp;gt;$this-&amp;gt;greeting&amp;lt;/h2&amp;gt;&lt;br /&gt;
			&amp;lt;dl class=&amp;#039;nav&amp;#039;&amp;gt;&lt;br /&gt;
				&amp;lt;dt&amp;gt;&amp;lt;a href=&amp;#039;./something/&amp;#039;&amp;gt;Do Something&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;&lt;br /&gt;
				&amp;lt;dd&amp;gt;Runs the executeSomething() function.&amp;lt;/dd&amp;gt;&lt;br /&gt;
			&amp;lt;/dl&amp;gt;&lt;br /&gt;
			&amp;quot;;&lt;br /&gt;
		return $out;&lt;br /&gt;
	}	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== executeSomething ===&lt;br /&gt;
Ruft man eine Unterseite des Moduls auf kann man eine eigene execute Funktion nutzen&lt;br /&gt;
___executeSlug wobei Slug für den Url Slug steht. Heißt der slug /field/ dann wird executeField() aufgerufen, falls diese Funktion existiert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	/**&lt;br /&gt;
	 * Called when the URL is this module&amp;#039;s page URL + &amp;quot;/something/&amp;quot;&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___executeSomething() {&lt;br /&gt;
		// set a new headline, replacing the one used by our page&lt;br /&gt;
		// this is optional as PW will auto-generate a headline &lt;br /&gt;
		$this-&amp;gt;headline(&amp;#039;This is something!&amp;#039;); &lt;br /&gt;
		// add a breadcrumb that returns to our main page &lt;br /&gt;
		// this is optional as PW will auto-generate breadcrumbs&lt;br /&gt;
		$this-&amp;gt;breadcrumb(&amp;#039;../&amp;#039;, &amp;#039;Hello&amp;#039;); &lt;br /&gt;
		$out = 	&amp;quot;&lt;br /&gt;
			&amp;lt;h2&amp;gt;Not much to to see here&amp;lt;/h2&amp;gt;&lt;br /&gt;
			&amp;lt;p&amp;gt;&amp;lt;a href=&amp;#039;../&amp;#039;&amp;gt;Go Back&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
			&amp;quot;;&lt;br /&gt;
		return $out; &lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== install &amp;amp; uninstall ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
	 * Called only when your module is installed&lt;br /&gt;
	 *&lt;br /&gt;
	 * If you don&amp;#039;t need anything here, you can simply remove this method. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___install() {&lt;br /&gt;
		parent::___install(); // always remember to call parent method&lt;br /&gt;
	}&lt;br /&gt;
	/**&lt;br /&gt;
	 * Called only when your module is uninstalled&lt;br /&gt;
	 *&lt;br /&gt;
	 * This should return the site to the same state it was in before the module was installed. &lt;br /&gt;
	 *&lt;br /&gt;
	 * If you don&amp;#039;t need anything here, you can simply remove this method. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___uninstall() {&lt;br /&gt;
		parent::___uninstall(); // always remember to call parent method&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vererbung und Eigenschaften in Modulen ==&lt;br /&gt;
Modules are not different from PHP classes.&lt;br /&gt;
&lt;br /&gt;
To change the properties of MyModule class from within MyOtherModule class, you can either:&lt;br /&gt;
&lt;br /&gt;
#Make MyOtherModule class extend MyModule. It will thus inherit MyModule&amp;#039;s public and protected properties and methods&lt;br /&gt;
#Make the properties firstName and lastName configurable by passing them as parameters/arguments in MyModule&amp;#039;s constructor method.&lt;br /&gt;
&lt;br /&gt;
== Autoload Module und Hooks ==&lt;br /&gt;
Autoload werden automatisch geladen müssen also nicht in einem Template o.ä. gestartet werden. Daher bieten sie sich an um die Funktionalität von ProcessWire zu erweitern. Als Werkzeug dafür dienen Hooks. Mit Hooks kann man an vielen Stellen den Rendering Process der Seiten beeinflussen. Außerdem kann man für eigene Module ebenfalls Hooks bereitstellen. &lt;br /&gt;
&lt;br /&gt;
=== Hooks ===&lt;br /&gt;
 https://processwire.com/docs/modules/hooks/&lt;br /&gt;
Hooks sind ein mächtiges Werkzeug. Sie geben einem die Möglichkeit an vielen Stellen &amp;quot;einzuhaken&amp;quot; und Funktionalität einzubauen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, function($event) {&lt;br /&gt;
    $event-&amp;gt;return .= &amp;#039;&amp;lt;p&amp;gt;Hallo&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Schreibt am Ende Jeder Seite ein &amp;quot;Hallo&amp;quot;. Das $event Objekt ist ein [https://processwire.com/api/ref/hook-event/ HookEvent]. Im Beispiel fügen wir einfach etwas Markup hinzu. Über $event-&amp;gt;arguments() kann man aber auf ale Argumente zugreifen.&lt;br /&gt;
&lt;br /&gt;
Das gleiche aber nicht mit anonymer Funktion:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  // add hook after Page::render() and make it call the &amp;quot;test&amp;quot; method of $this module&lt;br /&gt;
  $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, $this, &amp;#039;test&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public function test($event) {&lt;br /&gt;
  // modify the return value of Page::render() to include the following:&lt;br /&gt;
  $event-&amp;gt;return .= &amp;#039;&amp;lt;p&amp;gt;Hallo&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hooks zum erweitern von existierenden Klassen nutzen ===&lt;br /&gt;
Mit Hooks kann man in vorhandene Klassen einhaken. Z.B. läßt sich das Page Objekt erweitern.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  $this-&amp;gt;addHook(&amp;#039;Page::summarize&amp;#039;, $this, &amp;#039;summarize&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
public function summarize($event) {&lt;br /&gt;
  $page = $event-&amp;gt;object; // the $event-&amp;gt;object represents the object hooked (Page)&lt;br /&gt;
  $maxlen = $event-&amp;gt;arguments(0); // first argument is the optional max length&lt;br /&gt;
  if(!$maxlen) $maxlen = 200; // if no $maxlen was present, we&amp;#039;ll use a default of 200&lt;br /&gt;
  $summary = $this-&amp;gt;sanitizer-&amp;gt;truncate($page-&amp;gt;body, $maxlen); // use sanitizer truncate method to create a summary&lt;br /&gt;
  $event-&amp;gt;return = $summary; // populate $summary to $event-&amp;gt;return, the return value&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So kann man ganz einfach eine Zusammenfassung aller Kindseiten in einem Template rendern:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
foreach($page-&amp;gt;children as $item) {&lt;br /&gt;
  $summary = $item-&amp;gt;summarize(150);&lt;br /&gt;
  echo &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;$item-&amp;gt;url&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;$summary&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Autoload Module nur im Admin Bereich laden ===&lt;br /&gt;
&lt;br /&gt;
 &amp;#039;autoload&amp;#039; =&amp;gt; &amp;#039;template=admin&amp;#039; &lt;br /&gt;
statt&lt;br /&gt;
 &amp;#039;autoload&amp;#039; =&amp;gt; true&lt;br /&gt;
&lt;br /&gt;
=== Hook Beispiele ===&lt;br /&gt;
Hook am Ende des Renderings&lt;br /&gt;
 $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, function($event) {...});&lt;br /&gt;
Füge eine Funktion &amp;quot;summarize&amp;quot; zum Page Objekt hinzu.&lt;br /&gt;
 $this-&amp;gt;addHook(&amp;#039;Page::summarize&amp;#039;, $this, &amp;#039;summarize&amp;#039;);&lt;br /&gt;
Hook auf eine einzelne Instanz (hier pages Objekt)&lt;br /&gt;
 $this-&amp;gt;pages-&amp;gt;addHookAfter(&amp;#039;saved&amp;#039;, function($event){...});&lt;br /&gt;
 $this-&amp;gt;addHook(&amp;#039;Page::method&amp;#039;, ...) // Spricht ALLE Instanzen an - Regelfall&lt;br /&gt;
 $page-&amp;gt;addHook(&amp;#039;method&amp;#039;, ...) // Spricht nur die EINE Instanz der Seite an.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Module Dependencies - voneinander abhängige Module ==&lt;br /&gt;
&lt;br /&gt;
 https://processwire.com/talk/topic/778-module-dependencies/&lt;br /&gt;
Wenn ein Modul nicht ohne ein anderes funktioniert spricht man von Module Dependency. In solchen Fällen kann man in der Modul Info angeben In vielen Fällen besteht ein Modul unter der Haube aus mehreren Einzelmodulen.&lt;br /&gt;
&lt;br /&gt;
Um ProcessWire mitzuteilen dass ein Modul benötigt wird gibt man es in der Moduldefinition an:&lt;br /&gt;
 &amp;#039;requires&amp;#039; =&amp;gt; &amp;quot;LazyCron&amp;quot;  // added this line&lt;br /&gt;
oder auch mehrere als Array&lt;br /&gt;
 &amp;#039;requires&amp;#039; =&amp;gt; array(&amp;quot;LazyCron&amp;quot;, &amp;quot;AdminBar&amp;quot;)  // added this line&lt;br /&gt;
&lt;br /&gt;
ProcessWire kann auch dafür sorgen, dass ein Modul andere &amp;quot;Kindmodule&amp;quot; gleich mitinstalliert bzw. deinstalliert wenn es nicht mehr benötigt wird. Dazu gibt man dem Modul noch die &amp;#039;install&amp;#039; dependency mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
public static function getModuleInfo() {&lt;br /&gt;
   return array(&lt;br /&gt;
       &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Log Master&amp;#039;,&lt;br /&gt;
       &amp;#039;version&amp;#039; =&amp;gt; 101,&lt;br /&gt;
       &amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Lumberjack Bob&amp;#039;,&lt;br /&gt;
       &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Log all actions on your site&amp;#039;,&lt;br /&gt;
       &amp;#039;requires&amp;#039; =&amp;gt; &amp;#039;LazyCron&amp;#039;, &lt;br /&gt;
       &amp;#039;installs&amp;#039; =&amp;gt; &amp;#039;ProcessLogMaster&amp;#039;  // added this line&lt;br /&gt;
       ); &lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProcessWire sieht dann eine Kindabhängigkeit zu diesem Modul und handelt auch das Deinstallieren, wenn das Elternmodul deinstalliert wird.&lt;br /&gt;
&lt;br /&gt;
== CSS und JavaScript in Modulen ==&lt;br /&gt;
Bei Process Modulen möchte man für das Styling etc. im Backend oft CSS und JS Dateien hinzufügen.&lt;br /&gt;
&lt;br /&gt;
Einfach Eine Datei MeinModul.css und / oder MeinModul.js hinzufügen. JQuery ist im Admin bereits geladen daher kann eine MeinModul.js Starter Datei so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This JS file is only loaded when the ProcessHello module is run&lt;br /&gt;
 *&lt;br /&gt;
 * You should delete it if you have no javascript to add.&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
$(document).ready(function() {&lt;br /&gt;
	// do something&lt;br /&gt;
}); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Frontend Rendering Module ===&lt;br /&gt;
A bit old but working&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * FrontEndRender&lt;br /&gt;
 *&lt;br /&gt;
 * Author: Ben Byford&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2010 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class FrontEndRender extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;FrontEndRender&amp;#039;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 0.1,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;Outputs html and static variables to frontend&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ben Byford&amp;#039;,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://github.com/benbyford/PW-starter-modules&amp;#039;&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// protected variable only accessable within module&lt;br /&gt;
	protected $name = &amp;#039;Ben&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* render function to be called in PW template like this:&lt;br /&gt;
	* $FrontEndRender = $modules-&amp;gt;getModule(&amp;#039;FrontEndRender&amp;#039;);&lt;br /&gt;
	* echo &amp;#039;&amp;lt;h1&amp;gt;&amp;#039; . $FrontEndRender-&amp;gt;render() . &amp;#039;&amp;lt;/h1&amp;gt;&amp;#039;;&lt;br /&gt;
	*&lt;br /&gt;
	*/&lt;br /&gt;
	public function render(){&lt;br /&gt;
		return &amp;quot;Hello &amp;quot; . $this-&amp;gt;name;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Hello World Modul ===&lt;br /&gt;
Beispiel Modul mit Hooks (liegt immer in der Standardinstallation)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * ProcessWire &amp;#039;Hello world&amp;#039; demonstration module&lt;br /&gt;
 *&lt;br /&gt;
 * Demonstrates the Module interface and how to add hooks.&lt;br /&gt;
 * &lt;br /&gt;
 * See README file for further links regarding module development.&lt;br /&gt;
 * &lt;br /&gt;
 * This file is licensed under the MIT license&lt;br /&gt;
 * https://processwire.com/about/license/mit/&lt;br /&gt;
 * &lt;br /&gt;
 * ProcessWire 3.x, Copyright 2016 by Ryan Cramer&lt;br /&gt;
 * https://processwire.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class Helloworld extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * getModuleInfo is a module required by all modules to tell ProcessWire about them&lt;br /&gt;
	 *&lt;br /&gt;
	 * @return array&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
&lt;br /&gt;
		return array(&lt;br /&gt;
&lt;br /&gt;
			// The module&amp;#039;s title, typically a little more descriptive than the class name&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello World&amp;#039;, &lt;br /&gt;
&lt;br /&gt;
			// version number &lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 3, &lt;br /&gt;
&lt;br /&gt;
			// summary is brief description of what this module is&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;An example module used for demonstration purposes.&amp;#039;,&lt;br /&gt;
			&lt;br /&gt;
			// Optional URL to more information about the module&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://processwire.com&amp;#039;,&lt;br /&gt;
&lt;br /&gt;
			// singular=true: indicates that only one instance of the module is allowed.&lt;br /&gt;
			// This is usually what you want for modules that attach hooks. &lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true, &lt;br /&gt;
&lt;br /&gt;
			// autoload=true: indicates the module should be started with ProcessWire.&lt;br /&gt;
			// This is necessary for any modules that attach runtime hooks, otherwise those&lt;br /&gt;
			// hooks won&amp;#039;t get attached unless some other code calls the module on it&amp;#039;s own.&lt;br /&gt;
			// Note that autoload modules are almost always also &amp;#039;singular&amp;#039; (seen above).&lt;br /&gt;
			&amp;#039;autoload&amp;#039; =&amp;gt; true, &lt;br /&gt;
		&lt;br /&gt;
			// Optional font-awesome icon name, minus the &amp;#039;fa-&amp;#039; part&lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;smile-o&amp;#039;, &lt;br /&gt;
			);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Initialize the module&lt;br /&gt;
	 *&lt;br /&gt;
	 * ProcessWire calls this when the module is loaded. For &amp;#039;autoload&amp;#039; modules, this will be called&lt;br /&gt;
	 * when ProcessWire&amp;#039;s API is ready. As a result, this is a good place to attach hooks. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function init() {&lt;br /&gt;
&lt;br /&gt;
		// add a hook after the $pages-&amp;gt;save, to issue a notice every time a page is saved&lt;br /&gt;
		$this-&amp;gt;pages-&amp;gt;addHookAfter(&amp;#039;save&amp;#039;, $this, &amp;#039;example1&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a hook after each page is rendered and modify the output&lt;br /&gt;
		$this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, $this, &amp;#039;example2&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a &amp;#039;hello&amp;#039; method to every page that returns &amp;quot;Hello World&amp;quot;&lt;br /&gt;
		// use &amp;quot;echo $page-&amp;gt;hello();&amp;quot; in your template file to display output&lt;br /&gt;
		$this-&amp;gt;addHook(&amp;#039;Page::hello&amp;#039;, $this, &amp;#039;example3&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a &amp;#039;hello_world&amp;#039; property to every page that returns &amp;quot;Hello [user]&amp;quot;&lt;br /&gt;
		// use &amp;quot;echo $page-&amp;gt;hello_world;&amp;quot; in your template file to display output&lt;br /&gt;
		$this-&amp;gt;addHookProperty(&amp;#039;Page::hello_world&amp;#039;, $this, &amp;#039;example4&amp;#039;); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example1 hooks into the pages-&amp;gt;save method and displays a notice every time a page is saved&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example1($event) {&lt;br /&gt;
		/** @var Page $page */&lt;br /&gt;
		$page = $event-&amp;gt;arguments[0]; &lt;br /&gt;
		$this-&amp;gt;message(&amp;quot;Hello World! You saved {$page-&amp;gt;path}.&amp;quot;); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example2 hooks into every page after it&amp;#039;s rendered and adds &amp;quot;Hello World&amp;quot; text at the bottom&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example2($event) {&lt;br /&gt;
&lt;br /&gt;
		/** @var Page $page */&lt;br /&gt;
		$page = $event-&amp;gt;object; &lt;br /&gt;
&lt;br /&gt;
		// don&amp;#039;t add this to the admin pages&lt;br /&gt;
		if($page-&amp;gt;template == &amp;#039;admin&amp;#039;) return;&lt;br /&gt;
&lt;br /&gt;
		// add a &amp;quot;Hello World&amp;quot; paragraph right before the closing body tag&lt;br /&gt;
		$event-&amp;gt;return = str_replace(&amp;quot;&amp;lt;/body&amp;gt;&amp;quot;, &amp;quot;&amp;lt;p&amp;gt;Hello World!&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;quot;, $event-&amp;gt;return); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example3 adds a &amp;#039;hello&amp;#039; method (not property) to every page that simply returns &amp;quot;Hello World&amp;quot;&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example3($event) {&lt;br /&gt;
		$event-&amp;gt;return = &amp;quot;Hello World&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example 4 adds a &amp;#039;hello_world&amp;#039; property (not method) to every page that returns &amp;quot;Hello [user]&amp;quot;&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example4($event) {&lt;br /&gt;
		$event-&amp;gt;return = &amp;quot;Hello &amp;quot; . $this-&amp;gt;user-&amp;gt;name; &lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Admin Bereich mit eigener Funktionalität erweitern (Modul)===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
* ProcessSimpleAdminPage&lt;br /&gt;
*&lt;br /&gt;
* @author Ben Byford&lt;br /&gt;
* http://www.benbyford.com&lt;br /&gt;
*&lt;br /&gt;
* @see http://www.processwire.com&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
class ProcessSimpleAdminPage extends Process {&lt;br /&gt;
&lt;br /&gt;
    public static function getModuleInfo() {&lt;br /&gt;
        return array(&lt;br /&gt;
            &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Process Simple Admin Page&amp;#039;,&lt;br /&gt;
            &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Simple Process module that adds new admin page with&amp;#039;,&lt;br /&gt;
            &amp;#039;version&amp;#039; =&amp;gt; 001,&lt;br /&gt;
&lt;br /&gt;
            // Modules that extend Process may specify a &amp;#039;page&amp;#039; attribute in the&lt;br /&gt;
            // getModuleInfo(), this page will automatically be given the module&lt;br /&gt;
            // process when added to teh pagetree.&lt;br /&gt;
&lt;br /&gt;
            // I have exampled but commented out the &amp;#039;page&amp;#039; settings below&lt;br /&gt;
            // so that I can show how one might add a page to install() and&lt;br /&gt;
            // uninstall() in this and other modules (that might not extend&lt;br /&gt;
            // Process)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        // 	&amp;#039;page&amp;#039; =&amp;gt; array(&lt;br /&gt;
        // 		&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;site-config&amp;#039;,&lt;br /&gt;
        // 		&amp;#039;parent&amp;#039; =&amp;gt; &amp;#039;admin&amp;#039;,&lt;br /&gt;
        // 		&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Site Config&amp;#039;&lt;br /&gt;
        // 	   )&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function execute() {&lt;br /&gt;
        return &amp;#039;&lt;br /&gt;
            &amp;lt;h2&amp;gt;Edit the text here in the module&amp;lt;/h2&amp;gt;&lt;br /&gt;
            &amp;lt;p&amp;gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mattis eros vitae metus sodales eget suscipit purus rhoncus. Proin ultrices gravida dolor, non porttitor enim interdum vitae. Integer feugiat lacinia tincidunt. Nulla laoreet tristique tristique. Sed elementum justo a nisl elementum sit amet accumsan nisi tempor. Nulla quis eros et massa dignissim imperdiet a vitae purus.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Donec scelerisque pulvinar sem eu lobortis. Maecenas turpis ipsum, tempus dictum pharetra eu, consectetur vitae arcu. Fusce orci mauris, semper at tempus quis, volutpat molestie tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed quam tortor, tincidunt sed semper lacinia, scelerisque dapibus quam. Morbi at nisi luctus lacus auctor ultrices eu eu leo.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Praesent faucibus purus id felis tincidunt dignissim. Sed sit amet ligula mi, eget semper dui. Proin consectetur gravida massa, nec luctus purus hendrerit in. Etiam volutpat, elit non venenatis suscipit, libero neque consectetur diam, id rutrum magna odio ac ligula. Maecenas sollicitudin congue neque fermentum vestibulum. Morbi nec leo nisi. Donec at nisl odio, et porta ligula.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Sed quis arcu nisi, ac tempor augue. Praesent non elit libero, a ullamcorper lorem. Curabitur porta odio eu nunc ultricies interdum id nec risus. Donec nibh nibh, porta eget vehicula ac, aliquet eget ante. Phasellus eget lorem eu eros eleifend ultrices. Cras sit amet neque sit amet nibh fringilla cursus ut id mauris. Praesent quis nunc justo, sed suscipit lectus. Phasellus eget ultrices risus. Curabitur eu semper est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut suscipit, nisl ut imperdiet eleifend, turpis arcu placerat tortor, nec laoreet lacus neque ac tellus. Aenean ac lacus justo, quis ultricies nisi.&amp;lt;/p&amp;gt;&lt;br /&gt;
            &amp;#039;;&lt;br /&gt;
    }&lt;br /&gt;
    public function install(){&lt;br /&gt;
&lt;br /&gt;
        // create new page to add to CMS&lt;br /&gt;
		$page = new Page();&lt;br /&gt;
&lt;br /&gt;
        // add page attributes&lt;br /&gt;
        $page-&amp;gt;template = &amp;quot;admin&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;name = &amp;quot;cms-faq&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;title = &amp;quot;CMS FAQ&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;save();&lt;br /&gt;
&lt;br /&gt;
        // set this module as the page process, this allows us to display the above&lt;br /&gt;
        $page-&amp;gt;process = &amp;#039;ProcessSimpleAdminPage&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
        // get admin page and set as page parent&lt;br /&gt;
        $admin = $this-&amp;gt;pages-&amp;gt;get(&amp;quot;id=2&amp;quot;);&lt;br /&gt;
        $page-&amp;gt;parent = $admin;&lt;br /&gt;
&lt;br /&gt;
        // save page&lt;br /&gt;
        $page-&amp;gt;save();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function uninstall(){&lt;br /&gt;
&lt;br /&gt;
        // delete created page&lt;br /&gt;
        $page = $this-&amp;gt;pages-&amp;gt;get(&amp;quot;name=cms-faq&amp;quot;);&lt;br /&gt;
        if(count($page)) $this-&amp;gt;pages-&amp;gt;delete($page, true);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Textformatter Modul ===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * TextformatterFindReplace&lt;br /&gt;
 *&lt;br /&gt;
 * Author: Ben Byford&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2010 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class TextformatterFindReplace extends Textformatter implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;TextformatterFindReplace&amp;#039;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 0.1,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;Finds and replaces any instance of config input to config output&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ben Byford&amp;#039;,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://github.com/benbyford/PW-starter-modules&amp;#039;&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
     * Find and Replace the input string&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $str The block of text to parse&lt;br /&gt;
     *&lt;br /&gt;
     * The incoming string is replaced with the formatted version of itself.&lt;br /&gt;
	 **/&lt;br /&gt;
&lt;br /&gt;
	public function format(&amp;amp;$str) {&lt;br /&gt;
		$find = $this-&amp;gt;findStr;&lt;br /&gt;
		$str = preg_replace_callback($find, array($this,&amp;quot;replace&amp;quot;), $str);&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// adding three underscores to a function allows other modules to hook it&lt;br /&gt;
	public function ___replace($match) {&lt;br /&gt;
		return $this-&amp;gt;replaceStr;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Admin Funktionalität: Countdown zum Seitenveröffentlichen ===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&lt;br /&gt;
The module PageDeferredPublish, on clicking one of the &amp;#039;&amp;#039;&amp;#039;Publish Later buttons&amp;#039;&amp;#039;&amp;#039;, sets LazyCron to check that page’s countdown every minute and publishes the page when its countdown reaches 0. This means I can publish a page approximately 24 hours in advance (obviously the checking interval and delay time can be changed to your requirements).&lt;br /&gt;
&lt;br /&gt;
I did this by:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Creating two fields&amp;#039;&amp;#039;&amp;#039; within my install() function: a checkbox field to set to true when a button is checked to indicate the page should countdown, and a countdown field to store the count in seconds for that specific page.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Adding hooks&amp;#039;&amp;#039;&amp;#039; to both &amp;#039;&amp;#039;ProcessPageEdit::buildForm&amp;#039;&amp;#039; and &amp;#039;&amp;#039;ProcessPageListActions::getExtraActions&amp;#039;&amp;#039; enabling me to add the two buttons.&lt;br /&gt;
&lt;br /&gt;
Checking to see if one of the buttons was clicked with my &amp;#039;&amp;#039;&amp;#039;ready() function&amp;#039;&amp;#039;&amp;#039; then setting the corresponding page’s checkbox to true.&lt;br /&gt;
&lt;br /&gt;
Using a &amp;#039;&amp;#039;&amp;#039;LazyCron hook function&amp;#039;&amp;#039;&amp;#039; to check all pages that are unpublished for true checkboxes and then comparing the seconds field to see if the page needs publishing. If not then deduct the elapsed time in seconds.&lt;br /&gt;
&lt;br /&gt;
The result is a &amp;#039;&amp;#039;&amp;#039;module that has settings&amp;#039;&amp;#039;&amp;#039; (the time interval to check and publish at a later time), &amp;#039;&amp;#039;&amp;#039;hooks into the admin&amp;#039;&amp;#039;&amp;#039; using buttons and fields, and enables us to &amp;#039;&amp;#039;&amp;#039;use other modules installe&amp;#039;&amp;#039;&amp;#039;d in PW (i.e. LazyCron).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * DeferredPublish (0.0.1)&lt;br /&gt;
 * DeferredPublish publishes a page after a defined amount of time has elapsed using lazycron.&lt;br /&gt;
 *&lt;br /&gt;
 * @author Ben Byford&lt;br /&gt;
 * http://www.benbyford.com&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2011 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class PageDeferredPublish extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;quot;PageDeferredPublish&amp;quot;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; &amp;quot;0.0.1&amp;quot;,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;PageDeferredPublish&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;quot;Ben Byford&amp;quot;,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;quot;https://github.com/benbyford/PW-intermediate-modules&amp;quot;,&lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;quot;clock-o&amp;quot;,&lt;br /&gt;
			&amp;#039;autoload&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;requires&amp;#039; =&amp;gt; &amp;quot;LazyCron&amp;quot;,&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	private $postPubLater 	= null;&lt;br /&gt;
	private $pageID 		= null;&lt;br /&gt;
	private $pagePubLater 	= null;&lt;br /&gt;
	private $currentPage	= null;&lt;br /&gt;
&lt;br /&gt;
	private $submitName 	= &amp;#039;pdp_pub_later_submit&amp;#039;;&lt;br /&gt;
	private $listPageName	= &amp;#039;pdp_pub_later_list&amp;#039;;&lt;br /&gt;
	private $fieldName 		= &amp;#039;pdp_pub_later&amp;#039;;&lt;br /&gt;
	private $checkboxName	= &amp;#039;pdp_pub_later_check&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	private $defaultInterval = &amp;#039;everyMinute&amp;#039;;&lt;br /&gt;
	private $defaultTime 	= 86400;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	public function install(){&lt;br /&gt;
		// add new fields needed for module&lt;br /&gt;
		$this-&amp;gt;installFields();&lt;br /&gt;
	}&lt;br /&gt;
	public function uninstall(){&lt;br /&gt;
		// uninstall fields&lt;br /&gt;
		$this-&amp;gt;uninstallFields();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// initialize the hook in your AutoLoad module&lt;br /&gt;
	public function init() {&lt;br /&gt;
&lt;br /&gt;
		// get defaults from module setting in CMS&lt;br /&gt;
		$this-&amp;gt;defaultTime = $this-&amp;gt;pub_after;&lt;br /&gt;
		$this-&amp;gt;defaultInterval = $this-&amp;gt;cron_check;&lt;br /&gt;
&lt;br /&gt;
		// get admin URL&lt;br /&gt;
		$this-&amp;gt;adminUrl = $this-&amp;gt;wire(&amp;#039;config&amp;#039;)-&amp;gt;urls-&amp;gt;admin;&lt;br /&gt;
&lt;br /&gt;
		// add hooks to CRON, PageList, PageEdit&lt;br /&gt;
	    $this-&amp;gt;addHookAfter(&amp;quot;LazyCron::{$this-&amp;gt;defaultInterval}&amp;quot;, $this, &amp;#039;publishDefferedPages&amp;#039;);&lt;br /&gt;
		$this-&amp;gt;addHook(&amp;quot;ProcessPageListActions::getExtraActions&amp;quot;, $this, &amp;#039;hookPageListActions&amp;#039;);&lt;br /&gt;
		$this-&amp;gt;addHookAfter(&amp;quot;ProcessPageEdit::buildForm&amp;quot;, $this, &amp;quot;editForm&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function ready() {&lt;br /&gt;
&lt;br /&gt;
		// if list button clicked then grab id&lt;br /&gt;
		$this-&amp;gt;pagePubLater = $this-&amp;gt;input-&amp;gt;get($this-&amp;gt;listPageName);&lt;br /&gt;
		$this-&amp;gt;pageID = $this-&amp;gt;input-&amp;gt;id;&lt;br /&gt;
&lt;br /&gt;
		// get page&lt;br /&gt;
		$this-&amp;gt;currentPage = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;pageID);&lt;br /&gt;
&lt;br /&gt;
		// if pagelist pub later submit button clicked&lt;br /&gt;
		if($this-&amp;gt;pagePubLater){&lt;br /&gt;
			$this-&amp;gt;message(&amp;quot;Page {$this-&amp;gt;currentPage-&amp;gt;name} deffered for publish.&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if page edit submit button clicked&lt;br /&gt;
		$this-&amp;gt;postPubLater = $this-&amp;gt;input-&amp;gt;post($this-&amp;gt;submitName);&lt;br /&gt;
		if($this-&amp;gt;postPubLater){&lt;br /&gt;
			$this-&amp;gt;message(&amp;quot;Page {$this-&amp;gt;currentPage-&amp;gt;name} deffered for publish.&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if either deffered publish sumbit found then publish page later&lt;br /&gt;
		if($this-&amp;gt;pagePubLater || $this-&amp;gt;postPubLater){&lt;br /&gt;
			$this-&amp;gt;publishLater();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	*	Hook: ProcessPageEdit::buildForm&lt;br /&gt;
	*&lt;br /&gt;
	*	add Publish Later button to edit page if not yet published&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___editForm(HookEvent $form) {&lt;br /&gt;
&lt;br /&gt;
		// get the InputFieldForm object from the event (return value of buildForm())&lt;br /&gt;
		$form = $form-&amp;gt;return;&lt;br /&gt;
&lt;br /&gt;
		$page = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;input-&amp;gt;get-&amp;gt;id);&lt;br /&gt;
		$check = $page-&amp;gt;get($this-&amp;gt;checkboxName);&lt;br /&gt;
&lt;br /&gt;
		// check if publish button available and therfore unpublished&lt;br /&gt;
		$target = $form-&amp;gt;get(&amp;#039;submit_publish&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
		if($target &amp;amp;&amp;amp; $check == false){&lt;br /&gt;
&lt;br /&gt;
			// get InputfieldText module&lt;br /&gt;
			$submit2 = $this-&amp;gt;modules-&amp;gt;get(&amp;#039;InputfieldSubmit&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;name&amp;#039;, $this-&amp;gt;submitName);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;id&amp;#039;, &amp;#039;publish_later&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;class&amp;#039;, &amp;#039;ui-button ui-widget ui-corner-all head_button_clone ui-state-default ui-priority-secondary&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;value&amp;#039;, &amp;#039;Publish Later&amp;#039;); // Button: save unpublished&lt;br /&gt;
&lt;br /&gt;
			// get form element save and place before&lt;br /&gt;
			$target = $form-&amp;gt;get(&amp;#039;submit_save&amp;#039;);&lt;br /&gt;
			$form-&amp;gt;insertBefore($submit2, $target);&lt;br /&gt;
&lt;br /&gt;
			$form-&amp;gt;return = $form;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function ___hookPageListActions(HookEvent $event) {&lt;br /&gt;
&lt;br /&gt;
		// get current page&lt;br /&gt;
		$page = $event-&amp;gt;arguments[0];&lt;br /&gt;
&lt;br /&gt;
		// check to see if page is published&lt;br /&gt;
		$pagePub = $page-&amp;gt;is(Page::statusUnpublished);&lt;br /&gt;
&lt;br /&gt;
		// check to see if page template has deffered field&lt;br /&gt;
		$pageHasDefferField = $page-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
&lt;br /&gt;
		$actions = array();&lt;br /&gt;
&lt;br /&gt;
		// don&amp;#039;t get homepage or pages that are already published or are being deffered for publish&lt;br /&gt;
		if($page-&amp;gt;id &amp;gt; 1 &amp;amp;&amp;amp; $pagePub == &amp;quot;published&amp;quot; &amp;amp;&amp;amp; !is_null($pageHasDefferField) &amp;amp;&amp;amp; $page-&amp;gt;get($this-&amp;gt;checkboxName) == false) {&lt;br /&gt;
&lt;br /&gt;
			$actions[&amp;#039;publish_later&amp;#039;] = array(&lt;br /&gt;
				&amp;#039;cn&amp;#039;   =&amp;gt; &amp;#039;PublishLater&amp;#039;,&lt;br /&gt;
				&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;pub later&amp;#039;,&lt;br /&gt;
				&amp;#039;url&amp;#039;  =&amp;gt; &amp;quot;{$this-&amp;gt;adminUrl}?{$this-&amp;gt;listPageName}=1&amp;amp;id={$page-&amp;gt;id}&amp;quot;,&lt;br /&gt;
			);&lt;br /&gt;
		}&lt;br /&gt;
		if(count($actions)) $event-&amp;gt;return = $actions + $event-&amp;gt;return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Publish Page on cron job&lt;br /&gt;
	*&lt;br /&gt;
	* Gets deffered page and publishes&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___publish($page) {&lt;br /&gt;
		$page-&amp;gt;removeStatus(Page::statusUnpublished);&lt;br /&gt;
		$page-&amp;gt;removeStatus(Page::statusHidden);&lt;br /&gt;
		$page-&amp;gt;Save();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Main publish later function&lt;br /&gt;
	*&lt;br /&gt;
	* Gets deffered page and sets fields to be checked be lazy cron&lt;br /&gt;
	*/&lt;br /&gt;
	private function ___publishLater() {&lt;br /&gt;
&lt;br /&gt;
		// get page&lt;br /&gt;
		$page = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;pageID);&lt;br /&gt;
&lt;br /&gt;
		// set output formatting to false&lt;br /&gt;
		$page-&amp;gt;of(false);&lt;br /&gt;
&lt;br /&gt;
		//  set field time to settings default time and checkbox to true&lt;br /&gt;
		$page-&amp;gt;set($this-&amp;gt;checkboxName, true);&lt;br /&gt;
		$page-&amp;gt;set($this-&amp;gt;fieldName, $this-&amp;gt;defaultTime);&lt;br /&gt;
&lt;br /&gt;
		// save page&lt;br /&gt;
		$page-&amp;gt;save();&lt;br /&gt;
		$page-&amp;gt;of(true);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Lazy Cron hook function&lt;br /&gt;
	*&lt;br /&gt;
	* Triggers every [set time interval] and checks pages&lt;br /&gt;
	* Publishes page if time runout&lt;br /&gt;
	*&lt;br /&gt;
	* Adds publish page log&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___publishDefferedPages(HookEvent $e){&lt;br /&gt;
&lt;br /&gt;
		// seconds since last lazycron&lt;br /&gt;
		$seconds = $e-&amp;gt;arguments[0];&lt;br /&gt;
&lt;br /&gt;
		// find all pages with deffered field&lt;br /&gt;
		$defferedPages = $this-&amp;gt;pages-&amp;gt;find(&amp;quot;{$this-&amp;gt;checkboxName}=1,include=unpublished&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		// for each page decrease time for deffered field&lt;br /&gt;
		foreach ($defferedPages as $page) {&lt;br /&gt;
&lt;br /&gt;
			// get current page time&lt;br /&gt;
			$timeTillPublish = $page-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
&lt;br /&gt;
			// set time to time minus time past&lt;br /&gt;
			$timeLeft = $timeTillPublish - $seconds;&lt;br /&gt;
&lt;br /&gt;
			// if time passed 0 or less then publish page&lt;br /&gt;
			$page-&amp;gt;of(false);&lt;br /&gt;
			if($timeLeft &amp;lt;= 0){&lt;br /&gt;
				// remove flags and save&lt;br /&gt;
				$this-&amp;gt;publish($page);&lt;br /&gt;
&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;fieldName, 0);&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;checkboxName, 0);&lt;br /&gt;
&lt;br /&gt;
				// log a page has been published&lt;br /&gt;
				$log = wire(&amp;#039;log&amp;#039;);&lt;br /&gt;
				$log-&amp;gt;message(&amp;#039;CRON:&amp;#039;. $seconds .&amp;#039; Pages: &amp;#039;. $page-&amp;gt;name .&amp;#039; published&amp;#039;);&lt;br /&gt;
			}else{&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;fieldName, $timeLeft);&lt;br /&gt;
			}&lt;br /&gt;
			// save page time&lt;br /&gt;
			$page-&amp;gt;Save();&lt;br /&gt;
			$page-&amp;gt;of(true);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Install new module specific fields&lt;br /&gt;
	*/&lt;br /&gt;
	private function installFields(){&lt;br /&gt;
&lt;br /&gt;
		// install pub later checkbox field&lt;br /&gt;
		// find installed fields&lt;br /&gt;
		$f = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
		if($f){&lt;br /&gt;
&lt;br /&gt;
			// if field already found then don&amp;#039;t try and make it&lt;br /&gt;
			$this-&amp;gt;message($this-&amp;gt;fieldName . &amp;#039; field found&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
		}else{&lt;br /&gt;
&lt;br /&gt;
			// create new field object to store crontime&lt;br /&gt;
			$f = new Field();&lt;br /&gt;
			// get a field type&lt;br /&gt;
			$f-&amp;gt;type = $this-&amp;gt;modules-&amp;gt;get(&amp;quot;FieldtypeInteger&amp;quot;);&lt;br /&gt;
			$f-&amp;gt;name = $this-&amp;gt;fieldName;&lt;br /&gt;
			$f-&amp;gt;label = &amp;#039;Publish Time Left&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;defaultValue = $this-&amp;gt;defaultTime;&lt;br /&gt;
			$f-&amp;gt;icon = &amp;#039;clock-o&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;columnWidth = 50;&lt;br /&gt;
			$f-&amp;gt;collapsed = 1;&lt;br /&gt;
			$f-&amp;gt;flags = 4;&lt;br /&gt;
&lt;br /&gt;
			$f-&amp;gt;save(); // save the field&lt;br /&gt;
&lt;br /&gt;
			// create new field object to store whether to publish or not&lt;br /&gt;
			$f = new Field();&lt;br /&gt;
			// get a field type&lt;br /&gt;
			$f-&amp;gt;type = $this-&amp;gt;modules-&amp;gt;get(&amp;quot;FieldtypeCheckbox&amp;quot;);&lt;br /&gt;
			$f-&amp;gt;name = $this-&amp;gt;checkboxName;&lt;br /&gt;
			$f-&amp;gt;label = &amp;#039;Publish Page later&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;defaultValue = false;&lt;br /&gt;
			$f-&amp;gt;columnWidth = 50;&lt;br /&gt;
			$f-&amp;gt;icon = &amp;#039;clock-o&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;collapsed = 1;&lt;br /&gt;
			$f-&amp;gt;flags = 4;&lt;br /&gt;
&lt;br /&gt;
			$f-&amp;gt;save(); // save the field&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Uninstall module specific fields&lt;br /&gt;
	*/&lt;br /&gt;
	private function uninstallFields(){&lt;br /&gt;
&lt;br /&gt;
		// find installed fields&lt;br /&gt;
		$fInt = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
		$fCheck = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;checkboxName);&lt;br /&gt;
&lt;br /&gt;
		if($fInt &amp;amp;&amp;amp; $fCheck){&lt;br /&gt;
			$fieldIntUsed = $fInt-&amp;gt;numFieldgroups();&lt;br /&gt;
			$fieldCheckUsed = $fCheck-&amp;gt;numFieldgroups();&lt;br /&gt;
&lt;br /&gt;
			if($fieldIntUsed){&lt;br /&gt;
				// field in use by template&lt;br /&gt;
				$this-&amp;gt;message(&amp;#039;Unable to uninstall field &amp;#039;.$fInt-&amp;gt;name);&lt;br /&gt;
			}else{&lt;br /&gt;
				// delete installed fields&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;delete($fInt);&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;save;&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			if($fieldCheckUsed){&lt;br /&gt;
				// field in use by template&lt;br /&gt;
				$this-&amp;gt;message(&amp;#039;Unable to uninstall field &amp;#039;.$fCheck-&amp;gt;name);&lt;br /&gt;
			}else{&lt;br /&gt;
				// delete installed fields&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;delete($fCheck);&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;save;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Inputfield / Fieldtype ===&lt;br /&gt;
[[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei statt getModuleInfo ===&lt;br /&gt;
Bei größeren Konfigruation (z.B. Admin Page Navigation) sinnvoll.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * ProcessHello.info.php&lt;br /&gt;
 * &lt;br /&gt;
 * Return information about this module.&lt;br /&gt;
 *&lt;br /&gt;
 * If preferred, you can use a getModuleInfo() method in your module file, &lt;br /&gt;
 * or you can use a ModuleName.info.json file (if you prefer JSON definition). &lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
$info = array(&lt;br /&gt;
	// Your module&amp;#039;s title&lt;br /&gt;
	&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello: Process Module Example&amp;#039;, &lt;br /&gt;
	// A 1 sentence description of what your module does&lt;br /&gt;
	&amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;A starting point module skeleton from which to build your own Process module.&amp;#039;, &lt;br /&gt;
	// Module version number: use 1 for 0.0.1 or 100 for 1.0.0, and so on&lt;br /&gt;
	&amp;#039;version&amp;#039; =&amp;gt; 1, &lt;br /&gt;
	// Name of person who created this module (change to your name)&lt;br /&gt;
	&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ryan Cramer&amp;#039;, &lt;br /&gt;
	// Icon to accompany this module (optional), uses font-awesome icon names, minus the &amp;quot;fa-&amp;quot; part&lt;br /&gt;
	&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;thumbs-up&amp;#039;, &lt;br /&gt;
	// URL to more info: change to your full modules.processwire.com URL (if available), or something else if you prefer&lt;br /&gt;
	&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;http://modules.processwire.com/&amp;#039;, &lt;br /&gt;
	// name of permission required of users to execute this Process (optional)&lt;br /&gt;
	&amp;#039;permission&amp;#039; =&amp;gt; &amp;#039;helloworld&amp;#039;, &lt;br /&gt;
	// permissions that you want automatically installed/uninstalled with this module (name =&amp;gt; description)&lt;br /&gt;
	&amp;#039;permissions&amp;#039; =&amp;gt; array(&lt;br /&gt;
		&amp;#039;helloworld&amp;#039; =&amp;gt; &amp;#039;Run the HelloWorld module&amp;#039;&lt;br /&gt;
	), &lt;br /&gt;
	&lt;br /&gt;
	// page that you want created to execute this module&lt;br /&gt;
	&amp;#039;page&amp;#039; =&amp;gt; array(&lt;br /&gt;
		&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;helloworld&amp;#039;,&lt;br /&gt;
		&amp;#039;parent&amp;#039; =&amp;gt; &amp;#039;setup&amp;#039;, &lt;br /&gt;
		&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello World&amp;#039;&lt;br /&gt;
	),&lt;br /&gt;
	// optional extra navigation that appears in admin&lt;br /&gt;
	// if you change this, you&amp;#039;ll need to a Modules &amp;gt; Refresh to see changes&lt;br /&gt;
	&amp;#039;nav&amp;#039; =&amp;gt; array(&lt;br /&gt;
		array(&lt;br /&gt;
			&amp;#039;url&amp;#039; =&amp;gt; &amp;#039;&amp;#039;, &lt;br /&gt;
			&amp;#039;label&amp;#039; =&amp;gt; &amp;#039;Hello&amp;#039;, &lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;smile-o&amp;#039;, &lt;br /&gt;
		), &lt;br /&gt;
		array(&lt;br /&gt;
			&amp;#039;url&amp;#039; =&amp;gt; &amp;#039;something/&amp;#039;, &lt;br /&gt;
			&amp;#039;label&amp;#039; =&amp;gt; &amp;#039;Something&amp;#039;, &lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;beer&amp;#039;, &lt;br /&gt;
		),&lt;br /&gt;
	)&lt;br /&gt;
	// for more options that you may specify here, see the file: /wire/core/Process.php&lt;br /&gt;
	// and the file: /wire/core/Module.php&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interessantes - Read On ==&lt;br /&gt;
 https://processwire.com/talk/topic/24067-solved-settings-fields-that-dont-save-to-database/&lt;br /&gt;
 https://processwire.com/talk/topic/24075-solved-create-field-and-add-to-template/&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Module_schreiben&amp;diff=24850</id>
		<title>ProcessWire - Module schreiben</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Module_schreiben&amp;diff=24850"/>
		<updated>2020-11-04T21:42:39Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Wichtigste Resourcen&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 https://processwire.com/docs/modules/development/ - Guter Ausgangspunkt&lt;br /&gt;
 https://processwire.com/api/ref/module/ - Module API&lt;br /&gt;
 https://processwire.com/api/ref/configurable-module/ - Klasse für Konfigurierbare Module&lt;br /&gt;
 https://processwire.com/docs/modules/types/ - Welche Modultypen gibt es ?&lt;br /&gt;
 https://processwire.com/talk/topic/778-module-dependencies/ - Module die andere Module benötigen&lt;br /&gt;
 https://processwire.com/talk/forum/19-moduleplugin-development/ - Forum zum Thema Module entwickeln&lt;br /&gt;
 http://somatonic.github.io/Captain-Hook/ - Hook Cheatsheet&lt;br /&gt;
 https://processwire.com/blog/posts/new-module-configuration-options/ - Neuere Konfigurationsmöglichkeiten&lt;br /&gt;
 https://processwire.com/docs/start/api-access/ Zugriff auf ProcessWire API Variablen (wire Objekt)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039; Tutorials und Beispiele zum Einstieg &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 https://processwire.com/docs/modules/ - Introduction, Development, Hooks, Types, Pro Modules, Third Party&lt;br /&gt;
 https://github.com/ryancramerdesign/ProcessHello - Modul Skelett Beispiel für eigene Backend (Process) Module&lt;br /&gt;
 https://github.com/ryancramerdesign/FieldtypeMapMarker - Beispiel für ein Fieldtype und Inputfield Modul&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/a-beginners-introduction-to-writing-modules-in-processwire--cms-26862&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Wikiseiten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 [[ProcessWire - Module Snippets]]&lt;br /&gt;
 [[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Weitere Links&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 http://modules.pw/ (Module Creator)&lt;br /&gt;
&lt;br /&gt;
== Wo - Was ? ==&lt;br /&gt;
=== Welche Typen von Modulen gibt es ? ===&lt;br /&gt;
 https://processwire.com/docs/modules/types/&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Fieldtype&amp;#039;&amp;#039;&amp;#039;: Repräsentiert einen Datentyp. Meistens keine Public API, Handelt Daten / Datenbank - [[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Inputfield&amp;#039;&amp;#039;&amp;#039;: Sammelt User Eingaben über ein Formular im Admin Bereich. Im Gegensatz zum Fieldtype geht es hier um das UI im Backend. Das Handling der Daten liegt beim Fieldtype.&lt;br /&gt;
* [[Process Module (ProcessWire)|&amp;#039;&amp;#039;&amp;#039;Process&amp;#039;&amp;#039;&amp;#039; for creating admin processes/applications.]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Textformatter&amp;#039;&amp;#039;&amp;#039; for formatting text.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminTheme&amp;#039;&amp;#039;&amp;#039; for creating themes in the admin.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;WireMail&amp;#039;&amp;#039;&amp;#039; for modules that send email and extend the WireMail class.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tfa&amp;#039;&amp;#039;&amp;#039; for implementing a specific kind of two-factor authentication.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ImageSizerEngine&amp;#039;&amp;#039;&amp;#039; for modules that extend ImageSizerEngine for resizing images.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FileCompiler&amp;#039;&amp;#039;&amp;#039; for modules that extend FileCompilerModule for compilation of files.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FileValidator&amp;#039;&amp;#039;&amp;#039; for modules that extend FileValidatorModule for validation of files.&lt;br /&gt;
&lt;br /&gt;
=== Wie werden Felder in der Datenbank angelegt ? ===&lt;br /&gt;
Dazu nutzt man den Typ &amp;quot;Fieldtype&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Wo rendert man die Ausgabe ? ===&lt;br /&gt;
Bei Ryan Cramers Event Beispiel legt er zwei Klassen Event und EventArray an, die auch die Render Funktionen enthalten.&lt;br /&gt;
&lt;br /&gt;
=== Namenskonventionen ===&lt;br /&gt;
Ein Modulname sollte mit dem Typ den das Modul hat beginnen. Also etwa ProcessMeinAdminModul oder FieldtypeTable. ProcessWire listet das Modul dann in der Entsprechenden Kategorie auf. Wenn man etwas anderes nimmt z.B. LoginRegister dann kommt das Modul unter der neuen Rubrik &amp;quot;Login&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurierbare Module ===&lt;br /&gt;
Das geht seit 2.5.5 mittlerweile sehr einfach mit den neuen configuration-options.&lt;br /&gt;
 https://processwire.com/blog/posts/new-module-configuration-options/&lt;br /&gt;
 [[ProcessWire - Konfigurierbare Module]]&lt;br /&gt;
&lt;br /&gt;
== Spezielle Funktionen in Modulen ==&lt;br /&gt;
&lt;br /&gt;
=== Modulinformation ===&lt;br /&gt;
Das Modul stellt Infos zur Verfügung und nutzt dafür eine von 3 Methoden:&lt;br /&gt;
    getModuleInfo() static method in your module class that returns an array.&lt;br /&gt;
    YourModuleClass.info.php file that populates an $info array.&lt;br /&gt;
    YourModuleClass.info.json file that contains an info object.&lt;br /&gt;
&lt;br /&gt;
Hier werden title, version, summary und weitere Daten hinterlegt. Hier kann man auch angeben ob ein Modul ein Autoload Modul ist.&lt;br /&gt;
&lt;br /&gt;
 https://processwire.com/api/ref/module/&lt;br /&gt;
&lt;br /&gt;
=== init ===&lt;br /&gt;
 public function init(){}&lt;br /&gt;
Initialisiert das Modul. ProcessWire ruft diese Funktion auf, wenn das Modul geladen ist. Bei Autoload Modulen wird es aufgerufen wenn die ProcessWire API bereit ist. Daher ist es ein guter Ort um Hooks einzubinden.&lt;br /&gt;
&lt;br /&gt;
=== ready ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  public function ready() {&lt;br /&gt;
    if($this-&amp;gt;page-&amp;gt;template == &amp;#039;admin&amp;#039;) {&lt;br /&gt;
      $this-&amp;gt;message($this-&amp;gt;hi());&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird in autoload Modulen aufgerufen wenn die API bereit ist. Nützlich für Hooks:&lt;br /&gt;
&lt;br /&gt;
=== execute ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	/**&lt;br /&gt;
	 * This function is executed when a page with your Process assigned is accessed. &lt;br /&gt;
 	 *&lt;br /&gt;
	 * This can be seen as your main or index function. You&amp;#039;ll probably want to replace&lt;br /&gt;
	 * everything in this function. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___execute() {&lt;br /&gt;
		// greetingType and greeting are automatically populated to this module&lt;br /&gt;
		// and they were defined in ProcessHello.config.php&lt;br /&gt;
		if($this-&amp;gt;greetingType == &amp;#039;message&amp;#039;) {&lt;br /&gt;
			$this-&amp;gt;message($this-&amp;gt;greeting); &lt;br /&gt;
		} else if($this-&amp;gt;greetingType == &amp;#039;warning&amp;#039;) {&lt;br /&gt;
			$this-&amp;gt;warning($this-&amp;gt;greeting); &lt;br /&gt;
		} else {&lt;br /&gt;
			$this-&amp;gt;error($this-&amp;gt;greeting); &lt;br /&gt;
		}&lt;br /&gt;
		// generate some navigation&lt;br /&gt;
		$out = 	&amp;quot;&lt;br /&gt;
			&amp;lt;h2&amp;gt;$this-&amp;gt;greeting&amp;lt;/h2&amp;gt;&lt;br /&gt;
			&amp;lt;dl class=&amp;#039;nav&amp;#039;&amp;gt;&lt;br /&gt;
				&amp;lt;dt&amp;gt;&amp;lt;a href=&amp;#039;./something/&amp;#039;&amp;gt;Do Something&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;&lt;br /&gt;
				&amp;lt;dd&amp;gt;Runs the executeSomething() function.&amp;lt;/dd&amp;gt;&lt;br /&gt;
			&amp;lt;/dl&amp;gt;&lt;br /&gt;
			&amp;quot;;&lt;br /&gt;
		return $out;&lt;br /&gt;
	}	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== executeSomething ===&lt;br /&gt;
Ruft man eine Unterseite des Moduls auf kann man eine eigene execute Funktion nutzen&lt;br /&gt;
___executeSlug wobei Slug für den Url Slug steht. Heißt der slug /field/ dann wird executeField() aufgerufen, falls diese Funktion existiert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	/**&lt;br /&gt;
	 * Called when the URL is this module&amp;#039;s page URL + &amp;quot;/something/&amp;quot;&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___executeSomething() {&lt;br /&gt;
		// set a new headline, replacing the one used by our page&lt;br /&gt;
		// this is optional as PW will auto-generate a headline &lt;br /&gt;
		$this-&amp;gt;headline(&amp;#039;This is something!&amp;#039;); &lt;br /&gt;
		// add a breadcrumb that returns to our main page &lt;br /&gt;
		// this is optional as PW will auto-generate breadcrumbs&lt;br /&gt;
		$this-&amp;gt;breadcrumb(&amp;#039;../&amp;#039;, &amp;#039;Hello&amp;#039;); &lt;br /&gt;
		$out = 	&amp;quot;&lt;br /&gt;
			&amp;lt;h2&amp;gt;Not much to to see here&amp;lt;/h2&amp;gt;&lt;br /&gt;
			&amp;lt;p&amp;gt;&amp;lt;a href=&amp;#039;../&amp;#039;&amp;gt;Go Back&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
			&amp;quot;;&lt;br /&gt;
		return $out; &lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== install &amp;amp; uninstall ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
	 * Called only when your module is installed&lt;br /&gt;
	 *&lt;br /&gt;
	 * If you don&amp;#039;t need anything here, you can simply remove this method. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___install() {&lt;br /&gt;
		parent::___install(); // always remember to call parent method&lt;br /&gt;
	}&lt;br /&gt;
	/**&lt;br /&gt;
	 * Called only when your module is uninstalled&lt;br /&gt;
	 *&lt;br /&gt;
	 * This should return the site to the same state it was in before the module was installed. &lt;br /&gt;
	 *&lt;br /&gt;
	 * If you don&amp;#039;t need anything here, you can simply remove this method. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___uninstall() {&lt;br /&gt;
		parent::___uninstall(); // always remember to call parent method&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vererbung und Eigenschaften in Modulen ==&lt;br /&gt;
Modules are not different from PHP classes.&lt;br /&gt;
&lt;br /&gt;
To change the properties of MyModule class from within MyOtherModule class, you can either:&lt;br /&gt;
&lt;br /&gt;
#Make MyOtherModule class extend MyModule. It will thus inherit MyModule&amp;#039;s public and protected properties and methods&lt;br /&gt;
#Make the properties firstName and lastName configurable by passing them as parameters/arguments in MyModule&amp;#039;s constructor method.&lt;br /&gt;
&lt;br /&gt;
== Autoload Module und Hooks ==&lt;br /&gt;
Autoload werden automatisch geladen müssen also nicht in einem Template o.ä. gestartet werden. Daher bieten sie sich an um die Funktionalität von ProcessWire zu erweitern. Als Werkzeug dafür dienen Hooks. Mit Hooks kann man an vielen Stellen den Rendering Process der Seiten beeinflussen. Außerdem kann man für eigene Module ebenfalls Hooks bereitstellen. &lt;br /&gt;
&lt;br /&gt;
=== Hooks ===&lt;br /&gt;
 https://processwire.com/docs/modules/hooks/&lt;br /&gt;
Hooks sind ein mächtiges Werkzeug. Sie geben einem die Möglichkeit an vielen Stellen &amp;quot;einzuhaken&amp;quot; und Funktionalität einzubauen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, function($event) {&lt;br /&gt;
    $event-&amp;gt;return .= &amp;#039;&amp;lt;p&amp;gt;Hallo&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Schreibt am Ende Jeder Seite ein &amp;quot;Hallo&amp;quot;. Das $event Objekt ist ein [https://processwire.com/api/ref/hook-event/ HookEvent]. Im Beispiel fügen wir einfach etwas Markup hinzu. Über $event-&amp;gt;arguments() kann man aber auf ale Argumente zugreifen.&lt;br /&gt;
&lt;br /&gt;
Das gleiche aber nicht mit anonymer Funktion:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  // add hook after Page::render() and make it call the &amp;quot;test&amp;quot; method of $this module&lt;br /&gt;
  $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, $this, &amp;#039;test&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public function test($event) {&lt;br /&gt;
  // modify the return value of Page::render() to include the following:&lt;br /&gt;
  $event-&amp;gt;return .= &amp;#039;&amp;lt;p&amp;gt;Hallo&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hooks zum erweitern von existierenden Klassen nutzen ===&lt;br /&gt;
Mit Hooks kann man in vorhandene Klassen einhaken. Z.B. läßt sich das Page Objekt erweitern.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  $this-&amp;gt;addHook(&amp;#039;Page::summarize&amp;#039;, $this, &amp;#039;summarize&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
public function summarize($event) {&lt;br /&gt;
  $page = $event-&amp;gt;object; // the $event-&amp;gt;object represents the object hooked (Page)&lt;br /&gt;
  $maxlen = $event-&amp;gt;arguments(0); // first argument is the optional max length&lt;br /&gt;
  if(!$maxlen) $maxlen = 200; // if no $maxlen was present, we&amp;#039;ll use a default of 200&lt;br /&gt;
  $summary = $this-&amp;gt;sanitizer-&amp;gt;truncate($page-&amp;gt;body, $maxlen); // use sanitizer truncate method to create a summary&lt;br /&gt;
  $event-&amp;gt;return = $summary; // populate $summary to $event-&amp;gt;return, the return value&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So kann man ganz einfach eine Zusammenfassung aller Kindseiten in einem Template rendern:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
foreach($page-&amp;gt;children as $item) {&lt;br /&gt;
  $summary = $item-&amp;gt;summarize(150);&lt;br /&gt;
  echo &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;$item-&amp;gt;url&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;$summary&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Autoload Module nur im Admin Bereich laden ===&lt;br /&gt;
&lt;br /&gt;
 &amp;#039;autoload&amp;#039; =&amp;gt; &amp;#039;template=admin&amp;#039; &lt;br /&gt;
statt&lt;br /&gt;
 &amp;#039;autoload&amp;#039; =&amp;gt; true&lt;br /&gt;
&lt;br /&gt;
=== Hook Beispiele ===&lt;br /&gt;
Hook am Ende des Renderings&lt;br /&gt;
 $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, function($event) {...});&lt;br /&gt;
Füge eine Funktion &amp;quot;summarize&amp;quot; zum Page Objekt hinzu.&lt;br /&gt;
 $this-&amp;gt;addHook(&amp;#039;Page::summarize&amp;#039;, $this, &amp;#039;summarize&amp;#039;);&lt;br /&gt;
Hook auf eine einzelne Instanz (hier pages Objekt)&lt;br /&gt;
 $this-&amp;gt;pages-&amp;gt;addHookAfter(&amp;#039;saved&amp;#039;, function($event){...});&lt;br /&gt;
 $this-&amp;gt;addHook(&amp;#039;Page::method&amp;#039;, ...) // Spricht ALLE Instanzen an - Regelfall&lt;br /&gt;
 $page-&amp;gt;addHook(&amp;#039;method&amp;#039;, ...) // Spricht nur die EINE Instanz der Seite an.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Module Dependencies - voneinander abhängige Module ==&lt;br /&gt;
&lt;br /&gt;
 https://processwire.com/talk/topic/778-module-dependencies/&lt;br /&gt;
Wenn ein Modul nicht ohne ein anderes funktioniert spricht man von Module Dependency. In solchen Fällen kann man in der Modul Info angeben In vielen Fällen besteht ein Modul unter der Haube aus mehreren Einzelmodulen.&lt;br /&gt;
&lt;br /&gt;
Um ProcessWire mitzuteilen dass ein Modul benötigt wird gibt man es in der Moduldefinition an:&lt;br /&gt;
 &amp;#039;requires&amp;#039; =&amp;gt; &amp;quot;LazyCron&amp;quot;  // added this line&lt;br /&gt;
oder auch mehrere als Array&lt;br /&gt;
 &amp;#039;requires&amp;#039; =&amp;gt; array(&amp;quot;LazyCron&amp;quot;, &amp;quot;AdminBar&amp;quot;)  // added this line&lt;br /&gt;
&lt;br /&gt;
ProcessWire kann auch dafür sorgen, dass ein Modul andere &amp;quot;Kindmodule&amp;quot; gleich mitinstalliert bzw. deinstalliert wenn es nicht mehr benötigt wird. Dazu gibt man dem Modul noch die &amp;#039;install&amp;#039; dependency mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
public static function getModuleInfo() {&lt;br /&gt;
   return array(&lt;br /&gt;
       &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Log Master&amp;#039;,&lt;br /&gt;
       &amp;#039;version&amp;#039; =&amp;gt; 101,&lt;br /&gt;
       &amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Lumberjack Bob&amp;#039;,&lt;br /&gt;
       &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Log all actions on your site&amp;#039;,&lt;br /&gt;
       &amp;#039;requires&amp;#039; =&amp;gt; &amp;#039;LazyCron&amp;#039;, &lt;br /&gt;
       &amp;#039;installs&amp;#039; =&amp;gt; &amp;#039;ProcessLogMaster&amp;#039;  // added this line&lt;br /&gt;
       ); &lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProcessWire sieht dann eine Kindabhängigkeit zu diesem Modul und handelt auch das Deinstallieren, wenn das Elternmodul deinstalliert wird.&lt;br /&gt;
&lt;br /&gt;
== CSS und JavaScript in Modulen ==&lt;br /&gt;
Bei Process Modulen möchte man für das Styling etc. im Backend oft CSS und JS Dateien hinzufügen.&lt;br /&gt;
&lt;br /&gt;
Einfach Eine Datei MeinModul.css und / oder MeinModul.js hinzufügen. JQuery ist im Admin bereits geladen daher kann eine MeinModul.js Starter Datei so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This JS file is only loaded when the ProcessHello module is run&lt;br /&gt;
 *&lt;br /&gt;
 * You should delete it if you have no javascript to add.&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
$(document).ready(function() {&lt;br /&gt;
	// do something&lt;br /&gt;
}); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Frontend Rendering Module ===&lt;br /&gt;
A bit old but working&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * FrontEndRender&lt;br /&gt;
 *&lt;br /&gt;
 * Author: Ben Byford&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2010 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class FrontEndRender extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;FrontEndRender&amp;#039;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 0.1,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;Outputs html and static variables to frontend&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ben Byford&amp;#039;,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://github.com/benbyford/PW-starter-modules&amp;#039;&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// protected variable only accessable within module&lt;br /&gt;
	protected $name = &amp;#039;Ben&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* render function to be called in PW template like this:&lt;br /&gt;
	* $FrontEndRender = $modules-&amp;gt;getModule(&amp;#039;FrontEndRender&amp;#039;);&lt;br /&gt;
	* echo &amp;#039;&amp;lt;h1&amp;gt;&amp;#039; . $FrontEndRender-&amp;gt;render() . &amp;#039;&amp;lt;/h1&amp;gt;&amp;#039;;&lt;br /&gt;
	*&lt;br /&gt;
	*/&lt;br /&gt;
	public function render(){&lt;br /&gt;
		return &amp;quot;Hello &amp;quot; . $this-&amp;gt;name;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Hello World Modul ===&lt;br /&gt;
Beispiel Modul mit Hooks (liegt immer in der Standardinstallation)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * ProcessWire &amp;#039;Hello world&amp;#039; demonstration module&lt;br /&gt;
 *&lt;br /&gt;
 * Demonstrates the Module interface and how to add hooks.&lt;br /&gt;
 * &lt;br /&gt;
 * See README file for further links regarding module development.&lt;br /&gt;
 * &lt;br /&gt;
 * This file is licensed under the MIT license&lt;br /&gt;
 * https://processwire.com/about/license/mit/&lt;br /&gt;
 * &lt;br /&gt;
 * ProcessWire 3.x, Copyright 2016 by Ryan Cramer&lt;br /&gt;
 * https://processwire.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class Helloworld extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * getModuleInfo is a module required by all modules to tell ProcessWire about them&lt;br /&gt;
	 *&lt;br /&gt;
	 * @return array&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
&lt;br /&gt;
		return array(&lt;br /&gt;
&lt;br /&gt;
			// The module&amp;#039;s title, typically a little more descriptive than the class name&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello World&amp;#039;, &lt;br /&gt;
&lt;br /&gt;
			// version number &lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 3, &lt;br /&gt;
&lt;br /&gt;
			// summary is brief description of what this module is&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;An example module used for demonstration purposes.&amp;#039;,&lt;br /&gt;
			&lt;br /&gt;
			// Optional URL to more information about the module&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://processwire.com&amp;#039;,&lt;br /&gt;
&lt;br /&gt;
			// singular=true: indicates that only one instance of the module is allowed.&lt;br /&gt;
			// This is usually what you want for modules that attach hooks. &lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true, &lt;br /&gt;
&lt;br /&gt;
			// autoload=true: indicates the module should be started with ProcessWire.&lt;br /&gt;
			// This is necessary for any modules that attach runtime hooks, otherwise those&lt;br /&gt;
			// hooks won&amp;#039;t get attached unless some other code calls the module on it&amp;#039;s own.&lt;br /&gt;
			// Note that autoload modules are almost always also &amp;#039;singular&amp;#039; (seen above).&lt;br /&gt;
			&amp;#039;autoload&amp;#039; =&amp;gt; true, &lt;br /&gt;
		&lt;br /&gt;
			// Optional font-awesome icon name, minus the &amp;#039;fa-&amp;#039; part&lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;smile-o&amp;#039;, &lt;br /&gt;
			);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Initialize the module&lt;br /&gt;
	 *&lt;br /&gt;
	 * ProcessWire calls this when the module is loaded. For &amp;#039;autoload&amp;#039; modules, this will be called&lt;br /&gt;
	 * when ProcessWire&amp;#039;s API is ready. As a result, this is a good place to attach hooks. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function init() {&lt;br /&gt;
&lt;br /&gt;
		// add a hook after the $pages-&amp;gt;save, to issue a notice every time a page is saved&lt;br /&gt;
		$this-&amp;gt;pages-&amp;gt;addHookAfter(&amp;#039;save&amp;#039;, $this, &amp;#039;example1&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a hook after each page is rendered and modify the output&lt;br /&gt;
		$this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, $this, &amp;#039;example2&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a &amp;#039;hello&amp;#039; method to every page that returns &amp;quot;Hello World&amp;quot;&lt;br /&gt;
		// use &amp;quot;echo $page-&amp;gt;hello();&amp;quot; in your template file to display output&lt;br /&gt;
		$this-&amp;gt;addHook(&amp;#039;Page::hello&amp;#039;, $this, &amp;#039;example3&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a &amp;#039;hello_world&amp;#039; property to every page that returns &amp;quot;Hello [user]&amp;quot;&lt;br /&gt;
		// use &amp;quot;echo $page-&amp;gt;hello_world;&amp;quot; in your template file to display output&lt;br /&gt;
		$this-&amp;gt;addHookProperty(&amp;#039;Page::hello_world&amp;#039;, $this, &amp;#039;example4&amp;#039;); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example1 hooks into the pages-&amp;gt;save method and displays a notice every time a page is saved&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example1($event) {&lt;br /&gt;
		/** @var Page $page */&lt;br /&gt;
		$page = $event-&amp;gt;arguments[0]; &lt;br /&gt;
		$this-&amp;gt;message(&amp;quot;Hello World! You saved {$page-&amp;gt;path}.&amp;quot;); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example2 hooks into every page after it&amp;#039;s rendered and adds &amp;quot;Hello World&amp;quot; text at the bottom&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example2($event) {&lt;br /&gt;
&lt;br /&gt;
		/** @var Page $page */&lt;br /&gt;
		$page = $event-&amp;gt;object; &lt;br /&gt;
&lt;br /&gt;
		// don&amp;#039;t add this to the admin pages&lt;br /&gt;
		if($page-&amp;gt;template == &amp;#039;admin&amp;#039;) return;&lt;br /&gt;
&lt;br /&gt;
		// add a &amp;quot;Hello World&amp;quot; paragraph right before the closing body tag&lt;br /&gt;
		$event-&amp;gt;return = str_replace(&amp;quot;&amp;lt;/body&amp;gt;&amp;quot;, &amp;quot;&amp;lt;p&amp;gt;Hello World!&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;quot;, $event-&amp;gt;return); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example3 adds a &amp;#039;hello&amp;#039; method (not property) to every page that simply returns &amp;quot;Hello World&amp;quot;&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example3($event) {&lt;br /&gt;
		$event-&amp;gt;return = &amp;quot;Hello World&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example 4 adds a &amp;#039;hello_world&amp;#039; property (not method) to every page that returns &amp;quot;Hello [user]&amp;quot;&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example4($event) {&lt;br /&gt;
		$event-&amp;gt;return = &amp;quot;Hello &amp;quot; . $this-&amp;gt;user-&amp;gt;name; &lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Admin Bereich mit eigener Funktionalität erweitern (Modul)===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
* ProcessSimpleAdminPage&lt;br /&gt;
*&lt;br /&gt;
* @author Ben Byford&lt;br /&gt;
* http://www.benbyford.com&lt;br /&gt;
*&lt;br /&gt;
* @see http://www.processwire.com&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
class ProcessSimpleAdminPage extends Process {&lt;br /&gt;
&lt;br /&gt;
    public static function getModuleInfo() {&lt;br /&gt;
        return array(&lt;br /&gt;
            &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Process Simple Admin Page&amp;#039;,&lt;br /&gt;
            &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Simple Process module that adds new admin page with&amp;#039;,&lt;br /&gt;
            &amp;#039;version&amp;#039; =&amp;gt; 001,&lt;br /&gt;
&lt;br /&gt;
            // Modules that extend Process may specify a &amp;#039;page&amp;#039; attribute in the&lt;br /&gt;
            // getModuleInfo(), this page will automatically be given the module&lt;br /&gt;
            // process when added to teh pagetree.&lt;br /&gt;
&lt;br /&gt;
            // I have exampled but commented out the &amp;#039;page&amp;#039; settings below&lt;br /&gt;
            // so that I can show how one might add a page to install() and&lt;br /&gt;
            // uninstall() in this and other modules (that might not extend&lt;br /&gt;
            // Process)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        // 	&amp;#039;page&amp;#039; =&amp;gt; array(&lt;br /&gt;
        // 		&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;site-config&amp;#039;,&lt;br /&gt;
        // 		&amp;#039;parent&amp;#039; =&amp;gt; &amp;#039;admin&amp;#039;,&lt;br /&gt;
        // 		&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Site Config&amp;#039;&lt;br /&gt;
        // 	   )&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function execute() {&lt;br /&gt;
        return &amp;#039;&lt;br /&gt;
            &amp;lt;h2&amp;gt;Edit the text here in the module&amp;lt;/h2&amp;gt;&lt;br /&gt;
            &amp;lt;p&amp;gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mattis eros vitae metus sodales eget suscipit purus rhoncus. Proin ultrices gravida dolor, non porttitor enim interdum vitae. Integer feugiat lacinia tincidunt. Nulla laoreet tristique tristique. Sed elementum justo a nisl elementum sit amet accumsan nisi tempor. Nulla quis eros et massa dignissim imperdiet a vitae purus.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Donec scelerisque pulvinar sem eu lobortis. Maecenas turpis ipsum, tempus dictum pharetra eu, consectetur vitae arcu. Fusce orci mauris, semper at tempus quis, volutpat molestie tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed quam tortor, tincidunt sed semper lacinia, scelerisque dapibus quam. Morbi at nisi luctus lacus auctor ultrices eu eu leo.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Praesent faucibus purus id felis tincidunt dignissim. Sed sit amet ligula mi, eget semper dui. Proin consectetur gravida massa, nec luctus purus hendrerit in. Etiam volutpat, elit non venenatis suscipit, libero neque consectetur diam, id rutrum magna odio ac ligula. Maecenas sollicitudin congue neque fermentum vestibulum. Morbi nec leo nisi. Donec at nisl odio, et porta ligula.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Sed quis arcu nisi, ac tempor augue. Praesent non elit libero, a ullamcorper lorem. Curabitur porta odio eu nunc ultricies interdum id nec risus. Donec nibh nibh, porta eget vehicula ac, aliquet eget ante. Phasellus eget lorem eu eros eleifend ultrices. Cras sit amet neque sit amet nibh fringilla cursus ut id mauris. Praesent quis nunc justo, sed suscipit lectus. Phasellus eget ultrices risus. Curabitur eu semper est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut suscipit, nisl ut imperdiet eleifend, turpis arcu placerat tortor, nec laoreet lacus neque ac tellus. Aenean ac lacus justo, quis ultricies nisi.&amp;lt;/p&amp;gt;&lt;br /&gt;
            &amp;#039;;&lt;br /&gt;
    }&lt;br /&gt;
    public function install(){&lt;br /&gt;
&lt;br /&gt;
        // create new page to add to CMS&lt;br /&gt;
		$page = new Page();&lt;br /&gt;
&lt;br /&gt;
        // add page attributes&lt;br /&gt;
        $page-&amp;gt;template = &amp;quot;admin&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;name = &amp;quot;cms-faq&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;title = &amp;quot;CMS FAQ&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;save();&lt;br /&gt;
&lt;br /&gt;
        // set this module as the page process, this allows us to display the above&lt;br /&gt;
        $page-&amp;gt;process = &amp;#039;ProcessSimpleAdminPage&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
        // get admin page and set as page parent&lt;br /&gt;
        $admin = $this-&amp;gt;pages-&amp;gt;get(&amp;quot;id=2&amp;quot;);&lt;br /&gt;
        $page-&amp;gt;parent = $admin;&lt;br /&gt;
&lt;br /&gt;
        // save page&lt;br /&gt;
        $page-&amp;gt;save();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function uninstall(){&lt;br /&gt;
&lt;br /&gt;
        // delete created page&lt;br /&gt;
        $page = $this-&amp;gt;pages-&amp;gt;get(&amp;quot;name=cms-faq&amp;quot;);&lt;br /&gt;
        if(count($page)) $this-&amp;gt;pages-&amp;gt;delete($page, true);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Textformatter Modul ===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * TextformatterFindReplace&lt;br /&gt;
 *&lt;br /&gt;
 * Author: Ben Byford&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2010 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class TextformatterFindReplace extends Textformatter implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;TextformatterFindReplace&amp;#039;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 0.1,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;Finds and replaces any instance of config input to config output&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ben Byford&amp;#039;,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://github.com/benbyford/PW-starter-modules&amp;#039;&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
     * Find and Replace the input string&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $str The block of text to parse&lt;br /&gt;
     *&lt;br /&gt;
     * The incoming string is replaced with the formatted version of itself.&lt;br /&gt;
	 **/&lt;br /&gt;
&lt;br /&gt;
	public function format(&amp;amp;$str) {&lt;br /&gt;
		$find = $this-&amp;gt;findStr;&lt;br /&gt;
		$str = preg_replace_callback($find, array($this,&amp;quot;replace&amp;quot;), $str);&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// adding three underscores to a function allows other modules to hook it&lt;br /&gt;
	public function ___replace($match) {&lt;br /&gt;
		return $this-&amp;gt;replaceStr;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Admin Funktionalität: Countdown zum Seitenveröffentlichen ===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&lt;br /&gt;
The module PageDeferredPublish, on clicking one of the &amp;#039;&amp;#039;&amp;#039;Publish Later buttons&amp;#039;&amp;#039;&amp;#039;, sets LazyCron to check that page’s countdown every minute and publishes the page when its countdown reaches 0. This means I can publish a page approximately 24 hours in advance (obviously the checking interval and delay time can be changed to your requirements).&lt;br /&gt;
&lt;br /&gt;
I did this by:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Creating two fields&amp;#039;&amp;#039;&amp;#039; within my install() function: a checkbox field to set to true when a button is checked to indicate the page should countdown, and a countdown field to store the count in seconds for that specific page.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Adding hooks&amp;#039;&amp;#039;&amp;#039; to both &amp;#039;&amp;#039;ProcessPageEdit::buildForm&amp;#039;&amp;#039; and &amp;#039;&amp;#039;ProcessPageListActions::getExtraActions&amp;#039;&amp;#039; enabling me to add the two buttons.&lt;br /&gt;
&lt;br /&gt;
Checking to see if one of the buttons was clicked with my &amp;#039;&amp;#039;&amp;#039;ready() function&amp;#039;&amp;#039;&amp;#039; then setting the corresponding page’s checkbox to true.&lt;br /&gt;
&lt;br /&gt;
Using a &amp;#039;&amp;#039;&amp;#039;LazyCron hook function&amp;#039;&amp;#039;&amp;#039; to check all pages that are unpublished for true checkboxes and then comparing the seconds field to see if the page needs publishing. If not then deduct the elapsed time in seconds.&lt;br /&gt;
&lt;br /&gt;
The result is a &amp;#039;&amp;#039;&amp;#039;module that has settings&amp;#039;&amp;#039;&amp;#039; (the time interval to check and publish at a later time), &amp;#039;&amp;#039;&amp;#039;hooks into the admin&amp;#039;&amp;#039;&amp;#039; using buttons and fields, and enables us to &amp;#039;&amp;#039;&amp;#039;use other modules installe&amp;#039;&amp;#039;&amp;#039;d in PW (i.e. LazyCron).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * DeferredPublish (0.0.1)&lt;br /&gt;
 * DeferredPublish publishes a page after a defined amount of time has elapsed using lazycron.&lt;br /&gt;
 *&lt;br /&gt;
 * @author Ben Byford&lt;br /&gt;
 * http://www.benbyford.com&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2011 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class PageDeferredPublish extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;quot;PageDeferredPublish&amp;quot;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; &amp;quot;0.0.1&amp;quot;,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;PageDeferredPublish&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;quot;Ben Byford&amp;quot;,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;quot;https://github.com/benbyford/PW-intermediate-modules&amp;quot;,&lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;quot;clock-o&amp;quot;,&lt;br /&gt;
			&amp;#039;autoload&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;requires&amp;#039; =&amp;gt; &amp;quot;LazyCron&amp;quot;,&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	private $postPubLater 	= null;&lt;br /&gt;
	private $pageID 		= null;&lt;br /&gt;
	private $pagePubLater 	= null;&lt;br /&gt;
	private $currentPage	= null;&lt;br /&gt;
&lt;br /&gt;
	private $submitName 	= &amp;#039;pdp_pub_later_submit&amp;#039;;&lt;br /&gt;
	private $listPageName	= &amp;#039;pdp_pub_later_list&amp;#039;;&lt;br /&gt;
	private $fieldName 		= &amp;#039;pdp_pub_later&amp;#039;;&lt;br /&gt;
	private $checkboxName	= &amp;#039;pdp_pub_later_check&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	private $defaultInterval = &amp;#039;everyMinute&amp;#039;;&lt;br /&gt;
	private $defaultTime 	= 86400;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	public function install(){&lt;br /&gt;
		// add new fields needed for module&lt;br /&gt;
		$this-&amp;gt;installFields();&lt;br /&gt;
	}&lt;br /&gt;
	public function uninstall(){&lt;br /&gt;
		// uninstall fields&lt;br /&gt;
		$this-&amp;gt;uninstallFields();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// initialize the hook in your AutoLoad module&lt;br /&gt;
	public function init() {&lt;br /&gt;
&lt;br /&gt;
		// get defaults from module setting in CMS&lt;br /&gt;
		$this-&amp;gt;defaultTime = $this-&amp;gt;pub_after;&lt;br /&gt;
		$this-&amp;gt;defaultInterval = $this-&amp;gt;cron_check;&lt;br /&gt;
&lt;br /&gt;
		// get admin URL&lt;br /&gt;
		$this-&amp;gt;adminUrl = $this-&amp;gt;wire(&amp;#039;config&amp;#039;)-&amp;gt;urls-&amp;gt;admin;&lt;br /&gt;
&lt;br /&gt;
		// add hooks to CRON, PageList, PageEdit&lt;br /&gt;
	    $this-&amp;gt;addHookAfter(&amp;quot;LazyCron::{$this-&amp;gt;defaultInterval}&amp;quot;, $this, &amp;#039;publishDefferedPages&amp;#039;);&lt;br /&gt;
		$this-&amp;gt;addHook(&amp;quot;ProcessPageListActions::getExtraActions&amp;quot;, $this, &amp;#039;hookPageListActions&amp;#039;);&lt;br /&gt;
		$this-&amp;gt;addHookAfter(&amp;quot;ProcessPageEdit::buildForm&amp;quot;, $this, &amp;quot;editForm&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function ready() {&lt;br /&gt;
&lt;br /&gt;
		// if list button clicked then grab id&lt;br /&gt;
		$this-&amp;gt;pagePubLater = $this-&amp;gt;input-&amp;gt;get($this-&amp;gt;listPageName);&lt;br /&gt;
		$this-&amp;gt;pageID = $this-&amp;gt;input-&amp;gt;id;&lt;br /&gt;
&lt;br /&gt;
		// get page&lt;br /&gt;
		$this-&amp;gt;currentPage = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;pageID);&lt;br /&gt;
&lt;br /&gt;
		// if pagelist pub later submit button clicked&lt;br /&gt;
		if($this-&amp;gt;pagePubLater){&lt;br /&gt;
			$this-&amp;gt;message(&amp;quot;Page {$this-&amp;gt;currentPage-&amp;gt;name} deffered for publish.&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if page edit submit button clicked&lt;br /&gt;
		$this-&amp;gt;postPubLater = $this-&amp;gt;input-&amp;gt;post($this-&amp;gt;submitName);&lt;br /&gt;
		if($this-&amp;gt;postPubLater){&lt;br /&gt;
			$this-&amp;gt;message(&amp;quot;Page {$this-&amp;gt;currentPage-&amp;gt;name} deffered for publish.&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if either deffered publish sumbit found then publish page later&lt;br /&gt;
		if($this-&amp;gt;pagePubLater || $this-&amp;gt;postPubLater){&lt;br /&gt;
			$this-&amp;gt;publishLater();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	*	Hook: ProcessPageEdit::buildForm&lt;br /&gt;
	*&lt;br /&gt;
	*	add Publish Later button to edit page if not yet published&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___editForm(HookEvent $form) {&lt;br /&gt;
&lt;br /&gt;
		// get the InputFieldForm object from the event (return value of buildForm())&lt;br /&gt;
		$form = $form-&amp;gt;return;&lt;br /&gt;
&lt;br /&gt;
		$page = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;input-&amp;gt;get-&amp;gt;id);&lt;br /&gt;
		$check = $page-&amp;gt;get($this-&amp;gt;checkboxName);&lt;br /&gt;
&lt;br /&gt;
		// check if publish button available and therfore unpublished&lt;br /&gt;
		$target = $form-&amp;gt;get(&amp;#039;submit_publish&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
		if($target &amp;amp;&amp;amp; $check == false){&lt;br /&gt;
&lt;br /&gt;
			// get InputfieldText module&lt;br /&gt;
			$submit2 = $this-&amp;gt;modules-&amp;gt;get(&amp;#039;InputfieldSubmit&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;name&amp;#039;, $this-&amp;gt;submitName);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;id&amp;#039;, &amp;#039;publish_later&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;class&amp;#039;, &amp;#039;ui-button ui-widget ui-corner-all head_button_clone ui-state-default ui-priority-secondary&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;value&amp;#039;, &amp;#039;Publish Later&amp;#039;); // Button: save unpublished&lt;br /&gt;
&lt;br /&gt;
			// get form element save and place before&lt;br /&gt;
			$target = $form-&amp;gt;get(&amp;#039;submit_save&amp;#039;);&lt;br /&gt;
			$form-&amp;gt;insertBefore($submit2, $target);&lt;br /&gt;
&lt;br /&gt;
			$form-&amp;gt;return = $form;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function ___hookPageListActions(HookEvent $event) {&lt;br /&gt;
&lt;br /&gt;
		// get current page&lt;br /&gt;
		$page = $event-&amp;gt;arguments[0];&lt;br /&gt;
&lt;br /&gt;
		// check to see if page is published&lt;br /&gt;
		$pagePub = $page-&amp;gt;is(Page::statusUnpublished);&lt;br /&gt;
&lt;br /&gt;
		// check to see if page template has deffered field&lt;br /&gt;
		$pageHasDefferField = $page-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
&lt;br /&gt;
		$actions = array();&lt;br /&gt;
&lt;br /&gt;
		// don&amp;#039;t get homepage or pages that are already published or are being deffered for publish&lt;br /&gt;
		if($page-&amp;gt;id &amp;gt; 1 &amp;amp;&amp;amp; $pagePub == &amp;quot;published&amp;quot; &amp;amp;&amp;amp; !is_null($pageHasDefferField) &amp;amp;&amp;amp; $page-&amp;gt;get($this-&amp;gt;checkboxName) == false) {&lt;br /&gt;
&lt;br /&gt;
			$actions[&amp;#039;publish_later&amp;#039;] = array(&lt;br /&gt;
				&amp;#039;cn&amp;#039;   =&amp;gt; &amp;#039;PublishLater&amp;#039;,&lt;br /&gt;
				&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;pub later&amp;#039;,&lt;br /&gt;
				&amp;#039;url&amp;#039;  =&amp;gt; &amp;quot;{$this-&amp;gt;adminUrl}?{$this-&amp;gt;listPageName}=1&amp;amp;id={$page-&amp;gt;id}&amp;quot;,&lt;br /&gt;
			);&lt;br /&gt;
		}&lt;br /&gt;
		if(count($actions)) $event-&amp;gt;return = $actions + $event-&amp;gt;return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Publish Page on cron job&lt;br /&gt;
	*&lt;br /&gt;
	* Gets deffered page and publishes&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___publish($page) {&lt;br /&gt;
		$page-&amp;gt;removeStatus(Page::statusUnpublished);&lt;br /&gt;
		$page-&amp;gt;removeStatus(Page::statusHidden);&lt;br /&gt;
		$page-&amp;gt;Save();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Main publish later function&lt;br /&gt;
	*&lt;br /&gt;
	* Gets deffered page and sets fields to be checked be lazy cron&lt;br /&gt;
	*/&lt;br /&gt;
	private function ___publishLater() {&lt;br /&gt;
&lt;br /&gt;
		// get page&lt;br /&gt;
		$page = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;pageID);&lt;br /&gt;
&lt;br /&gt;
		// set output formatting to false&lt;br /&gt;
		$page-&amp;gt;of(false);&lt;br /&gt;
&lt;br /&gt;
		//  set field time to settings default time and checkbox to true&lt;br /&gt;
		$page-&amp;gt;set($this-&amp;gt;checkboxName, true);&lt;br /&gt;
		$page-&amp;gt;set($this-&amp;gt;fieldName, $this-&amp;gt;defaultTime);&lt;br /&gt;
&lt;br /&gt;
		// save page&lt;br /&gt;
		$page-&amp;gt;save();&lt;br /&gt;
		$page-&amp;gt;of(true);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Lazy Cron hook function&lt;br /&gt;
	*&lt;br /&gt;
	* Triggers every [set time interval] and checks pages&lt;br /&gt;
	* Publishes page if time runout&lt;br /&gt;
	*&lt;br /&gt;
	* Adds publish page log&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___publishDefferedPages(HookEvent $e){&lt;br /&gt;
&lt;br /&gt;
		// seconds since last lazycron&lt;br /&gt;
		$seconds = $e-&amp;gt;arguments[0];&lt;br /&gt;
&lt;br /&gt;
		// find all pages with deffered field&lt;br /&gt;
		$defferedPages = $this-&amp;gt;pages-&amp;gt;find(&amp;quot;{$this-&amp;gt;checkboxName}=1,include=unpublished&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		// for each page decrease time for deffered field&lt;br /&gt;
		foreach ($defferedPages as $page) {&lt;br /&gt;
&lt;br /&gt;
			// get current page time&lt;br /&gt;
			$timeTillPublish = $page-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
&lt;br /&gt;
			// set time to time minus time past&lt;br /&gt;
			$timeLeft = $timeTillPublish - $seconds;&lt;br /&gt;
&lt;br /&gt;
			// if time passed 0 or less then publish page&lt;br /&gt;
			$page-&amp;gt;of(false);&lt;br /&gt;
			if($timeLeft &amp;lt;= 0){&lt;br /&gt;
				// remove flags and save&lt;br /&gt;
				$this-&amp;gt;publish($page);&lt;br /&gt;
&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;fieldName, 0);&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;checkboxName, 0);&lt;br /&gt;
&lt;br /&gt;
				// log a page has been published&lt;br /&gt;
				$log = wire(&amp;#039;log&amp;#039;);&lt;br /&gt;
				$log-&amp;gt;message(&amp;#039;CRON:&amp;#039;. $seconds .&amp;#039; Pages: &amp;#039;. $page-&amp;gt;name .&amp;#039; published&amp;#039;);&lt;br /&gt;
			}else{&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;fieldName, $timeLeft);&lt;br /&gt;
			}&lt;br /&gt;
			// save page time&lt;br /&gt;
			$page-&amp;gt;Save();&lt;br /&gt;
			$page-&amp;gt;of(true);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Install new module specific fields&lt;br /&gt;
	*/&lt;br /&gt;
	private function installFields(){&lt;br /&gt;
&lt;br /&gt;
		// install pub later checkbox field&lt;br /&gt;
		// find installed fields&lt;br /&gt;
		$f = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
		if($f){&lt;br /&gt;
&lt;br /&gt;
			// if field already found then don&amp;#039;t try and make it&lt;br /&gt;
			$this-&amp;gt;message($this-&amp;gt;fieldName . &amp;#039; field found&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
		}else{&lt;br /&gt;
&lt;br /&gt;
			// create new field object to store crontime&lt;br /&gt;
			$f = new Field();&lt;br /&gt;
			// get a field type&lt;br /&gt;
			$f-&amp;gt;type = $this-&amp;gt;modules-&amp;gt;get(&amp;quot;FieldtypeInteger&amp;quot;);&lt;br /&gt;
			$f-&amp;gt;name = $this-&amp;gt;fieldName;&lt;br /&gt;
			$f-&amp;gt;label = &amp;#039;Publish Time Left&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;defaultValue = $this-&amp;gt;defaultTime;&lt;br /&gt;
			$f-&amp;gt;icon = &amp;#039;clock-o&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;columnWidth = 50;&lt;br /&gt;
			$f-&amp;gt;collapsed = 1;&lt;br /&gt;
			$f-&amp;gt;flags = 4;&lt;br /&gt;
&lt;br /&gt;
			$f-&amp;gt;save(); // save the field&lt;br /&gt;
&lt;br /&gt;
			// create new field object to store whether to publish or not&lt;br /&gt;
			$f = new Field();&lt;br /&gt;
			// get a field type&lt;br /&gt;
			$f-&amp;gt;type = $this-&amp;gt;modules-&amp;gt;get(&amp;quot;FieldtypeCheckbox&amp;quot;);&lt;br /&gt;
			$f-&amp;gt;name = $this-&amp;gt;checkboxName;&lt;br /&gt;
			$f-&amp;gt;label = &amp;#039;Publish Page later&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;defaultValue = false;&lt;br /&gt;
			$f-&amp;gt;columnWidth = 50;&lt;br /&gt;
			$f-&amp;gt;icon = &amp;#039;clock-o&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;collapsed = 1;&lt;br /&gt;
			$f-&amp;gt;flags = 4;&lt;br /&gt;
&lt;br /&gt;
			$f-&amp;gt;save(); // save the field&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Uninstall module specific fields&lt;br /&gt;
	*/&lt;br /&gt;
	private function uninstallFields(){&lt;br /&gt;
&lt;br /&gt;
		// find installed fields&lt;br /&gt;
		$fInt = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
		$fCheck = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;checkboxName);&lt;br /&gt;
&lt;br /&gt;
		if($fInt &amp;amp;&amp;amp; $fCheck){&lt;br /&gt;
			$fieldIntUsed = $fInt-&amp;gt;numFieldgroups();&lt;br /&gt;
			$fieldCheckUsed = $fCheck-&amp;gt;numFieldgroups();&lt;br /&gt;
&lt;br /&gt;
			if($fieldIntUsed){&lt;br /&gt;
				// field in use by template&lt;br /&gt;
				$this-&amp;gt;message(&amp;#039;Unable to uninstall field &amp;#039;.$fInt-&amp;gt;name);&lt;br /&gt;
			}else{&lt;br /&gt;
				// delete installed fields&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;delete($fInt);&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;save;&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			if($fieldCheckUsed){&lt;br /&gt;
				// field in use by template&lt;br /&gt;
				$this-&amp;gt;message(&amp;#039;Unable to uninstall field &amp;#039;.$fCheck-&amp;gt;name);&lt;br /&gt;
			}else{&lt;br /&gt;
				// delete installed fields&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;delete($fCheck);&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;save;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Inputfield / Fieldtype ===&lt;br /&gt;
[[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei statt getModuleInfo ===&lt;br /&gt;
Bei größeren Konfigruation (z.B. Admin Page Navigation) sinnvoll.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * ProcessHello.info.php&lt;br /&gt;
 * &lt;br /&gt;
 * Return information about this module.&lt;br /&gt;
 *&lt;br /&gt;
 * If preferred, you can use a getModuleInfo() method in your module file, &lt;br /&gt;
 * or you can use a ModuleName.info.json file (if you prefer JSON definition). &lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
$info = array(&lt;br /&gt;
	// Your module&amp;#039;s title&lt;br /&gt;
	&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello: Process Module Example&amp;#039;, &lt;br /&gt;
	// A 1 sentence description of what your module does&lt;br /&gt;
	&amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;A starting point module skeleton from which to build your own Process module.&amp;#039;, &lt;br /&gt;
	// Module version number: use 1 for 0.0.1 or 100 for 1.0.0, and so on&lt;br /&gt;
	&amp;#039;version&amp;#039; =&amp;gt; 1, &lt;br /&gt;
	// Name of person who created this module (change to your name)&lt;br /&gt;
	&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ryan Cramer&amp;#039;, &lt;br /&gt;
	// Icon to accompany this module (optional), uses font-awesome icon names, minus the &amp;quot;fa-&amp;quot; part&lt;br /&gt;
	&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;thumbs-up&amp;#039;, &lt;br /&gt;
	// URL to more info: change to your full modules.processwire.com URL (if available), or something else if you prefer&lt;br /&gt;
	&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;http://modules.processwire.com/&amp;#039;, &lt;br /&gt;
	// name of permission required of users to execute this Process (optional)&lt;br /&gt;
	&amp;#039;permission&amp;#039; =&amp;gt; &amp;#039;helloworld&amp;#039;, &lt;br /&gt;
	// permissions that you want automatically installed/uninstalled with this module (name =&amp;gt; description)&lt;br /&gt;
	&amp;#039;permissions&amp;#039; =&amp;gt; array(&lt;br /&gt;
		&amp;#039;helloworld&amp;#039; =&amp;gt; &amp;#039;Run the HelloWorld module&amp;#039;&lt;br /&gt;
	), &lt;br /&gt;
	&lt;br /&gt;
	// page that you want created to execute this module&lt;br /&gt;
	&amp;#039;page&amp;#039; =&amp;gt; array(&lt;br /&gt;
		&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;helloworld&amp;#039;,&lt;br /&gt;
		&amp;#039;parent&amp;#039; =&amp;gt; &amp;#039;setup&amp;#039;, &lt;br /&gt;
		&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello World&amp;#039;&lt;br /&gt;
	),&lt;br /&gt;
	// optional extra navigation that appears in admin&lt;br /&gt;
	// if you change this, you&amp;#039;ll need to a Modules &amp;gt; Refresh to see changes&lt;br /&gt;
	&amp;#039;nav&amp;#039; =&amp;gt; array(&lt;br /&gt;
		array(&lt;br /&gt;
			&amp;#039;url&amp;#039; =&amp;gt; &amp;#039;&amp;#039;, &lt;br /&gt;
			&amp;#039;label&amp;#039; =&amp;gt; &amp;#039;Hello&amp;#039;, &lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;smile-o&amp;#039;, &lt;br /&gt;
		), &lt;br /&gt;
		array(&lt;br /&gt;
			&amp;#039;url&amp;#039; =&amp;gt; &amp;#039;something/&amp;#039;, &lt;br /&gt;
			&amp;#039;label&amp;#039; =&amp;gt; &amp;#039;Something&amp;#039;, &lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;beer&amp;#039;, &lt;br /&gt;
		),&lt;br /&gt;
	)&lt;br /&gt;
	// for more options that you may specify here, see the file: /wire/core/Process.php&lt;br /&gt;
	// and the file: /wire/core/Module.php&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interessantes - Read On ==&lt;br /&gt;
 https://processwire.com/talk/topic/24067-solved-settings-fields-that-dont-save-to-database/&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Module_schreiben&amp;diff=24849</id>
		<title>ProcessWire - Module schreiben</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Module_schreiben&amp;diff=24849"/>
		<updated>2020-11-04T20:12:52Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: /* getModuleInfo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Wichtigste Resourcen&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 https://processwire.com/docs/modules/development/ - Guter Ausgangspunkt&lt;br /&gt;
 https://processwire.com/api/ref/module/ - Module API&lt;br /&gt;
 https://processwire.com/api/ref/configurable-module/ - Klasse für Konfigurierbare Module&lt;br /&gt;
 https://processwire.com/docs/modules/types/ - Welche Modultypen gibt es ?&lt;br /&gt;
 https://processwire.com/talk/topic/778-module-dependencies/ - Module die andere Module benötigen&lt;br /&gt;
 https://processwire.com/talk/forum/19-moduleplugin-development/ - Forum zum Thema Module entwickeln&lt;br /&gt;
 http://somatonic.github.io/Captain-Hook/ - Hook Cheatsheet&lt;br /&gt;
 https://processwire.com/blog/posts/new-module-configuration-options/ - Neuere Konfigurationsmöglichkeiten&lt;br /&gt;
 https://processwire.com/docs/start/api-access/ Zugriff auf ProcessWire API Variablen (wire Objekt)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039; Tutorials und Beispiele zum Einstieg &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 https://processwire.com/docs/modules/ - Introduction, Development, Hooks, Types, Pro Modules, Third Party&lt;br /&gt;
 https://github.com/ryancramerdesign/ProcessHello - Modul Skelett Beispiel für eigene Backend (Process) Module&lt;br /&gt;
 https://github.com/ryancramerdesign/FieldtypeMapMarker - Beispiel für ein Fieldtype und Inputfield Modul&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/a-beginners-introduction-to-writing-modules-in-processwire--cms-26862&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Wikiseiten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 [[ProcessWire - Module Snippets]]&lt;br /&gt;
 [[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Weitere Links&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 http://modules.pw/ (Module Creator)&lt;br /&gt;
&lt;br /&gt;
== Wo - Was ? ==&lt;br /&gt;
=== Welche Typen von Modulen gibt es ? ===&lt;br /&gt;
 https://processwire.com/docs/modules/types/&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Fieldtype&amp;#039;&amp;#039;&amp;#039;: Repräsentiert einen Datentyp. Meistens keine Public API, Handelt Daten / Datenbank - [[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Inputfield&amp;#039;&amp;#039;&amp;#039;: Sammelt User Eingaben über ein Formular im Admin Bereich. Im Gegensatz zum Fieldtype geht es hier um das UI im Backend. Das Handling der Daten liegt beim Fieldtype.&lt;br /&gt;
* [[Process Module (ProcessWire)|&amp;#039;&amp;#039;&amp;#039;Process&amp;#039;&amp;#039;&amp;#039; for creating admin processes/applications.]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Textformatter&amp;#039;&amp;#039;&amp;#039; for formatting text.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminTheme&amp;#039;&amp;#039;&amp;#039; for creating themes in the admin.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;WireMail&amp;#039;&amp;#039;&amp;#039; for modules that send email and extend the WireMail class.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tfa&amp;#039;&amp;#039;&amp;#039; for implementing a specific kind of two-factor authentication.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ImageSizerEngine&amp;#039;&amp;#039;&amp;#039; for modules that extend ImageSizerEngine for resizing images.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FileCompiler&amp;#039;&amp;#039;&amp;#039; for modules that extend FileCompilerModule for compilation of files.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FileValidator&amp;#039;&amp;#039;&amp;#039; for modules that extend FileValidatorModule for validation of files.&lt;br /&gt;
&lt;br /&gt;
=== Wie werden Felder in der Datenbank angelegt ? ===&lt;br /&gt;
Dazu nutzt man den Typ &amp;quot;Fieldtype&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Wo rendert man die Ausgabe ? ===&lt;br /&gt;
Bei Ryan Cramers Event Beispiel legt er zwei Klassen Event und EventArray an, die auch die Render Funktionen enthalten.&lt;br /&gt;
&lt;br /&gt;
=== Namenskonventionen ===&lt;br /&gt;
Ein Modulname sollte mit dem Typ den das Modul hat beginnen. Also etwa ProcessMeinAdminModul oder FieldtypeTable. ProcessWire listet das Modul dann in der Entsprechenden Kategorie auf. Wenn man etwas anderes nimmt z.B. LoginRegister dann kommt das Modul unter der neuen Rubrik &amp;quot;Login&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurierbare Module ===&lt;br /&gt;
Das geht seit 2.5.5 mittlerweile sehr einfach mit den neuen configuration-options.&lt;br /&gt;
 https://processwire.com/blog/posts/new-module-configuration-options/&lt;br /&gt;
 [[ProcessWire - Konfigurierbare Module]]&lt;br /&gt;
&lt;br /&gt;
== Spezielle Funktionen in Modulen ==&lt;br /&gt;
&lt;br /&gt;
=== Modulinformation ===&lt;br /&gt;
Das Modul stellt Infos zur Verfügung und nutzt dafür eine von 3 Methoden:&lt;br /&gt;
    getModuleInfo() static method in your module class that returns an array.&lt;br /&gt;
    YourModuleClass.info.php file that populates an $info array.&lt;br /&gt;
    YourModuleClass.info.json file that contains an info object.&lt;br /&gt;
&lt;br /&gt;
Hier werden title, version, summary und weitere Daten hinterlegt. Hier kann man auch angeben ob ein Modul ein Autoload Modul ist.&lt;br /&gt;
&lt;br /&gt;
 https://processwire.com/api/ref/module/&lt;br /&gt;
&lt;br /&gt;
=== init ===&lt;br /&gt;
 public function init(){}&lt;br /&gt;
Initialisiert das Modul. ProcessWire ruft diese Funktion auf, wenn das Modul geladen ist. Bei Autoload Modulen wird es aufgerufen wenn die ProcessWire API bereit ist. Daher ist es ein guter Ort um Hooks einzubinden.&lt;br /&gt;
&lt;br /&gt;
=== ready ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  public function ready() {&lt;br /&gt;
    if($this-&amp;gt;page-&amp;gt;template == &amp;#039;admin&amp;#039;) {&lt;br /&gt;
      $this-&amp;gt;message($this-&amp;gt;hi());&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird in autoload Modulen aufgerufen wenn die API bereit ist. Nützlich für Hooks:&lt;br /&gt;
&lt;br /&gt;
=== execute ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	/**&lt;br /&gt;
	 * This function is executed when a page with your Process assigned is accessed. &lt;br /&gt;
 	 *&lt;br /&gt;
	 * This can be seen as your main or index function. You&amp;#039;ll probably want to replace&lt;br /&gt;
	 * everything in this function. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___execute() {&lt;br /&gt;
		// greetingType and greeting are automatically populated to this module&lt;br /&gt;
		// and they were defined in ProcessHello.config.php&lt;br /&gt;
		if($this-&amp;gt;greetingType == &amp;#039;message&amp;#039;) {&lt;br /&gt;
			$this-&amp;gt;message($this-&amp;gt;greeting); &lt;br /&gt;
		} else if($this-&amp;gt;greetingType == &amp;#039;warning&amp;#039;) {&lt;br /&gt;
			$this-&amp;gt;warning($this-&amp;gt;greeting); &lt;br /&gt;
		} else {&lt;br /&gt;
			$this-&amp;gt;error($this-&amp;gt;greeting); &lt;br /&gt;
		}&lt;br /&gt;
		// generate some navigation&lt;br /&gt;
		$out = 	&amp;quot;&lt;br /&gt;
			&amp;lt;h2&amp;gt;$this-&amp;gt;greeting&amp;lt;/h2&amp;gt;&lt;br /&gt;
			&amp;lt;dl class=&amp;#039;nav&amp;#039;&amp;gt;&lt;br /&gt;
				&amp;lt;dt&amp;gt;&amp;lt;a href=&amp;#039;./something/&amp;#039;&amp;gt;Do Something&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;&lt;br /&gt;
				&amp;lt;dd&amp;gt;Runs the executeSomething() function.&amp;lt;/dd&amp;gt;&lt;br /&gt;
			&amp;lt;/dl&amp;gt;&lt;br /&gt;
			&amp;quot;;&lt;br /&gt;
		return $out;&lt;br /&gt;
	}	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== executeSomething ===&lt;br /&gt;
Ruft man eine Unterseite des Moduls auf kann man eine eigene execute Funktion nutzen&lt;br /&gt;
___executeSlug wobei Slug für den Url Slug steht. Heißt der slug /field/ dann wird executeField() aufgerufen, falls diese Funktion existiert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	/**&lt;br /&gt;
	 * Called when the URL is this module&amp;#039;s page URL + &amp;quot;/something/&amp;quot;&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___executeSomething() {&lt;br /&gt;
		// set a new headline, replacing the one used by our page&lt;br /&gt;
		// this is optional as PW will auto-generate a headline &lt;br /&gt;
		$this-&amp;gt;headline(&amp;#039;This is something!&amp;#039;); &lt;br /&gt;
		// add a breadcrumb that returns to our main page &lt;br /&gt;
		// this is optional as PW will auto-generate breadcrumbs&lt;br /&gt;
		$this-&amp;gt;breadcrumb(&amp;#039;../&amp;#039;, &amp;#039;Hello&amp;#039;); &lt;br /&gt;
		$out = 	&amp;quot;&lt;br /&gt;
			&amp;lt;h2&amp;gt;Not much to to see here&amp;lt;/h2&amp;gt;&lt;br /&gt;
			&amp;lt;p&amp;gt;&amp;lt;a href=&amp;#039;../&amp;#039;&amp;gt;Go Back&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
			&amp;quot;;&lt;br /&gt;
		return $out; &lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== install &amp;amp; uninstall ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
	 * Called only when your module is installed&lt;br /&gt;
	 *&lt;br /&gt;
	 * If you don&amp;#039;t need anything here, you can simply remove this method. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___install() {&lt;br /&gt;
		parent::___install(); // always remember to call parent method&lt;br /&gt;
	}&lt;br /&gt;
	/**&lt;br /&gt;
	 * Called only when your module is uninstalled&lt;br /&gt;
	 *&lt;br /&gt;
	 * This should return the site to the same state it was in before the module was installed. &lt;br /&gt;
	 *&lt;br /&gt;
	 * If you don&amp;#039;t need anything here, you can simply remove this method. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___uninstall() {&lt;br /&gt;
		parent::___uninstall(); // always remember to call parent method&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vererbung und Eigenschaften in Modulen ==&lt;br /&gt;
Modules are not different from PHP classes.&lt;br /&gt;
&lt;br /&gt;
To change the properties of MyModule class from within MyOtherModule class, you can either:&lt;br /&gt;
&lt;br /&gt;
#Make MyOtherModule class extend MyModule. It will thus inherit MyModule&amp;#039;s public and protected properties and methods&lt;br /&gt;
#Make the properties firstName and lastName configurable by passing them as parameters/arguments in MyModule&amp;#039;s constructor method.&lt;br /&gt;
&lt;br /&gt;
== Autoload Module und Hooks ==&lt;br /&gt;
Autoload werden automatisch geladen müssen also nicht in einem Template o.ä. gestartet werden. Daher bieten sie sich an um die Funktionalität von ProcessWire zu erweitern. Als Werkzeug dafür dienen Hooks. Mit Hooks kann man an vielen Stellen den Rendering Process der Seiten beeinflussen. Außerdem kann man für eigene Module ebenfalls Hooks bereitstellen. &lt;br /&gt;
&lt;br /&gt;
=== Hooks ===&lt;br /&gt;
 https://processwire.com/docs/modules/hooks/&lt;br /&gt;
Hooks sind ein mächtiges Werkzeug. Sie geben einem die Möglichkeit an vielen Stellen &amp;quot;einzuhaken&amp;quot; und Funktionalität einzubauen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, function($event) {&lt;br /&gt;
    $event-&amp;gt;return .= &amp;#039;&amp;lt;p&amp;gt;Hallo&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Schreibt am Ende Jeder Seite ein &amp;quot;Hallo&amp;quot;. Das $event Objekt ist ein [https://processwire.com/api/ref/hook-event/ HookEvent]. Im Beispiel fügen wir einfach etwas Markup hinzu. Über $event-&amp;gt;arguments() kann man aber auf ale Argumente zugreifen.&lt;br /&gt;
&lt;br /&gt;
Das gleiche aber nicht mit anonymer Funktion:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  // add hook after Page::render() and make it call the &amp;quot;test&amp;quot; method of $this module&lt;br /&gt;
  $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, $this, &amp;#039;test&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public function test($event) {&lt;br /&gt;
  // modify the return value of Page::render() to include the following:&lt;br /&gt;
  $event-&amp;gt;return .= &amp;#039;&amp;lt;p&amp;gt;Hallo&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hooks zum erweitern von existierenden Klassen nutzen ===&lt;br /&gt;
Mit Hooks kann man in vorhandene Klassen einhaken. Z.B. läßt sich das Page Objekt erweitern.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  $this-&amp;gt;addHook(&amp;#039;Page::summarize&amp;#039;, $this, &amp;#039;summarize&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
public function summarize($event) {&lt;br /&gt;
  $page = $event-&amp;gt;object; // the $event-&amp;gt;object represents the object hooked (Page)&lt;br /&gt;
  $maxlen = $event-&amp;gt;arguments(0); // first argument is the optional max length&lt;br /&gt;
  if(!$maxlen) $maxlen = 200; // if no $maxlen was present, we&amp;#039;ll use a default of 200&lt;br /&gt;
  $summary = $this-&amp;gt;sanitizer-&amp;gt;truncate($page-&amp;gt;body, $maxlen); // use sanitizer truncate method to create a summary&lt;br /&gt;
  $event-&amp;gt;return = $summary; // populate $summary to $event-&amp;gt;return, the return value&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So kann man ganz einfach eine Zusammenfassung aller Kindseiten in einem Template rendern:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
foreach($page-&amp;gt;children as $item) {&lt;br /&gt;
  $summary = $item-&amp;gt;summarize(150);&lt;br /&gt;
  echo &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;$item-&amp;gt;url&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;$summary&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Autoload Module nur im Admin Bereich laden ===&lt;br /&gt;
&lt;br /&gt;
 &amp;#039;autoload&amp;#039; =&amp;gt; &amp;#039;template=admin&amp;#039; &lt;br /&gt;
statt&lt;br /&gt;
 &amp;#039;autoload&amp;#039; =&amp;gt; true&lt;br /&gt;
&lt;br /&gt;
=== Hook Beispiele ===&lt;br /&gt;
Hook am Ende des Renderings&lt;br /&gt;
 $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, function($event) {...});&lt;br /&gt;
Füge eine Funktion &amp;quot;summarize&amp;quot; zum Page Objekt hinzu.&lt;br /&gt;
 $this-&amp;gt;addHook(&amp;#039;Page::summarize&amp;#039;, $this, &amp;#039;summarize&amp;#039;);&lt;br /&gt;
Hook auf eine einzelne Instanz (hier pages Objekt)&lt;br /&gt;
 $this-&amp;gt;pages-&amp;gt;addHookAfter(&amp;#039;saved&amp;#039;, function($event){...});&lt;br /&gt;
 $this-&amp;gt;addHook(&amp;#039;Page::method&amp;#039;, ...) // Spricht ALLE Instanzen an - Regelfall&lt;br /&gt;
 $page-&amp;gt;addHook(&amp;#039;method&amp;#039;, ...) // Spricht nur die EINE Instanz der Seite an.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Module Dependencies - voneinander abhängige Module ==&lt;br /&gt;
&lt;br /&gt;
 https://processwire.com/talk/topic/778-module-dependencies/&lt;br /&gt;
Wenn ein Modul nicht ohne ein anderes funktioniert spricht man von Module Dependency. In solchen Fällen kann man in der Modul Info angeben In vielen Fällen besteht ein Modul unter der Haube aus mehreren Einzelmodulen.&lt;br /&gt;
&lt;br /&gt;
Um ProcessWire mitzuteilen dass ein Modul benötigt wird gibt man es in der Moduldefinition an:&lt;br /&gt;
 &amp;#039;requires&amp;#039; =&amp;gt; &amp;quot;LazyCron&amp;quot;  // added this line&lt;br /&gt;
oder auch mehrere als Array&lt;br /&gt;
 &amp;#039;requires&amp;#039; =&amp;gt; array(&amp;quot;LazyCron&amp;quot;, &amp;quot;AdminBar&amp;quot;)  // added this line&lt;br /&gt;
&lt;br /&gt;
ProcessWire kann auch dafür sorgen, dass ein Modul andere &amp;quot;Kindmodule&amp;quot; gleich mitinstalliert bzw. deinstalliert wenn es nicht mehr benötigt wird. Dazu gibt man dem Modul noch die &amp;#039;install&amp;#039; dependency mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
public static function getModuleInfo() {&lt;br /&gt;
   return array(&lt;br /&gt;
       &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Log Master&amp;#039;,&lt;br /&gt;
       &amp;#039;version&amp;#039; =&amp;gt; 101,&lt;br /&gt;
       &amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Lumberjack Bob&amp;#039;,&lt;br /&gt;
       &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Log all actions on your site&amp;#039;,&lt;br /&gt;
       &amp;#039;requires&amp;#039; =&amp;gt; &amp;#039;LazyCron&amp;#039;, &lt;br /&gt;
       &amp;#039;installs&amp;#039; =&amp;gt; &amp;#039;ProcessLogMaster&amp;#039;  // added this line&lt;br /&gt;
       ); &lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProcessWire sieht dann eine Kindabhängigkeit zu diesem Modul und handelt auch das Deinstallieren, wenn das Elternmodul deinstalliert wird.&lt;br /&gt;
&lt;br /&gt;
== CSS und JavaScript in Modulen ==&lt;br /&gt;
Bei Process Modulen möchte man für das Styling etc. im Backend oft CSS und JS Dateien hinzufügen.&lt;br /&gt;
&lt;br /&gt;
Einfach Eine Datei MeinModul.css und / oder MeinModul.js hinzufügen. JQuery ist im Admin bereits geladen daher kann eine MeinModul.js Starter Datei so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This JS file is only loaded when the ProcessHello module is run&lt;br /&gt;
 *&lt;br /&gt;
 * You should delete it if you have no javascript to add.&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
$(document).ready(function() {&lt;br /&gt;
	// do something&lt;br /&gt;
}); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Frontend Rendering Module ===&lt;br /&gt;
A bit old but working&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * FrontEndRender&lt;br /&gt;
 *&lt;br /&gt;
 * Author: Ben Byford&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2010 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class FrontEndRender extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;FrontEndRender&amp;#039;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 0.1,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;Outputs html and static variables to frontend&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ben Byford&amp;#039;,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://github.com/benbyford/PW-starter-modules&amp;#039;&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// protected variable only accessable within module&lt;br /&gt;
	protected $name = &amp;#039;Ben&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* render function to be called in PW template like this:&lt;br /&gt;
	* $FrontEndRender = $modules-&amp;gt;getModule(&amp;#039;FrontEndRender&amp;#039;);&lt;br /&gt;
	* echo &amp;#039;&amp;lt;h1&amp;gt;&amp;#039; . $FrontEndRender-&amp;gt;render() . &amp;#039;&amp;lt;/h1&amp;gt;&amp;#039;;&lt;br /&gt;
	*&lt;br /&gt;
	*/&lt;br /&gt;
	public function render(){&lt;br /&gt;
		return &amp;quot;Hello &amp;quot; . $this-&amp;gt;name;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Hello World Modul ===&lt;br /&gt;
Beispiel Modul mit Hooks (liegt immer in der Standardinstallation)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * ProcessWire &amp;#039;Hello world&amp;#039; demonstration module&lt;br /&gt;
 *&lt;br /&gt;
 * Demonstrates the Module interface and how to add hooks.&lt;br /&gt;
 * &lt;br /&gt;
 * See README file for further links regarding module development.&lt;br /&gt;
 * &lt;br /&gt;
 * This file is licensed under the MIT license&lt;br /&gt;
 * https://processwire.com/about/license/mit/&lt;br /&gt;
 * &lt;br /&gt;
 * ProcessWire 3.x, Copyright 2016 by Ryan Cramer&lt;br /&gt;
 * https://processwire.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class Helloworld extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * getModuleInfo is a module required by all modules to tell ProcessWire about them&lt;br /&gt;
	 *&lt;br /&gt;
	 * @return array&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
&lt;br /&gt;
		return array(&lt;br /&gt;
&lt;br /&gt;
			// The module&amp;#039;s title, typically a little more descriptive than the class name&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello World&amp;#039;, &lt;br /&gt;
&lt;br /&gt;
			// version number &lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 3, &lt;br /&gt;
&lt;br /&gt;
			// summary is brief description of what this module is&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;An example module used for demonstration purposes.&amp;#039;,&lt;br /&gt;
			&lt;br /&gt;
			// Optional URL to more information about the module&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://processwire.com&amp;#039;,&lt;br /&gt;
&lt;br /&gt;
			// singular=true: indicates that only one instance of the module is allowed.&lt;br /&gt;
			// This is usually what you want for modules that attach hooks. &lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true, &lt;br /&gt;
&lt;br /&gt;
			// autoload=true: indicates the module should be started with ProcessWire.&lt;br /&gt;
			// This is necessary for any modules that attach runtime hooks, otherwise those&lt;br /&gt;
			// hooks won&amp;#039;t get attached unless some other code calls the module on it&amp;#039;s own.&lt;br /&gt;
			// Note that autoload modules are almost always also &amp;#039;singular&amp;#039; (seen above).&lt;br /&gt;
			&amp;#039;autoload&amp;#039; =&amp;gt; true, &lt;br /&gt;
		&lt;br /&gt;
			// Optional font-awesome icon name, minus the &amp;#039;fa-&amp;#039; part&lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;smile-o&amp;#039;, &lt;br /&gt;
			);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Initialize the module&lt;br /&gt;
	 *&lt;br /&gt;
	 * ProcessWire calls this when the module is loaded. For &amp;#039;autoload&amp;#039; modules, this will be called&lt;br /&gt;
	 * when ProcessWire&amp;#039;s API is ready. As a result, this is a good place to attach hooks. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function init() {&lt;br /&gt;
&lt;br /&gt;
		// add a hook after the $pages-&amp;gt;save, to issue a notice every time a page is saved&lt;br /&gt;
		$this-&amp;gt;pages-&amp;gt;addHookAfter(&amp;#039;save&amp;#039;, $this, &amp;#039;example1&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a hook after each page is rendered and modify the output&lt;br /&gt;
		$this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, $this, &amp;#039;example2&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a &amp;#039;hello&amp;#039; method to every page that returns &amp;quot;Hello World&amp;quot;&lt;br /&gt;
		// use &amp;quot;echo $page-&amp;gt;hello();&amp;quot; in your template file to display output&lt;br /&gt;
		$this-&amp;gt;addHook(&amp;#039;Page::hello&amp;#039;, $this, &amp;#039;example3&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a &amp;#039;hello_world&amp;#039; property to every page that returns &amp;quot;Hello [user]&amp;quot;&lt;br /&gt;
		// use &amp;quot;echo $page-&amp;gt;hello_world;&amp;quot; in your template file to display output&lt;br /&gt;
		$this-&amp;gt;addHookProperty(&amp;#039;Page::hello_world&amp;#039;, $this, &amp;#039;example4&amp;#039;); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example1 hooks into the pages-&amp;gt;save method and displays a notice every time a page is saved&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example1($event) {&lt;br /&gt;
		/** @var Page $page */&lt;br /&gt;
		$page = $event-&amp;gt;arguments[0]; &lt;br /&gt;
		$this-&amp;gt;message(&amp;quot;Hello World! You saved {$page-&amp;gt;path}.&amp;quot;); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example2 hooks into every page after it&amp;#039;s rendered and adds &amp;quot;Hello World&amp;quot; text at the bottom&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example2($event) {&lt;br /&gt;
&lt;br /&gt;
		/** @var Page $page */&lt;br /&gt;
		$page = $event-&amp;gt;object; &lt;br /&gt;
&lt;br /&gt;
		// don&amp;#039;t add this to the admin pages&lt;br /&gt;
		if($page-&amp;gt;template == &amp;#039;admin&amp;#039;) return;&lt;br /&gt;
&lt;br /&gt;
		// add a &amp;quot;Hello World&amp;quot; paragraph right before the closing body tag&lt;br /&gt;
		$event-&amp;gt;return = str_replace(&amp;quot;&amp;lt;/body&amp;gt;&amp;quot;, &amp;quot;&amp;lt;p&amp;gt;Hello World!&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;quot;, $event-&amp;gt;return); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example3 adds a &amp;#039;hello&amp;#039; method (not property) to every page that simply returns &amp;quot;Hello World&amp;quot;&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example3($event) {&lt;br /&gt;
		$event-&amp;gt;return = &amp;quot;Hello World&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example 4 adds a &amp;#039;hello_world&amp;#039; property (not method) to every page that returns &amp;quot;Hello [user]&amp;quot;&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example4($event) {&lt;br /&gt;
		$event-&amp;gt;return = &amp;quot;Hello &amp;quot; . $this-&amp;gt;user-&amp;gt;name; &lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Admin Bereich mit eigener Funktionalität erweitern (Modul)===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
* ProcessSimpleAdminPage&lt;br /&gt;
*&lt;br /&gt;
* @author Ben Byford&lt;br /&gt;
* http://www.benbyford.com&lt;br /&gt;
*&lt;br /&gt;
* @see http://www.processwire.com&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
class ProcessSimpleAdminPage extends Process {&lt;br /&gt;
&lt;br /&gt;
    public static function getModuleInfo() {&lt;br /&gt;
        return array(&lt;br /&gt;
            &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Process Simple Admin Page&amp;#039;,&lt;br /&gt;
            &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Simple Process module that adds new admin page with&amp;#039;,&lt;br /&gt;
            &amp;#039;version&amp;#039; =&amp;gt; 001,&lt;br /&gt;
&lt;br /&gt;
            // Modules that extend Process may specify a &amp;#039;page&amp;#039; attribute in the&lt;br /&gt;
            // getModuleInfo(), this page will automatically be given the module&lt;br /&gt;
            // process when added to teh pagetree.&lt;br /&gt;
&lt;br /&gt;
            // I have exampled but commented out the &amp;#039;page&amp;#039; settings below&lt;br /&gt;
            // so that I can show how one might add a page to install() and&lt;br /&gt;
            // uninstall() in this and other modules (that might not extend&lt;br /&gt;
            // Process)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        // 	&amp;#039;page&amp;#039; =&amp;gt; array(&lt;br /&gt;
        // 		&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;site-config&amp;#039;,&lt;br /&gt;
        // 		&amp;#039;parent&amp;#039; =&amp;gt; &amp;#039;admin&amp;#039;,&lt;br /&gt;
        // 		&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Site Config&amp;#039;&lt;br /&gt;
        // 	   )&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function execute() {&lt;br /&gt;
        return &amp;#039;&lt;br /&gt;
            &amp;lt;h2&amp;gt;Edit the text here in the module&amp;lt;/h2&amp;gt;&lt;br /&gt;
            &amp;lt;p&amp;gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mattis eros vitae metus sodales eget suscipit purus rhoncus. Proin ultrices gravida dolor, non porttitor enim interdum vitae. Integer feugiat lacinia tincidunt. Nulla laoreet tristique tristique. Sed elementum justo a nisl elementum sit amet accumsan nisi tempor. Nulla quis eros et massa dignissim imperdiet a vitae purus.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Donec scelerisque pulvinar sem eu lobortis. Maecenas turpis ipsum, tempus dictum pharetra eu, consectetur vitae arcu. Fusce orci mauris, semper at tempus quis, volutpat molestie tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed quam tortor, tincidunt sed semper lacinia, scelerisque dapibus quam. Morbi at nisi luctus lacus auctor ultrices eu eu leo.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Praesent faucibus purus id felis tincidunt dignissim. Sed sit amet ligula mi, eget semper dui. Proin consectetur gravida massa, nec luctus purus hendrerit in. Etiam volutpat, elit non venenatis suscipit, libero neque consectetur diam, id rutrum magna odio ac ligula. Maecenas sollicitudin congue neque fermentum vestibulum. Morbi nec leo nisi. Donec at nisl odio, et porta ligula.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Sed quis arcu nisi, ac tempor augue. Praesent non elit libero, a ullamcorper lorem. Curabitur porta odio eu nunc ultricies interdum id nec risus. Donec nibh nibh, porta eget vehicula ac, aliquet eget ante. Phasellus eget lorem eu eros eleifend ultrices. Cras sit amet neque sit amet nibh fringilla cursus ut id mauris. Praesent quis nunc justo, sed suscipit lectus. Phasellus eget ultrices risus. Curabitur eu semper est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut suscipit, nisl ut imperdiet eleifend, turpis arcu placerat tortor, nec laoreet lacus neque ac tellus. Aenean ac lacus justo, quis ultricies nisi.&amp;lt;/p&amp;gt;&lt;br /&gt;
            &amp;#039;;&lt;br /&gt;
    }&lt;br /&gt;
    public function install(){&lt;br /&gt;
&lt;br /&gt;
        // create new page to add to CMS&lt;br /&gt;
		$page = new Page();&lt;br /&gt;
&lt;br /&gt;
        // add page attributes&lt;br /&gt;
        $page-&amp;gt;template = &amp;quot;admin&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;name = &amp;quot;cms-faq&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;title = &amp;quot;CMS FAQ&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;save();&lt;br /&gt;
&lt;br /&gt;
        // set this module as the page process, this allows us to display the above&lt;br /&gt;
        $page-&amp;gt;process = &amp;#039;ProcessSimpleAdminPage&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
        // get admin page and set as page parent&lt;br /&gt;
        $admin = $this-&amp;gt;pages-&amp;gt;get(&amp;quot;id=2&amp;quot;);&lt;br /&gt;
        $page-&amp;gt;parent = $admin;&lt;br /&gt;
&lt;br /&gt;
        // save page&lt;br /&gt;
        $page-&amp;gt;save();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function uninstall(){&lt;br /&gt;
&lt;br /&gt;
        // delete created page&lt;br /&gt;
        $page = $this-&amp;gt;pages-&amp;gt;get(&amp;quot;name=cms-faq&amp;quot;);&lt;br /&gt;
        if(count($page)) $this-&amp;gt;pages-&amp;gt;delete($page, true);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Textformatter Modul ===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * TextformatterFindReplace&lt;br /&gt;
 *&lt;br /&gt;
 * Author: Ben Byford&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2010 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class TextformatterFindReplace extends Textformatter implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;TextformatterFindReplace&amp;#039;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 0.1,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;Finds and replaces any instance of config input to config output&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ben Byford&amp;#039;,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://github.com/benbyford/PW-starter-modules&amp;#039;&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
     * Find and Replace the input string&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $str The block of text to parse&lt;br /&gt;
     *&lt;br /&gt;
     * The incoming string is replaced with the formatted version of itself.&lt;br /&gt;
	 **/&lt;br /&gt;
&lt;br /&gt;
	public function format(&amp;amp;$str) {&lt;br /&gt;
		$find = $this-&amp;gt;findStr;&lt;br /&gt;
		$str = preg_replace_callback($find, array($this,&amp;quot;replace&amp;quot;), $str);&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// adding three underscores to a function allows other modules to hook it&lt;br /&gt;
	public function ___replace($match) {&lt;br /&gt;
		return $this-&amp;gt;replaceStr;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Admin Funktionalität: Countdown zum Seitenveröffentlichen ===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&lt;br /&gt;
The module PageDeferredPublish, on clicking one of the &amp;#039;&amp;#039;&amp;#039;Publish Later buttons&amp;#039;&amp;#039;&amp;#039;, sets LazyCron to check that page’s countdown every minute and publishes the page when its countdown reaches 0. This means I can publish a page approximately 24 hours in advance (obviously the checking interval and delay time can be changed to your requirements).&lt;br /&gt;
&lt;br /&gt;
I did this by:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Creating two fields&amp;#039;&amp;#039;&amp;#039; within my install() function: a checkbox field to set to true when a button is checked to indicate the page should countdown, and a countdown field to store the count in seconds for that specific page.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Adding hooks&amp;#039;&amp;#039;&amp;#039; to both &amp;#039;&amp;#039;ProcessPageEdit::buildForm&amp;#039;&amp;#039; and &amp;#039;&amp;#039;ProcessPageListActions::getExtraActions&amp;#039;&amp;#039; enabling me to add the two buttons.&lt;br /&gt;
&lt;br /&gt;
Checking to see if one of the buttons was clicked with my &amp;#039;&amp;#039;&amp;#039;ready() function&amp;#039;&amp;#039;&amp;#039; then setting the corresponding page’s checkbox to true.&lt;br /&gt;
&lt;br /&gt;
Using a &amp;#039;&amp;#039;&amp;#039;LazyCron hook function&amp;#039;&amp;#039;&amp;#039; to check all pages that are unpublished for true checkboxes and then comparing the seconds field to see if the page needs publishing. If not then deduct the elapsed time in seconds.&lt;br /&gt;
&lt;br /&gt;
The result is a &amp;#039;&amp;#039;&amp;#039;module that has settings&amp;#039;&amp;#039;&amp;#039; (the time interval to check and publish at a later time), &amp;#039;&amp;#039;&amp;#039;hooks into the admin&amp;#039;&amp;#039;&amp;#039; using buttons and fields, and enables us to &amp;#039;&amp;#039;&amp;#039;use other modules installe&amp;#039;&amp;#039;&amp;#039;d in PW (i.e. LazyCron).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * DeferredPublish (0.0.1)&lt;br /&gt;
 * DeferredPublish publishes a page after a defined amount of time has elapsed using lazycron.&lt;br /&gt;
 *&lt;br /&gt;
 * @author Ben Byford&lt;br /&gt;
 * http://www.benbyford.com&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2011 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class PageDeferredPublish extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;quot;PageDeferredPublish&amp;quot;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; &amp;quot;0.0.1&amp;quot;,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;PageDeferredPublish&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;quot;Ben Byford&amp;quot;,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;quot;https://github.com/benbyford/PW-intermediate-modules&amp;quot;,&lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;quot;clock-o&amp;quot;,&lt;br /&gt;
			&amp;#039;autoload&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;requires&amp;#039; =&amp;gt; &amp;quot;LazyCron&amp;quot;,&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	private $postPubLater 	= null;&lt;br /&gt;
	private $pageID 		= null;&lt;br /&gt;
	private $pagePubLater 	= null;&lt;br /&gt;
	private $currentPage	= null;&lt;br /&gt;
&lt;br /&gt;
	private $submitName 	= &amp;#039;pdp_pub_later_submit&amp;#039;;&lt;br /&gt;
	private $listPageName	= &amp;#039;pdp_pub_later_list&amp;#039;;&lt;br /&gt;
	private $fieldName 		= &amp;#039;pdp_pub_later&amp;#039;;&lt;br /&gt;
	private $checkboxName	= &amp;#039;pdp_pub_later_check&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	private $defaultInterval = &amp;#039;everyMinute&amp;#039;;&lt;br /&gt;
	private $defaultTime 	= 86400;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	public function install(){&lt;br /&gt;
		// add new fields needed for module&lt;br /&gt;
		$this-&amp;gt;installFields();&lt;br /&gt;
	}&lt;br /&gt;
	public function uninstall(){&lt;br /&gt;
		// uninstall fields&lt;br /&gt;
		$this-&amp;gt;uninstallFields();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// initialize the hook in your AutoLoad module&lt;br /&gt;
	public function init() {&lt;br /&gt;
&lt;br /&gt;
		// get defaults from module setting in CMS&lt;br /&gt;
		$this-&amp;gt;defaultTime = $this-&amp;gt;pub_after;&lt;br /&gt;
		$this-&amp;gt;defaultInterval = $this-&amp;gt;cron_check;&lt;br /&gt;
&lt;br /&gt;
		// get admin URL&lt;br /&gt;
		$this-&amp;gt;adminUrl = $this-&amp;gt;wire(&amp;#039;config&amp;#039;)-&amp;gt;urls-&amp;gt;admin;&lt;br /&gt;
&lt;br /&gt;
		// add hooks to CRON, PageList, PageEdit&lt;br /&gt;
	    $this-&amp;gt;addHookAfter(&amp;quot;LazyCron::{$this-&amp;gt;defaultInterval}&amp;quot;, $this, &amp;#039;publishDefferedPages&amp;#039;);&lt;br /&gt;
		$this-&amp;gt;addHook(&amp;quot;ProcessPageListActions::getExtraActions&amp;quot;, $this, &amp;#039;hookPageListActions&amp;#039;);&lt;br /&gt;
		$this-&amp;gt;addHookAfter(&amp;quot;ProcessPageEdit::buildForm&amp;quot;, $this, &amp;quot;editForm&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function ready() {&lt;br /&gt;
&lt;br /&gt;
		// if list button clicked then grab id&lt;br /&gt;
		$this-&amp;gt;pagePubLater = $this-&amp;gt;input-&amp;gt;get($this-&amp;gt;listPageName);&lt;br /&gt;
		$this-&amp;gt;pageID = $this-&amp;gt;input-&amp;gt;id;&lt;br /&gt;
&lt;br /&gt;
		// get page&lt;br /&gt;
		$this-&amp;gt;currentPage = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;pageID);&lt;br /&gt;
&lt;br /&gt;
		// if pagelist pub later submit button clicked&lt;br /&gt;
		if($this-&amp;gt;pagePubLater){&lt;br /&gt;
			$this-&amp;gt;message(&amp;quot;Page {$this-&amp;gt;currentPage-&amp;gt;name} deffered for publish.&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if page edit submit button clicked&lt;br /&gt;
		$this-&amp;gt;postPubLater = $this-&amp;gt;input-&amp;gt;post($this-&amp;gt;submitName);&lt;br /&gt;
		if($this-&amp;gt;postPubLater){&lt;br /&gt;
			$this-&amp;gt;message(&amp;quot;Page {$this-&amp;gt;currentPage-&amp;gt;name} deffered for publish.&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if either deffered publish sumbit found then publish page later&lt;br /&gt;
		if($this-&amp;gt;pagePubLater || $this-&amp;gt;postPubLater){&lt;br /&gt;
			$this-&amp;gt;publishLater();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	*	Hook: ProcessPageEdit::buildForm&lt;br /&gt;
	*&lt;br /&gt;
	*	add Publish Later button to edit page if not yet published&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___editForm(HookEvent $form) {&lt;br /&gt;
&lt;br /&gt;
		// get the InputFieldForm object from the event (return value of buildForm())&lt;br /&gt;
		$form = $form-&amp;gt;return;&lt;br /&gt;
&lt;br /&gt;
		$page = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;input-&amp;gt;get-&amp;gt;id);&lt;br /&gt;
		$check = $page-&amp;gt;get($this-&amp;gt;checkboxName);&lt;br /&gt;
&lt;br /&gt;
		// check if publish button available and therfore unpublished&lt;br /&gt;
		$target = $form-&amp;gt;get(&amp;#039;submit_publish&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
		if($target &amp;amp;&amp;amp; $check == false){&lt;br /&gt;
&lt;br /&gt;
			// get InputfieldText module&lt;br /&gt;
			$submit2 = $this-&amp;gt;modules-&amp;gt;get(&amp;#039;InputfieldSubmit&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;name&amp;#039;, $this-&amp;gt;submitName);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;id&amp;#039;, &amp;#039;publish_later&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;class&amp;#039;, &amp;#039;ui-button ui-widget ui-corner-all head_button_clone ui-state-default ui-priority-secondary&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;value&amp;#039;, &amp;#039;Publish Later&amp;#039;); // Button: save unpublished&lt;br /&gt;
&lt;br /&gt;
			// get form element save and place before&lt;br /&gt;
			$target = $form-&amp;gt;get(&amp;#039;submit_save&amp;#039;);&lt;br /&gt;
			$form-&amp;gt;insertBefore($submit2, $target);&lt;br /&gt;
&lt;br /&gt;
			$form-&amp;gt;return = $form;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function ___hookPageListActions(HookEvent $event) {&lt;br /&gt;
&lt;br /&gt;
		// get current page&lt;br /&gt;
		$page = $event-&amp;gt;arguments[0];&lt;br /&gt;
&lt;br /&gt;
		// check to see if page is published&lt;br /&gt;
		$pagePub = $page-&amp;gt;is(Page::statusUnpublished);&lt;br /&gt;
&lt;br /&gt;
		// check to see if page template has deffered field&lt;br /&gt;
		$pageHasDefferField = $page-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
&lt;br /&gt;
		$actions = array();&lt;br /&gt;
&lt;br /&gt;
		// don&amp;#039;t get homepage or pages that are already published or are being deffered for publish&lt;br /&gt;
		if($page-&amp;gt;id &amp;gt; 1 &amp;amp;&amp;amp; $pagePub == &amp;quot;published&amp;quot; &amp;amp;&amp;amp; !is_null($pageHasDefferField) &amp;amp;&amp;amp; $page-&amp;gt;get($this-&amp;gt;checkboxName) == false) {&lt;br /&gt;
&lt;br /&gt;
			$actions[&amp;#039;publish_later&amp;#039;] = array(&lt;br /&gt;
				&amp;#039;cn&amp;#039;   =&amp;gt; &amp;#039;PublishLater&amp;#039;,&lt;br /&gt;
				&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;pub later&amp;#039;,&lt;br /&gt;
				&amp;#039;url&amp;#039;  =&amp;gt; &amp;quot;{$this-&amp;gt;adminUrl}?{$this-&amp;gt;listPageName}=1&amp;amp;id={$page-&amp;gt;id}&amp;quot;,&lt;br /&gt;
			);&lt;br /&gt;
		}&lt;br /&gt;
		if(count($actions)) $event-&amp;gt;return = $actions + $event-&amp;gt;return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Publish Page on cron job&lt;br /&gt;
	*&lt;br /&gt;
	* Gets deffered page and publishes&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___publish($page) {&lt;br /&gt;
		$page-&amp;gt;removeStatus(Page::statusUnpublished);&lt;br /&gt;
		$page-&amp;gt;removeStatus(Page::statusHidden);&lt;br /&gt;
		$page-&amp;gt;Save();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Main publish later function&lt;br /&gt;
	*&lt;br /&gt;
	* Gets deffered page and sets fields to be checked be lazy cron&lt;br /&gt;
	*/&lt;br /&gt;
	private function ___publishLater() {&lt;br /&gt;
&lt;br /&gt;
		// get page&lt;br /&gt;
		$page = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;pageID);&lt;br /&gt;
&lt;br /&gt;
		// set output formatting to false&lt;br /&gt;
		$page-&amp;gt;of(false);&lt;br /&gt;
&lt;br /&gt;
		//  set field time to settings default time and checkbox to true&lt;br /&gt;
		$page-&amp;gt;set($this-&amp;gt;checkboxName, true);&lt;br /&gt;
		$page-&amp;gt;set($this-&amp;gt;fieldName, $this-&amp;gt;defaultTime);&lt;br /&gt;
&lt;br /&gt;
		// save page&lt;br /&gt;
		$page-&amp;gt;save();&lt;br /&gt;
		$page-&amp;gt;of(true);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Lazy Cron hook function&lt;br /&gt;
	*&lt;br /&gt;
	* Triggers every [set time interval] and checks pages&lt;br /&gt;
	* Publishes page if time runout&lt;br /&gt;
	*&lt;br /&gt;
	* Adds publish page log&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___publishDefferedPages(HookEvent $e){&lt;br /&gt;
&lt;br /&gt;
		// seconds since last lazycron&lt;br /&gt;
		$seconds = $e-&amp;gt;arguments[0];&lt;br /&gt;
&lt;br /&gt;
		// find all pages with deffered field&lt;br /&gt;
		$defferedPages = $this-&amp;gt;pages-&amp;gt;find(&amp;quot;{$this-&amp;gt;checkboxName}=1,include=unpublished&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		// for each page decrease time for deffered field&lt;br /&gt;
		foreach ($defferedPages as $page) {&lt;br /&gt;
&lt;br /&gt;
			// get current page time&lt;br /&gt;
			$timeTillPublish = $page-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
&lt;br /&gt;
			// set time to time minus time past&lt;br /&gt;
			$timeLeft = $timeTillPublish - $seconds;&lt;br /&gt;
&lt;br /&gt;
			// if time passed 0 or less then publish page&lt;br /&gt;
			$page-&amp;gt;of(false);&lt;br /&gt;
			if($timeLeft &amp;lt;= 0){&lt;br /&gt;
				// remove flags and save&lt;br /&gt;
				$this-&amp;gt;publish($page);&lt;br /&gt;
&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;fieldName, 0);&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;checkboxName, 0);&lt;br /&gt;
&lt;br /&gt;
				// log a page has been published&lt;br /&gt;
				$log = wire(&amp;#039;log&amp;#039;);&lt;br /&gt;
				$log-&amp;gt;message(&amp;#039;CRON:&amp;#039;. $seconds .&amp;#039; Pages: &amp;#039;. $page-&amp;gt;name .&amp;#039; published&amp;#039;);&lt;br /&gt;
			}else{&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;fieldName, $timeLeft);&lt;br /&gt;
			}&lt;br /&gt;
			// save page time&lt;br /&gt;
			$page-&amp;gt;Save();&lt;br /&gt;
			$page-&amp;gt;of(true);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Install new module specific fields&lt;br /&gt;
	*/&lt;br /&gt;
	private function installFields(){&lt;br /&gt;
&lt;br /&gt;
		// install pub later checkbox field&lt;br /&gt;
		// find installed fields&lt;br /&gt;
		$f = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
		if($f){&lt;br /&gt;
&lt;br /&gt;
			// if field already found then don&amp;#039;t try and make it&lt;br /&gt;
			$this-&amp;gt;message($this-&amp;gt;fieldName . &amp;#039; field found&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
		}else{&lt;br /&gt;
&lt;br /&gt;
			// create new field object to store crontime&lt;br /&gt;
			$f = new Field();&lt;br /&gt;
			// get a field type&lt;br /&gt;
			$f-&amp;gt;type = $this-&amp;gt;modules-&amp;gt;get(&amp;quot;FieldtypeInteger&amp;quot;);&lt;br /&gt;
			$f-&amp;gt;name = $this-&amp;gt;fieldName;&lt;br /&gt;
			$f-&amp;gt;label = &amp;#039;Publish Time Left&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;defaultValue = $this-&amp;gt;defaultTime;&lt;br /&gt;
			$f-&amp;gt;icon = &amp;#039;clock-o&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;columnWidth = 50;&lt;br /&gt;
			$f-&amp;gt;collapsed = 1;&lt;br /&gt;
			$f-&amp;gt;flags = 4;&lt;br /&gt;
&lt;br /&gt;
			$f-&amp;gt;save(); // save the field&lt;br /&gt;
&lt;br /&gt;
			// create new field object to store whether to publish or not&lt;br /&gt;
			$f = new Field();&lt;br /&gt;
			// get a field type&lt;br /&gt;
			$f-&amp;gt;type = $this-&amp;gt;modules-&amp;gt;get(&amp;quot;FieldtypeCheckbox&amp;quot;);&lt;br /&gt;
			$f-&amp;gt;name = $this-&amp;gt;checkboxName;&lt;br /&gt;
			$f-&amp;gt;label = &amp;#039;Publish Page later&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;defaultValue = false;&lt;br /&gt;
			$f-&amp;gt;columnWidth = 50;&lt;br /&gt;
			$f-&amp;gt;icon = &amp;#039;clock-o&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;collapsed = 1;&lt;br /&gt;
			$f-&amp;gt;flags = 4;&lt;br /&gt;
&lt;br /&gt;
			$f-&amp;gt;save(); // save the field&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Uninstall module specific fields&lt;br /&gt;
	*/&lt;br /&gt;
	private function uninstallFields(){&lt;br /&gt;
&lt;br /&gt;
		// find installed fields&lt;br /&gt;
		$fInt = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
		$fCheck = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;checkboxName);&lt;br /&gt;
&lt;br /&gt;
		if($fInt &amp;amp;&amp;amp; $fCheck){&lt;br /&gt;
			$fieldIntUsed = $fInt-&amp;gt;numFieldgroups();&lt;br /&gt;
			$fieldCheckUsed = $fCheck-&amp;gt;numFieldgroups();&lt;br /&gt;
&lt;br /&gt;
			if($fieldIntUsed){&lt;br /&gt;
				// field in use by template&lt;br /&gt;
				$this-&amp;gt;message(&amp;#039;Unable to uninstall field &amp;#039;.$fInt-&amp;gt;name);&lt;br /&gt;
			}else{&lt;br /&gt;
				// delete installed fields&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;delete($fInt);&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;save;&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			if($fieldCheckUsed){&lt;br /&gt;
				// field in use by template&lt;br /&gt;
				$this-&amp;gt;message(&amp;#039;Unable to uninstall field &amp;#039;.$fCheck-&amp;gt;name);&lt;br /&gt;
			}else{&lt;br /&gt;
				// delete installed fields&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;delete($fCheck);&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;save;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Inputfield / Fieldtype ===&lt;br /&gt;
[[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei statt getModuleInfo ===&lt;br /&gt;
Bei größeren Konfigruation (z.B. Admin Page Navigation) sinnvoll.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * ProcessHello.info.php&lt;br /&gt;
 * &lt;br /&gt;
 * Return information about this module.&lt;br /&gt;
 *&lt;br /&gt;
 * If preferred, you can use a getModuleInfo() method in your module file, &lt;br /&gt;
 * or you can use a ModuleName.info.json file (if you prefer JSON definition). &lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
$info = array(&lt;br /&gt;
	// Your module&amp;#039;s title&lt;br /&gt;
	&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello: Process Module Example&amp;#039;, &lt;br /&gt;
	// A 1 sentence description of what your module does&lt;br /&gt;
	&amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;A starting point module skeleton from which to build your own Process module.&amp;#039;, &lt;br /&gt;
	// Module version number: use 1 for 0.0.1 or 100 for 1.0.0, and so on&lt;br /&gt;
	&amp;#039;version&amp;#039; =&amp;gt; 1, &lt;br /&gt;
	// Name of person who created this module (change to your name)&lt;br /&gt;
	&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ryan Cramer&amp;#039;, &lt;br /&gt;
	// Icon to accompany this module (optional), uses font-awesome icon names, minus the &amp;quot;fa-&amp;quot; part&lt;br /&gt;
	&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;thumbs-up&amp;#039;, &lt;br /&gt;
	// URL to more info: change to your full modules.processwire.com URL (if available), or something else if you prefer&lt;br /&gt;
	&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;http://modules.processwire.com/&amp;#039;, &lt;br /&gt;
	// name of permission required of users to execute this Process (optional)&lt;br /&gt;
	&amp;#039;permission&amp;#039; =&amp;gt; &amp;#039;helloworld&amp;#039;, &lt;br /&gt;
	// permissions that you want automatically installed/uninstalled with this module (name =&amp;gt; description)&lt;br /&gt;
	&amp;#039;permissions&amp;#039; =&amp;gt; array(&lt;br /&gt;
		&amp;#039;helloworld&amp;#039; =&amp;gt; &amp;#039;Run the HelloWorld module&amp;#039;&lt;br /&gt;
	), &lt;br /&gt;
	&lt;br /&gt;
	// page that you want created to execute this module&lt;br /&gt;
	&amp;#039;page&amp;#039; =&amp;gt; array(&lt;br /&gt;
		&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;helloworld&amp;#039;,&lt;br /&gt;
		&amp;#039;parent&amp;#039; =&amp;gt; &amp;#039;setup&amp;#039;, &lt;br /&gt;
		&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello World&amp;#039;&lt;br /&gt;
	),&lt;br /&gt;
	// optional extra navigation that appears in admin&lt;br /&gt;
	// if you change this, you&amp;#039;ll need to a Modules &amp;gt; Refresh to see changes&lt;br /&gt;
	&amp;#039;nav&amp;#039; =&amp;gt; array(&lt;br /&gt;
		array(&lt;br /&gt;
			&amp;#039;url&amp;#039; =&amp;gt; &amp;#039;&amp;#039;, &lt;br /&gt;
			&amp;#039;label&amp;#039; =&amp;gt; &amp;#039;Hello&amp;#039;, &lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;smile-o&amp;#039;, &lt;br /&gt;
		), &lt;br /&gt;
		array(&lt;br /&gt;
			&amp;#039;url&amp;#039; =&amp;gt; &amp;#039;something/&amp;#039;, &lt;br /&gt;
			&amp;#039;label&amp;#039; =&amp;gt; &amp;#039;Something&amp;#039;, &lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;beer&amp;#039;, &lt;br /&gt;
		),&lt;br /&gt;
	)&lt;br /&gt;
	// for more options that you may specify here, see the file: /wire/core/Process.php&lt;br /&gt;
	// and the file: /wire/core/Module.php&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Konfigurierbare_Module&amp;diff=24848</id>
		<title>ProcessWire - Konfigurierbare Module</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Konfigurierbare_Module&amp;diff=24848"/>
		<updated>2020-11-04T19:57:08Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: Die Seite wurde neu angelegt: „Ab ProcessWire 2.5.5. kann man Module mit Konfigurationsmöglichkeiten einfacher erstellen. Die Konfigurationsoptionen lagert man in eine extra Datei aus.    h…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ab ProcessWire 2.5.5. kann man Module mit Konfigurationsmöglichkeiten einfacher erstellen. Die Konfigurationsoptionen lagert man in eine extra Datei aus. &lt;br /&gt;
&lt;br /&gt;
 https://processwire.com/blog/posts/new-module-configuration-options/&lt;br /&gt;
&lt;br /&gt;
Beispiel Modul &amp;quot;Test&amp;quot; (gibt eine Meldung im Admin bei jeder Seitenladen aus)&lt;br /&gt;
&lt;br /&gt;
* Datei mit dem Namen und Klasse [Modulname]Config erstellen&lt;br /&gt;
* Klasse extends ModulConfig&lt;br /&gt;
* Default Werte über getDefaults() Funktion definieren&lt;br /&gt;
* Inputfelder über getInputfields() Funktion definieren&lt;br /&gt;
&lt;br /&gt;
Test.php&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
class Test extends WireData implements Module {&lt;br /&gt;
  public static function getModuleInfo() {&lt;br /&gt;
    return array(&lt;br /&gt;
     &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Module Test&amp;#039;,&lt;br /&gt;
     &amp;#039;version&amp;#039; =&amp;gt; 1,&lt;br /&gt;
     &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Module for testing/demo purposes.&amp;#039;,&lt;br /&gt;
     &amp;#039;autoload&amp;#039; =&amp;gt; &amp;#039;template=admin&amp;#039;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  public function ready() {&lt;br /&gt;
    if($this-&amp;gt;fullname &amp;amp;&amp;amp; !count($this-&amp;gt;input-&amp;gt;post)) {&lt;br /&gt;
      $msg = &amp;quot;Hi $this-&amp;gt;fullname! &amp;quot;;&lt;br /&gt;
      $msg .= &amp;quot;Your age: $this-&amp;gt;age. &amp;quot;;&lt;br /&gt;
      $msg .= &amp;quot;Favorite color: $this-&amp;gt;color.&amp;quot;;&lt;br /&gt;
      $this-&amp;gt;message($msg);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TestConfig.php&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
class TestConfig extends ModuleConfig {&lt;br /&gt;
  public function getDefaults() {&lt;br /&gt;
    return array(&lt;br /&gt;
      &amp;#039;fullname&amp;#039; =&amp;gt; &amp;#039;&amp;#039;,&lt;br /&gt;
      &amp;#039;color&amp;#039; =&amp;gt; &amp;#039;blue&amp;#039;,&lt;br /&gt;
      &amp;#039;age&amp;#039; =&amp;gt; 40,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  public function getInputfields() {&lt;br /&gt;
    $inputfields = parent::getInputfields();&lt;br /&gt;
&lt;br /&gt;
    $f = $this-&amp;gt;modules-&amp;gt;get(&amp;#039;InputfieldText&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;attr(&amp;#039;name&amp;#039;, &amp;#039;fullname&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;label = &amp;#039;Full Name&amp;#039;;&lt;br /&gt;
    $f-&amp;gt;required = true;&lt;br /&gt;
    $inputfields-&amp;gt;add($f);&lt;br /&gt;
&lt;br /&gt;
    $f = $this-&amp;gt;modules-&amp;gt;get(&amp;#039;InputfieldSelect&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;attr(&amp;#039;name&amp;#039;, &amp;#039;color&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;label = &amp;#039;Favorite Color&amp;#039;;&lt;br /&gt;
    $f-&amp;gt;options = array(&lt;br /&gt;
      &amp;#039;red&amp;#039; =&amp;gt; &amp;#039;Red&amp;#039;,&lt;br /&gt;
      &amp;#039;green&amp;#039; =&amp;gt; &amp;#039;Green&amp;#039;,&lt;br /&gt;
      &amp;#039;blue&amp;#039; =&amp;gt; &amp;#039;Blue&amp;#039;&lt;br /&gt;
    );&lt;br /&gt;
    $inputfields-&amp;gt;add($f);&lt;br /&gt;
&lt;br /&gt;
    $f = $this-&amp;gt;modules-&amp;gt;get(&amp;#039;InputfieldInteger&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;attr(&amp;#039;name&amp;#039;, &amp;#039;age&amp;#039;);&lt;br /&gt;
    $f-&amp;gt;label = &amp;#039;Your Age&amp;#039;;&lt;br /&gt;
    $inputfields-&amp;gt;add($f);&lt;br /&gt;
&lt;br /&gt;
    return $inputfields;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Module_schreiben&amp;diff=24847</id>
		<title>ProcessWire - Module schreiben</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Module_schreiben&amp;diff=24847"/>
		<updated>2020-11-04T19:46:28Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Wichtigste Resourcen&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 https://processwire.com/docs/modules/development/ - Guter Ausgangspunkt&lt;br /&gt;
 https://processwire.com/api/ref/module/ - Module API&lt;br /&gt;
 https://processwire.com/api/ref/configurable-module/ - Klasse für Konfigurierbare Module&lt;br /&gt;
 https://processwire.com/docs/modules/types/ - Welche Modultypen gibt es ?&lt;br /&gt;
 https://processwire.com/talk/topic/778-module-dependencies/ - Module die andere Module benötigen&lt;br /&gt;
 https://processwire.com/talk/forum/19-moduleplugin-development/ - Forum zum Thema Module entwickeln&lt;br /&gt;
 http://somatonic.github.io/Captain-Hook/ - Hook Cheatsheet&lt;br /&gt;
 https://processwire.com/blog/posts/new-module-configuration-options/ - Neuere Konfigurationsmöglichkeiten&lt;br /&gt;
 https://processwire.com/docs/start/api-access/ Zugriff auf ProcessWire API Variablen (wire Objekt)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039; Tutorials und Beispiele zum Einstieg &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 https://processwire.com/docs/modules/ - Introduction, Development, Hooks, Types, Pro Modules, Third Party&lt;br /&gt;
 https://github.com/ryancramerdesign/ProcessHello - Modul Skelett Beispiel für eigene Backend (Process) Module&lt;br /&gt;
 https://github.com/ryancramerdesign/FieldtypeMapMarker - Beispiel für ein Fieldtype und Inputfield Modul&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/a-beginners-introduction-to-writing-modules-in-processwire--cms-26862&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Wikiseiten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 [[ProcessWire - Module Snippets]]&lt;br /&gt;
 [[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Weitere Links&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 http://modules.pw/ (Module Creator)&lt;br /&gt;
&lt;br /&gt;
== Wo - Was ? ==&lt;br /&gt;
=== Welche Typen von Modulen gibt es ? ===&lt;br /&gt;
 https://processwire.com/docs/modules/types/&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Fieldtype&amp;#039;&amp;#039;&amp;#039;: Repräsentiert einen Datentyp. Meistens keine Public API, Handelt Daten / Datenbank - [[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Inputfield&amp;#039;&amp;#039;&amp;#039;: Sammelt User Eingaben über ein Formular im Admin Bereich. Im Gegensatz zum Fieldtype geht es hier um das UI im Backend. Das Handling der Daten liegt beim Fieldtype.&lt;br /&gt;
* [[Process Module (ProcessWire)|&amp;#039;&amp;#039;&amp;#039;Process&amp;#039;&amp;#039;&amp;#039; for creating admin processes/applications.]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Textformatter&amp;#039;&amp;#039;&amp;#039; for formatting text.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminTheme&amp;#039;&amp;#039;&amp;#039; for creating themes in the admin.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;WireMail&amp;#039;&amp;#039;&amp;#039; for modules that send email and extend the WireMail class.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tfa&amp;#039;&amp;#039;&amp;#039; for implementing a specific kind of two-factor authentication.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ImageSizerEngine&amp;#039;&amp;#039;&amp;#039; for modules that extend ImageSizerEngine for resizing images.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FileCompiler&amp;#039;&amp;#039;&amp;#039; for modules that extend FileCompilerModule for compilation of files.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FileValidator&amp;#039;&amp;#039;&amp;#039; for modules that extend FileValidatorModule for validation of files.&lt;br /&gt;
&lt;br /&gt;
=== Wie werden Felder in der Datenbank angelegt ? ===&lt;br /&gt;
Dazu nutzt man den Typ &amp;quot;Fieldtype&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Wo rendert man die Ausgabe ? ===&lt;br /&gt;
Bei Ryan Cramers Event Beispiel legt er zwei Klassen Event und EventArray an, die auch die Render Funktionen enthalten.&lt;br /&gt;
&lt;br /&gt;
=== Namenskonventionen ===&lt;br /&gt;
Ein Modulname sollte mit dem Typ den das Modul hat beginnen. Also etwa ProcessMeinAdminModul oder FieldtypeTable. ProcessWire listet das Modul dann in der Entsprechenden Kategorie auf. Wenn man etwas anderes nimmt z.B. LoginRegister dann kommt das Modul unter der neuen Rubrik &amp;quot;Login&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurierbare Module ===&lt;br /&gt;
Das geht seit 2.5.5 mittlerweile sehr einfach mit den neuen configuration-options.&lt;br /&gt;
 https://processwire.com/blog/posts/new-module-configuration-options/&lt;br /&gt;
 [[ProcessWire - Konfigurierbare Module]]&lt;br /&gt;
&lt;br /&gt;
== Spezielle Funktionen in Modulen ==&lt;br /&gt;
&lt;br /&gt;
=== getModuleInfo ===&lt;br /&gt;
Ist die einzige Pflichtfunktion in Modulen. Hier werden title, version, summary und weitere Daten hinterlegt. Hier kann man auch angeben ob ein Modul ein Autoload Modul ist.&lt;br /&gt;
&lt;br /&gt;
Statt einer getModuleInfo() Funktion kann man auch eine json Konfiguration als Datei hinterlegen&lt;br /&gt;
&lt;br /&gt;
Siehe Beispiel unten&lt;br /&gt;
&lt;br /&gt;
=== init ===&lt;br /&gt;
 public function init(){}&lt;br /&gt;
Initialisiert das Modul. ProcessWire ruft diese Funktion auf, wenn das Modul geladen ist. Bei Autoload Modulen wird es aufgerufen wenn die ProcessWire API bereit ist. Daher ist es ein guter Ort um Hooks einzubinden.&lt;br /&gt;
&lt;br /&gt;
=== ready ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  public function ready() {&lt;br /&gt;
    if($this-&amp;gt;page-&amp;gt;template == &amp;#039;admin&amp;#039;) {&lt;br /&gt;
      $this-&amp;gt;message($this-&amp;gt;hi());&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird in autoload Modulen aufgerufen wenn die API bereit ist. Nützlich für Hooks:&lt;br /&gt;
&lt;br /&gt;
=== execute ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	/**&lt;br /&gt;
	 * This function is executed when a page with your Process assigned is accessed. &lt;br /&gt;
 	 *&lt;br /&gt;
	 * This can be seen as your main or index function. You&amp;#039;ll probably want to replace&lt;br /&gt;
	 * everything in this function. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___execute() {&lt;br /&gt;
		// greetingType and greeting are automatically populated to this module&lt;br /&gt;
		// and they were defined in ProcessHello.config.php&lt;br /&gt;
		if($this-&amp;gt;greetingType == &amp;#039;message&amp;#039;) {&lt;br /&gt;
			$this-&amp;gt;message($this-&amp;gt;greeting); &lt;br /&gt;
		} else if($this-&amp;gt;greetingType == &amp;#039;warning&amp;#039;) {&lt;br /&gt;
			$this-&amp;gt;warning($this-&amp;gt;greeting); &lt;br /&gt;
		} else {&lt;br /&gt;
			$this-&amp;gt;error($this-&amp;gt;greeting); &lt;br /&gt;
		}&lt;br /&gt;
		// generate some navigation&lt;br /&gt;
		$out = 	&amp;quot;&lt;br /&gt;
			&amp;lt;h2&amp;gt;$this-&amp;gt;greeting&amp;lt;/h2&amp;gt;&lt;br /&gt;
			&amp;lt;dl class=&amp;#039;nav&amp;#039;&amp;gt;&lt;br /&gt;
				&amp;lt;dt&amp;gt;&amp;lt;a href=&amp;#039;./something/&amp;#039;&amp;gt;Do Something&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;&lt;br /&gt;
				&amp;lt;dd&amp;gt;Runs the executeSomething() function.&amp;lt;/dd&amp;gt;&lt;br /&gt;
			&amp;lt;/dl&amp;gt;&lt;br /&gt;
			&amp;quot;;&lt;br /&gt;
		return $out;&lt;br /&gt;
	}	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== executeSomething ===&lt;br /&gt;
Ruft man eine Unterseite des Moduls auf kann man eine eigene execute Funktion nutzen&lt;br /&gt;
___executeSlug wobei Slug für den Url Slug steht. Heißt der slug /field/ dann wird executeField() aufgerufen, falls diese Funktion existiert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	/**&lt;br /&gt;
	 * Called when the URL is this module&amp;#039;s page URL + &amp;quot;/something/&amp;quot;&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___executeSomething() {&lt;br /&gt;
		// set a new headline, replacing the one used by our page&lt;br /&gt;
		// this is optional as PW will auto-generate a headline &lt;br /&gt;
		$this-&amp;gt;headline(&amp;#039;This is something!&amp;#039;); &lt;br /&gt;
		// add a breadcrumb that returns to our main page &lt;br /&gt;
		// this is optional as PW will auto-generate breadcrumbs&lt;br /&gt;
		$this-&amp;gt;breadcrumb(&amp;#039;../&amp;#039;, &amp;#039;Hello&amp;#039;); &lt;br /&gt;
		$out = 	&amp;quot;&lt;br /&gt;
			&amp;lt;h2&amp;gt;Not much to to see here&amp;lt;/h2&amp;gt;&lt;br /&gt;
			&amp;lt;p&amp;gt;&amp;lt;a href=&amp;#039;../&amp;#039;&amp;gt;Go Back&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
			&amp;quot;;&lt;br /&gt;
		return $out; &lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== install &amp;amp; uninstall ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
	 * Called only when your module is installed&lt;br /&gt;
	 *&lt;br /&gt;
	 * If you don&amp;#039;t need anything here, you can simply remove this method. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___install() {&lt;br /&gt;
		parent::___install(); // always remember to call parent method&lt;br /&gt;
	}&lt;br /&gt;
	/**&lt;br /&gt;
	 * Called only when your module is uninstalled&lt;br /&gt;
	 *&lt;br /&gt;
	 * This should return the site to the same state it was in before the module was installed. &lt;br /&gt;
	 *&lt;br /&gt;
	 * If you don&amp;#039;t need anything here, you can simply remove this method. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___uninstall() {&lt;br /&gt;
		parent::___uninstall(); // always remember to call parent method&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vererbung und Eigenschaften in Modulen ==&lt;br /&gt;
Modules are not different from PHP classes.&lt;br /&gt;
&lt;br /&gt;
To change the properties of MyModule class from within MyOtherModule class, you can either:&lt;br /&gt;
&lt;br /&gt;
#Make MyOtherModule class extend MyModule. It will thus inherit MyModule&amp;#039;s public and protected properties and methods&lt;br /&gt;
#Make the properties firstName and lastName configurable by passing them as parameters/arguments in MyModule&amp;#039;s constructor method.&lt;br /&gt;
&lt;br /&gt;
== Autoload Module und Hooks ==&lt;br /&gt;
Autoload werden automatisch geladen müssen also nicht in einem Template o.ä. gestartet werden. Daher bieten sie sich an um die Funktionalität von ProcessWire zu erweitern. Als Werkzeug dafür dienen Hooks. Mit Hooks kann man an vielen Stellen den Rendering Process der Seiten beeinflussen. Außerdem kann man für eigene Module ebenfalls Hooks bereitstellen. &lt;br /&gt;
&lt;br /&gt;
=== Hooks ===&lt;br /&gt;
 https://processwire.com/docs/modules/hooks/&lt;br /&gt;
Hooks sind ein mächtiges Werkzeug. Sie geben einem die Möglichkeit an vielen Stellen &amp;quot;einzuhaken&amp;quot; und Funktionalität einzubauen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, function($event) {&lt;br /&gt;
    $event-&amp;gt;return .= &amp;#039;&amp;lt;p&amp;gt;Hallo&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Schreibt am Ende Jeder Seite ein &amp;quot;Hallo&amp;quot;. Das $event Objekt ist ein [https://processwire.com/api/ref/hook-event/ HookEvent]. Im Beispiel fügen wir einfach etwas Markup hinzu. Über $event-&amp;gt;arguments() kann man aber auf ale Argumente zugreifen.&lt;br /&gt;
&lt;br /&gt;
Das gleiche aber nicht mit anonymer Funktion:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  // add hook after Page::render() and make it call the &amp;quot;test&amp;quot; method of $this module&lt;br /&gt;
  $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, $this, &amp;#039;test&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public function test($event) {&lt;br /&gt;
  // modify the return value of Page::render() to include the following:&lt;br /&gt;
  $event-&amp;gt;return .= &amp;#039;&amp;lt;p&amp;gt;Hallo&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hooks zum erweitern von existierenden Klassen nutzen ===&lt;br /&gt;
Mit Hooks kann man in vorhandene Klassen einhaken. Z.B. läßt sich das Page Objekt erweitern.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  $this-&amp;gt;addHook(&amp;#039;Page::summarize&amp;#039;, $this, &amp;#039;summarize&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
public function summarize($event) {&lt;br /&gt;
  $page = $event-&amp;gt;object; // the $event-&amp;gt;object represents the object hooked (Page)&lt;br /&gt;
  $maxlen = $event-&amp;gt;arguments(0); // first argument is the optional max length&lt;br /&gt;
  if(!$maxlen) $maxlen = 200; // if no $maxlen was present, we&amp;#039;ll use a default of 200&lt;br /&gt;
  $summary = $this-&amp;gt;sanitizer-&amp;gt;truncate($page-&amp;gt;body, $maxlen); // use sanitizer truncate method to create a summary&lt;br /&gt;
  $event-&amp;gt;return = $summary; // populate $summary to $event-&amp;gt;return, the return value&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So kann man ganz einfach eine Zusammenfassung aller Kindseiten in einem Template rendern:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
foreach($page-&amp;gt;children as $item) {&lt;br /&gt;
  $summary = $item-&amp;gt;summarize(150);&lt;br /&gt;
  echo &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;$item-&amp;gt;url&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;$summary&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Autoload Module nur im Admin Bereich laden ===&lt;br /&gt;
&lt;br /&gt;
 &amp;#039;autoload&amp;#039; =&amp;gt; &amp;#039;template=admin&amp;#039; &lt;br /&gt;
statt&lt;br /&gt;
 &amp;#039;autoload&amp;#039; =&amp;gt; true&lt;br /&gt;
&lt;br /&gt;
=== Hook Beispiele ===&lt;br /&gt;
Hook am Ende des Renderings&lt;br /&gt;
 $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, function($event) {...});&lt;br /&gt;
Füge eine Funktion &amp;quot;summarize&amp;quot; zum Page Objekt hinzu.&lt;br /&gt;
 $this-&amp;gt;addHook(&amp;#039;Page::summarize&amp;#039;, $this, &amp;#039;summarize&amp;#039;);&lt;br /&gt;
Hook auf eine einzelne Instanz (hier pages Objekt)&lt;br /&gt;
 $this-&amp;gt;pages-&amp;gt;addHookAfter(&amp;#039;saved&amp;#039;, function($event){...});&lt;br /&gt;
 $this-&amp;gt;addHook(&amp;#039;Page::method&amp;#039;, ...) // Spricht ALLE Instanzen an - Regelfall&lt;br /&gt;
 $page-&amp;gt;addHook(&amp;#039;method&amp;#039;, ...) // Spricht nur die EINE Instanz der Seite an.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Module Dependencies - voneinander abhängige Module ==&lt;br /&gt;
&lt;br /&gt;
 https://processwire.com/talk/topic/778-module-dependencies/&lt;br /&gt;
Wenn ein Modul nicht ohne ein anderes funktioniert spricht man von Module Dependency. In solchen Fällen kann man in der Modul Info angeben In vielen Fällen besteht ein Modul unter der Haube aus mehreren Einzelmodulen.&lt;br /&gt;
&lt;br /&gt;
Um ProcessWire mitzuteilen dass ein Modul benötigt wird gibt man es in der Moduldefinition an:&lt;br /&gt;
 &amp;#039;requires&amp;#039; =&amp;gt; &amp;quot;LazyCron&amp;quot;  // added this line&lt;br /&gt;
oder auch mehrere als Array&lt;br /&gt;
 &amp;#039;requires&amp;#039; =&amp;gt; array(&amp;quot;LazyCron&amp;quot;, &amp;quot;AdminBar&amp;quot;)  // added this line&lt;br /&gt;
&lt;br /&gt;
ProcessWire kann auch dafür sorgen, dass ein Modul andere &amp;quot;Kindmodule&amp;quot; gleich mitinstalliert bzw. deinstalliert wenn es nicht mehr benötigt wird. Dazu gibt man dem Modul noch die &amp;#039;install&amp;#039; dependency mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
public static function getModuleInfo() {&lt;br /&gt;
   return array(&lt;br /&gt;
       &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Log Master&amp;#039;,&lt;br /&gt;
       &amp;#039;version&amp;#039; =&amp;gt; 101,&lt;br /&gt;
       &amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Lumberjack Bob&amp;#039;,&lt;br /&gt;
       &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Log all actions on your site&amp;#039;,&lt;br /&gt;
       &amp;#039;requires&amp;#039; =&amp;gt; &amp;#039;LazyCron&amp;#039;, &lt;br /&gt;
       &amp;#039;installs&amp;#039; =&amp;gt; &amp;#039;ProcessLogMaster&amp;#039;  // added this line&lt;br /&gt;
       ); &lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProcessWire sieht dann eine Kindabhängigkeit zu diesem Modul und handelt auch das Deinstallieren, wenn das Elternmodul deinstalliert wird.&lt;br /&gt;
&lt;br /&gt;
== CSS und JavaScript in Modulen ==&lt;br /&gt;
Bei Process Modulen möchte man für das Styling etc. im Backend oft CSS und JS Dateien hinzufügen.&lt;br /&gt;
&lt;br /&gt;
Einfach Eine Datei MeinModul.css und / oder MeinModul.js hinzufügen. JQuery ist im Admin bereits geladen daher kann eine MeinModul.js Starter Datei so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This JS file is only loaded when the ProcessHello module is run&lt;br /&gt;
 *&lt;br /&gt;
 * You should delete it if you have no javascript to add.&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
$(document).ready(function() {&lt;br /&gt;
	// do something&lt;br /&gt;
}); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Frontend Rendering Module ===&lt;br /&gt;
A bit old but working&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * FrontEndRender&lt;br /&gt;
 *&lt;br /&gt;
 * Author: Ben Byford&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2010 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class FrontEndRender extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;FrontEndRender&amp;#039;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 0.1,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;Outputs html and static variables to frontend&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ben Byford&amp;#039;,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://github.com/benbyford/PW-starter-modules&amp;#039;&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// protected variable only accessable within module&lt;br /&gt;
	protected $name = &amp;#039;Ben&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* render function to be called in PW template like this:&lt;br /&gt;
	* $FrontEndRender = $modules-&amp;gt;getModule(&amp;#039;FrontEndRender&amp;#039;);&lt;br /&gt;
	* echo &amp;#039;&amp;lt;h1&amp;gt;&amp;#039; . $FrontEndRender-&amp;gt;render() . &amp;#039;&amp;lt;/h1&amp;gt;&amp;#039;;&lt;br /&gt;
	*&lt;br /&gt;
	*/&lt;br /&gt;
	public function render(){&lt;br /&gt;
		return &amp;quot;Hello &amp;quot; . $this-&amp;gt;name;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Hello World Modul ===&lt;br /&gt;
Beispiel Modul mit Hooks (liegt immer in der Standardinstallation)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * ProcessWire &amp;#039;Hello world&amp;#039; demonstration module&lt;br /&gt;
 *&lt;br /&gt;
 * Demonstrates the Module interface and how to add hooks.&lt;br /&gt;
 * &lt;br /&gt;
 * See README file for further links regarding module development.&lt;br /&gt;
 * &lt;br /&gt;
 * This file is licensed under the MIT license&lt;br /&gt;
 * https://processwire.com/about/license/mit/&lt;br /&gt;
 * &lt;br /&gt;
 * ProcessWire 3.x, Copyright 2016 by Ryan Cramer&lt;br /&gt;
 * https://processwire.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class Helloworld extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * getModuleInfo is a module required by all modules to tell ProcessWire about them&lt;br /&gt;
	 *&lt;br /&gt;
	 * @return array&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
&lt;br /&gt;
		return array(&lt;br /&gt;
&lt;br /&gt;
			// The module&amp;#039;s title, typically a little more descriptive than the class name&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello World&amp;#039;, &lt;br /&gt;
&lt;br /&gt;
			// version number &lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 3, &lt;br /&gt;
&lt;br /&gt;
			// summary is brief description of what this module is&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;An example module used for demonstration purposes.&amp;#039;,&lt;br /&gt;
			&lt;br /&gt;
			// Optional URL to more information about the module&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://processwire.com&amp;#039;,&lt;br /&gt;
&lt;br /&gt;
			// singular=true: indicates that only one instance of the module is allowed.&lt;br /&gt;
			// This is usually what you want for modules that attach hooks. &lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true, &lt;br /&gt;
&lt;br /&gt;
			// autoload=true: indicates the module should be started with ProcessWire.&lt;br /&gt;
			// This is necessary for any modules that attach runtime hooks, otherwise those&lt;br /&gt;
			// hooks won&amp;#039;t get attached unless some other code calls the module on it&amp;#039;s own.&lt;br /&gt;
			// Note that autoload modules are almost always also &amp;#039;singular&amp;#039; (seen above).&lt;br /&gt;
			&amp;#039;autoload&amp;#039; =&amp;gt; true, &lt;br /&gt;
		&lt;br /&gt;
			// Optional font-awesome icon name, minus the &amp;#039;fa-&amp;#039; part&lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;smile-o&amp;#039;, &lt;br /&gt;
			);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Initialize the module&lt;br /&gt;
	 *&lt;br /&gt;
	 * ProcessWire calls this when the module is loaded. For &amp;#039;autoload&amp;#039; modules, this will be called&lt;br /&gt;
	 * when ProcessWire&amp;#039;s API is ready. As a result, this is a good place to attach hooks. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function init() {&lt;br /&gt;
&lt;br /&gt;
		// add a hook after the $pages-&amp;gt;save, to issue a notice every time a page is saved&lt;br /&gt;
		$this-&amp;gt;pages-&amp;gt;addHookAfter(&amp;#039;save&amp;#039;, $this, &amp;#039;example1&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a hook after each page is rendered and modify the output&lt;br /&gt;
		$this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, $this, &amp;#039;example2&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a &amp;#039;hello&amp;#039; method to every page that returns &amp;quot;Hello World&amp;quot;&lt;br /&gt;
		// use &amp;quot;echo $page-&amp;gt;hello();&amp;quot; in your template file to display output&lt;br /&gt;
		$this-&amp;gt;addHook(&amp;#039;Page::hello&amp;#039;, $this, &amp;#039;example3&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a &amp;#039;hello_world&amp;#039; property to every page that returns &amp;quot;Hello [user]&amp;quot;&lt;br /&gt;
		// use &amp;quot;echo $page-&amp;gt;hello_world;&amp;quot; in your template file to display output&lt;br /&gt;
		$this-&amp;gt;addHookProperty(&amp;#039;Page::hello_world&amp;#039;, $this, &amp;#039;example4&amp;#039;); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example1 hooks into the pages-&amp;gt;save method and displays a notice every time a page is saved&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example1($event) {&lt;br /&gt;
		/** @var Page $page */&lt;br /&gt;
		$page = $event-&amp;gt;arguments[0]; &lt;br /&gt;
		$this-&amp;gt;message(&amp;quot;Hello World! You saved {$page-&amp;gt;path}.&amp;quot;); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example2 hooks into every page after it&amp;#039;s rendered and adds &amp;quot;Hello World&amp;quot; text at the bottom&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example2($event) {&lt;br /&gt;
&lt;br /&gt;
		/** @var Page $page */&lt;br /&gt;
		$page = $event-&amp;gt;object; &lt;br /&gt;
&lt;br /&gt;
		// don&amp;#039;t add this to the admin pages&lt;br /&gt;
		if($page-&amp;gt;template == &amp;#039;admin&amp;#039;) return;&lt;br /&gt;
&lt;br /&gt;
		// add a &amp;quot;Hello World&amp;quot; paragraph right before the closing body tag&lt;br /&gt;
		$event-&amp;gt;return = str_replace(&amp;quot;&amp;lt;/body&amp;gt;&amp;quot;, &amp;quot;&amp;lt;p&amp;gt;Hello World!&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;quot;, $event-&amp;gt;return); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example3 adds a &amp;#039;hello&amp;#039; method (not property) to every page that simply returns &amp;quot;Hello World&amp;quot;&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example3($event) {&lt;br /&gt;
		$event-&amp;gt;return = &amp;quot;Hello World&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example 4 adds a &amp;#039;hello_world&amp;#039; property (not method) to every page that returns &amp;quot;Hello [user]&amp;quot;&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example4($event) {&lt;br /&gt;
		$event-&amp;gt;return = &amp;quot;Hello &amp;quot; . $this-&amp;gt;user-&amp;gt;name; &lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Admin Bereich mit eigener Funktionalität erweitern (Modul)===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
* ProcessSimpleAdminPage&lt;br /&gt;
*&lt;br /&gt;
* @author Ben Byford&lt;br /&gt;
* http://www.benbyford.com&lt;br /&gt;
*&lt;br /&gt;
* @see http://www.processwire.com&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
class ProcessSimpleAdminPage extends Process {&lt;br /&gt;
&lt;br /&gt;
    public static function getModuleInfo() {&lt;br /&gt;
        return array(&lt;br /&gt;
            &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Process Simple Admin Page&amp;#039;,&lt;br /&gt;
            &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Simple Process module that adds new admin page with&amp;#039;,&lt;br /&gt;
            &amp;#039;version&amp;#039; =&amp;gt; 001,&lt;br /&gt;
&lt;br /&gt;
            // Modules that extend Process may specify a &amp;#039;page&amp;#039; attribute in the&lt;br /&gt;
            // getModuleInfo(), this page will automatically be given the module&lt;br /&gt;
            // process when added to teh pagetree.&lt;br /&gt;
&lt;br /&gt;
            // I have exampled but commented out the &amp;#039;page&amp;#039; settings below&lt;br /&gt;
            // so that I can show how one might add a page to install() and&lt;br /&gt;
            // uninstall() in this and other modules (that might not extend&lt;br /&gt;
            // Process)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        // 	&amp;#039;page&amp;#039; =&amp;gt; array(&lt;br /&gt;
        // 		&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;site-config&amp;#039;,&lt;br /&gt;
        // 		&amp;#039;parent&amp;#039; =&amp;gt; &amp;#039;admin&amp;#039;,&lt;br /&gt;
        // 		&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Site Config&amp;#039;&lt;br /&gt;
        // 	   )&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function execute() {&lt;br /&gt;
        return &amp;#039;&lt;br /&gt;
            &amp;lt;h2&amp;gt;Edit the text here in the module&amp;lt;/h2&amp;gt;&lt;br /&gt;
            &amp;lt;p&amp;gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mattis eros vitae metus sodales eget suscipit purus rhoncus. Proin ultrices gravida dolor, non porttitor enim interdum vitae. Integer feugiat lacinia tincidunt. Nulla laoreet tristique tristique. Sed elementum justo a nisl elementum sit amet accumsan nisi tempor. Nulla quis eros et massa dignissim imperdiet a vitae purus.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Donec scelerisque pulvinar sem eu lobortis. Maecenas turpis ipsum, tempus dictum pharetra eu, consectetur vitae arcu. Fusce orci mauris, semper at tempus quis, volutpat molestie tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed quam tortor, tincidunt sed semper lacinia, scelerisque dapibus quam. Morbi at nisi luctus lacus auctor ultrices eu eu leo.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Praesent faucibus purus id felis tincidunt dignissim. Sed sit amet ligula mi, eget semper dui. Proin consectetur gravida massa, nec luctus purus hendrerit in. Etiam volutpat, elit non venenatis suscipit, libero neque consectetur diam, id rutrum magna odio ac ligula. Maecenas sollicitudin congue neque fermentum vestibulum. Morbi nec leo nisi. Donec at nisl odio, et porta ligula.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Sed quis arcu nisi, ac tempor augue. Praesent non elit libero, a ullamcorper lorem. Curabitur porta odio eu nunc ultricies interdum id nec risus. Donec nibh nibh, porta eget vehicula ac, aliquet eget ante. Phasellus eget lorem eu eros eleifend ultrices. Cras sit amet neque sit amet nibh fringilla cursus ut id mauris. Praesent quis nunc justo, sed suscipit lectus. Phasellus eget ultrices risus. Curabitur eu semper est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut suscipit, nisl ut imperdiet eleifend, turpis arcu placerat tortor, nec laoreet lacus neque ac tellus. Aenean ac lacus justo, quis ultricies nisi.&amp;lt;/p&amp;gt;&lt;br /&gt;
            &amp;#039;;&lt;br /&gt;
    }&lt;br /&gt;
    public function install(){&lt;br /&gt;
&lt;br /&gt;
        // create new page to add to CMS&lt;br /&gt;
		$page = new Page();&lt;br /&gt;
&lt;br /&gt;
        // add page attributes&lt;br /&gt;
        $page-&amp;gt;template = &amp;quot;admin&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;name = &amp;quot;cms-faq&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;title = &amp;quot;CMS FAQ&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;save();&lt;br /&gt;
&lt;br /&gt;
        // set this module as the page process, this allows us to display the above&lt;br /&gt;
        $page-&amp;gt;process = &amp;#039;ProcessSimpleAdminPage&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
        // get admin page and set as page parent&lt;br /&gt;
        $admin = $this-&amp;gt;pages-&amp;gt;get(&amp;quot;id=2&amp;quot;);&lt;br /&gt;
        $page-&amp;gt;parent = $admin;&lt;br /&gt;
&lt;br /&gt;
        // save page&lt;br /&gt;
        $page-&amp;gt;save();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function uninstall(){&lt;br /&gt;
&lt;br /&gt;
        // delete created page&lt;br /&gt;
        $page = $this-&amp;gt;pages-&amp;gt;get(&amp;quot;name=cms-faq&amp;quot;);&lt;br /&gt;
        if(count($page)) $this-&amp;gt;pages-&amp;gt;delete($page, true);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Textformatter Modul ===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * TextformatterFindReplace&lt;br /&gt;
 *&lt;br /&gt;
 * Author: Ben Byford&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2010 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class TextformatterFindReplace extends Textformatter implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;TextformatterFindReplace&amp;#039;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 0.1,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;Finds and replaces any instance of config input to config output&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ben Byford&amp;#039;,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://github.com/benbyford/PW-starter-modules&amp;#039;&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
     * Find and Replace the input string&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $str The block of text to parse&lt;br /&gt;
     *&lt;br /&gt;
     * The incoming string is replaced with the formatted version of itself.&lt;br /&gt;
	 **/&lt;br /&gt;
&lt;br /&gt;
	public function format(&amp;amp;$str) {&lt;br /&gt;
		$find = $this-&amp;gt;findStr;&lt;br /&gt;
		$str = preg_replace_callback($find, array($this,&amp;quot;replace&amp;quot;), $str);&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// adding three underscores to a function allows other modules to hook it&lt;br /&gt;
	public function ___replace($match) {&lt;br /&gt;
		return $this-&amp;gt;replaceStr;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Admin Funktionalität: Countdown zum Seitenveröffentlichen ===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&lt;br /&gt;
The module PageDeferredPublish, on clicking one of the &amp;#039;&amp;#039;&amp;#039;Publish Later buttons&amp;#039;&amp;#039;&amp;#039;, sets LazyCron to check that page’s countdown every minute and publishes the page when its countdown reaches 0. This means I can publish a page approximately 24 hours in advance (obviously the checking interval and delay time can be changed to your requirements).&lt;br /&gt;
&lt;br /&gt;
I did this by:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Creating two fields&amp;#039;&amp;#039;&amp;#039; within my install() function: a checkbox field to set to true when a button is checked to indicate the page should countdown, and a countdown field to store the count in seconds for that specific page.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Adding hooks&amp;#039;&amp;#039;&amp;#039; to both &amp;#039;&amp;#039;ProcessPageEdit::buildForm&amp;#039;&amp;#039; and &amp;#039;&amp;#039;ProcessPageListActions::getExtraActions&amp;#039;&amp;#039; enabling me to add the two buttons.&lt;br /&gt;
&lt;br /&gt;
Checking to see if one of the buttons was clicked with my &amp;#039;&amp;#039;&amp;#039;ready() function&amp;#039;&amp;#039;&amp;#039; then setting the corresponding page’s checkbox to true.&lt;br /&gt;
&lt;br /&gt;
Using a &amp;#039;&amp;#039;&amp;#039;LazyCron hook function&amp;#039;&amp;#039;&amp;#039; to check all pages that are unpublished for true checkboxes and then comparing the seconds field to see if the page needs publishing. If not then deduct the elapsed time in seconds.&lt;br /&gt;
&lt;br /&gt;
The result is a &amp;#039;&amp;#039;&amp;#039;module that has settings&amp;#039;&amp;#039;&amp;#039; (the time interval to check and publish at a later time), &amp;#039;&amp;#039;&amp;#039;hooks into the admin&amp;#039;&amp;#039;&amp;#039; using buttons and fields, and enables us to &amp;#039;&amp;#039;&amp;#039;use other modules installe&amp;#039;&amp;#039;&amp;#039;d in PW (i.e. LazyCron).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * DeferredPublish (0.0.1)&lt;br /&gt;
 * DeferredPublish publishes a page after a defined amount of time has elapsed using lazycron.&lt;br /&gt;
 *&lt;br /&gt;
 * @author Ben Byford&lt;br /&gt;
 * http://www.benbyford.com&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2011 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class PageDeferredPublish extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;quot;PageDeferredPublish&amp;quot;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; &amp;quot;0.0.1&amp;quot;,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;PageDeferredPublish&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;quot;Ben Byford&amp;quot;,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;quot;https://github.com/benbyford/PW-intermediate-modules&amp;quot;,&lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;quot;clock-o&amp;quot;,&lt;br /&gt;
			&amp;#039;autoload&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;requires&amp;#039; =&amp;gt; &amp;quot;LazyCron&amp;quot;,&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	private $postPubLater 	= null;&lt;br /&gt;
	private $pageID 		= null;&lt;br /&gt;
	private $pagePubLater 	= null;&lt;br /&gt;
	private $currentPage	= null;&lt;br /&gt;
&lt;br /&gt;
	private $submitName 	= &amp;#039;pdp_pub_later_submit&amp;#039;;&lt;br /&gt;
	private $listPageName	= &amp;#039;pdp_pub_later_list&amp;#039;;&lt;br /&gt;
	private $fieldName 		= &amp;#039;pdp_pub_later&amp;#039;;&lt;br /&gt;
	private $checkboxName	= &amp;#039;pdp_pub_later_check&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	private $defaultInterval = &amp;#039;everyMinute&amp;#039;;&lt;br /&gt;
	private $defaultTime 	= 86400;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	public function install(){&lt;br /&gt;
		// add new fields needed for module&lt;br /&gt;
		$this-&amp;gt;installFields();&lt;br /&gt;
	}&lt;br /&gt;
	public function uninstall(){&lt;br /&gt;
		// uninstall fields&lt;br /&gt;
		$this-&amp;gt;uninstallFields();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// initialize the hook in your AutoLoad module&lt;br /&gt;
	public function init() {&lt;br /&gt;
&lt;br /&gt;
		// get defaults from module setting in CMS&lt;br /&gt;
		$this-&amp;gt;defaultTime = $this-&amp;gt;pub_after;&lt;br /&gt;
		$this-&amp;gt;defaultInterval = $this-&amp;gt;cron_check;&lt;br /&gt;
&lt;br /&gt;
		// get admin URL&lt;br /&gt;
		$this-&amp;gt;adminUrl = $this-&amp;gt;wire(&amp;#039;config&amp;#039;)-&amp;gt;urls-&amp;gt;admin;&lt;br /&gt;
&lt;br /&gt;
		// add hooks to CRON, PageList, PageEdit&lt;br /&gt;
	    $this-&amp;gt;addHookAfter(&amp;quot;LazyCron::{$this-&amp;gt;defaultInterval}&amp;quot;, $this, &amp;#039;publishDefferedPages&amp;#039;);&lt;br /&gt;
		$this-&amp;gt;addHook(&amp;quot;ProcessPageListActions::getExtraActions&amp;quot;, $this, &amp;#039;hookPageListActions&amp;#039;);&lt;br /&gt;
		$this-&amp;gt;addHookAfter(&amp;quot;ProcessPageEdit::buildForm&amp;quot;, $this, &amp;quot;editForm&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function ready() {&lt;br /&gt;
&lt;br /&gt;
		// if list button clicked then grab id&lt;br /&gt;
		$this-&amp;gt;pagePubLater = $this-&amp;gt;input-&amp;gt;get($this-&amp;gt;listPageName);&lt;br /&gt;
		$this-&amp;gt;pageID = $this-&amp;gt;input-&amp;gt;id;&lt;br /&gt;
&lt;br /&gt;
		// get page&lt;br /&gt;
		$this-&amp;gt;currentPage = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;pageID);&lt;br /&gt;
&lt;br /&gt;
		// if pagelist pub later submit button clicked&lt;br /&gt;
		if($this-&amp;gt;pagePubLater){&lt;br /&gt;
			$this-&amp;gt;message(&amp;quot;Page {$this-&amp;gt;currentPage-&amp;gt;name} deffered for publish.&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if page edit submit button clicked&lt;br /&gt;
		$this-&amp;gt;postPubLater = $this-&amp;gt;input-&amp;gt;post($this-&amp;gt;submitName);&lt;br /&gt;
		if($this-&amp;gt;postPubLater){&lt;br /&gt;
			$this-&amp;gt;message(&amp;quot;Page {$this-&amp;gt;currentPage-&amp;gt;name} deffered for publish.&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if either deffered publish sumbit found then publish page later&lt;br /&gt;
		if($this-&amp;gt;pagePubLater || $this-&amp;gt;postPubLater){&lt;br /&gt;
			$this-&amp;gt;publishLater();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	*	Hook: ProcessPageEdit::buildForm&lt;br /&gt;
	*&lt;br /&gt;
	*	add Publish Later button to edit page if not yet published&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___editForm(HookEvent $form) {&lt;br /&gt;
&lt;br /&gt;
		// get the InputFieldForm object from the event (return value of buildForm())&lt;br /&gt;
		$form = $form-&amp;gt;return;&lt;br /&gt;
&lt;br /&gt;
		$page = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;input-&amp;gt;get-&amp;gt;id);&lt;br /&gt;
		$check = $page-&amp;gt;get($this-&amp;gt;checkboxName);&lt;br /&gt;
&lt;br /&gt;
		// check if publish button available and therfore unpublished&lt;br /&gt;
		$target = $form-&amp;gt;get(&amp;#039;submit_publish&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
		if($target &amp;amp;&amp;amp; $check == false){&lt;br /&gt;
&lt;br /&gt;
			// get InputfieldText module&lt;br /&gt;
			$submit2 = $this-&amp;gt;modules-&amp;gt;get(&amp;#039;InputfieldSubmit&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;name&amp;#039;, $this-&amp;gt;submitName);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;id&amp;#039;, &amp;#039;publish_later&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;class&amp;#039;, &amp;#039;ui-button ui-widget ui-corner-all head_button_clone ui-state-default ui-priority-secondary&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;value&amp;#039;, &amp;#039;Publish Later&amp;#039;); // Button: save unpublished&lt;br /&gt;
&lt;br /&gt;
			// get form element save and place before&lt;br /&gt;
			$target = $form-&amp;gt;get(&amp;#039;submit_save&amp;#039;);&lt;br /&gt;
			$form-&amp;gt;insertBefore($submit2, $target);&lt;br /&gt;
&lt;br /&gt;
			$form-&amp;gt;return = $form;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function ___hookPageListActions(HookEvent $event) {&lt;br /&gt;
&lt;br /&gt;
		// get current page&lt;br /&gt;
		$page = $event-&amp;gt;arguments[0];&lt;br /&gt;
&lt;br /&gt;
		// check to see if page is published&lt;br /&gt;
		$pagePub = $page-&amp;gt;is(Page::statusUnpublished);&lt;br /&gt;
&lt;br /&gt;
		// check to see if page template has deffered field&lt;br /&gt;
		$pageHasDefferField = $page-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
&lt;br /&gt;
		$actions = array();&lt;br /&gt;
&lt;br /&gt;
		// don&amp;#039;t get homepage or pages that are already published or are being deffered for publish&lt;br /&gt;
		if($page-&amp;gt;id &amp;gt; 1 &amp;amp;&amp;amp; $pagePub == &amp;quot;published&amp;quot; &amp;amp;&amp;amp; !is_null($pageHasDefferField) &amp;amp;&amp;amp; $page-&amp;gt;get($this-&amp;gt;checkboxName) == false) {&lt;br /&gt;
&lt;br /&gt;
			$actions[&amp;#039;publish_later&amp;#039;] = array(&lt;br /&gt;
				&amp;#039;cn&amp;#039;   =&amp;gt; &amp;#039;PublishLater&amp;#039;,&lt;br /&gt;
				&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;pub later&amp;#039;,&lt;br /&gt;
				&amp;#039;url&amp;#039;  =&amp;gt; &amp;quot;{$this-&amp;gt;adminUrl}?{$this-&amp;gt;listPageName}=1&amp;amp;id={$page-&amp;gt;id}&amp;quot;,&lt;br /&gt;
			);&lt;br /&gt;
		}&lt;br /&gt;
		if(count($actions)) $event-&amp;gt;return = $actions + $event-&amp;gt;return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Publish Page on cron job&lt;br /&gt;
	*&lt;br /&gt;
	* Gets deffered page and publishes&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___publish($page) {&lt;br /&gt;
		$page-&amp;gt;removeStatus(Page::statusUnpublished);&lt;br /&gt;
		$page-&amp;gt;removeStatus(Page::statusHidden);&lt;br /&gt;
		$page-&amp;gt;Save();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Main publish later function&lt;br /&gt;
	*&lt;br /&gt;
	* Gets deffered page and sets fields to be checked be lazy cron&lt;br /&gt;
	*/&lt;br /&gt;
	private function ___publishLater() {&lt;br /&gt;
&lt;br /&gt;
		// get page&lt;br /&gt;
		$page = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;pageID);&lt;br /&gt;
&lt;br /&gt;
		// set output formatting to false&lt;br /&gt;
		$page-&amp;gt;of(false);&lt;br /&gt;
&lt;br /&gt;
		//  set field time to settings default time and checkbox to true&lt;br /&gt;
		$page-&amp;gt;set($this-&amp;gt;checkboxName, true);&lt;br /&gt;
		$page-&amp;gt;set($this-&amp;gt;fieldName, $this-&amp;gt;defaultTime);&lt;br /&gt;
&lt;br /&gt;
		// save page&lt;br /&gt;
		$page-&amp;gt;save();&lt;br /&gt;
		$page-&amp;gt;of(true);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Lazy Cron hook function&lt;br /&gt;
	*&lt;br /&gt;
	* Triggers every [set time interval] and checks pages&lt;br /&gt;
	* Publishes page if time runout&lt;br /&gt;
	*&lt;br /&gt;
	* Adds publish page log&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___publishDefferedPages(HookEvent $e){&lt;br /&gt;
&lt;br /&gt;
		// seconds since last lazycron&lt;br /&gt;
		$seconds = $e-&amp;gt;arguments[0];&lt;br /&gt;
&lt;br /&gt;
		// find all pages with deffered field&lt;br /&gt;
		$defferedPages = $this-&amp;gt;pages-&amp;gt;find(&amp;quot;{$this-&amp;gt;checkboxName}=1,include=unpublished&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		// for each page decrease time for deffered field&lt;br /&gt;
		foreach ($defferedPages as $page) {&lt;br /&gt;
&lt;br /&gt;
			// get current page time&lt;br /&gt;
			$timeTillPublish = $page-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
&lt;br /&gt;
			// set time to time minus time past&lt;br /&gt;
			$timeLeft = $timeTillPublish - $seconds;&lt;br /&gt;
&lt;br /&gt;
			// if time passed 0 or less then publish page&lt;br /&gt;
			$page-&amp;gt;of(false);&lt;br /&gt;
			if($timeLeft &amp;lt;= 0){&lt;br /&gt;
				// remove flags and save&lt;br /&gt;
				$this-&amp;gt;publish($page);&lt;br /&gt;
&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;fieldName, 0);&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;checkboxName, 0);&lt;br /&gt;
&lt;br /&gt;
				// log a page has been published&lt;br /&gt;
				$log = wire(&amp;#039;log&amp;#039;);&lt;br /&gt;
				$log-&amp;gt;message(&amp;#039;CRON:&amp;#039;. $seconds .&amp;#039; Pages: &amp;#039;. $page-&amp;gt;name .&amp;#039; published&amp;#039;);&lt;br /&gt;
			}else{&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;fieldName, $timeLeft);&lt;br /&gt;
			}&lt;br /&gt;
			// save page time&lt;br /&gt;
			$page-&amp;gt;Save();&lt;br /&gt;
			$page-&amp;gt;of(true);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Install new module specific fields&lt;br /&gt;
	*/&lt;br /&gt;
	private function installFields(){&lt;br /&gt;
&lt;br /&gt;
		// install pub later checkbox field&lt;br /&gt;
		// find installed fields&lt;br /&gt;
		$f = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
		if($f){&lt;br /&gt;
&lt;br /&gt;
			// if field already found then don&amp;#039;t try and make it&lt;br /&gt;
			$this-&amp;gt;message($this-&amp;gt;fieldName . &amp;#039; field found&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
		}else{&lt;br /&gt;
&lt;br /&gt;
			// create new field object to store crontime&lt;br /&gt;
			$f = new Field();&lt;br /&gt;
			// get a field type&lt;br /&gt;
			$f-&amp;gt;type = $this-&amp;gt;modules-&amp;gt;get(&amp;quot;FieldtypeInteger&amp;quot;);&lt;br /&gt;
			$f-&amp;gt;name = $this-&amp;gt;fieldName;&lt;br /&gt;
			$f-&amp;gt;label = &amp;#039;Publish Time Left&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;defaultValue = $this-&amp;gt;defaultTime;&lt;br /&gt;
			$f-&amp;gt;icon = &amp;#039;clock-o&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;columnWidth = 50;&lt;br /&gt;
			$f-&amp;gt;collapsed = 1;&lt;br /&gt;
			$f-&amp;gt;flags = 4;&lt;br /&gt;
&lt;br /&gt;
			$f-&amp;gt;save(); // save the field&lt;br /&gt;
&lt;br /&gt;
			// create new field object to store whether to publish or not&lt;br /&gt;
			$f = new Field();&lt;br /&gt;
			// get a field type&lt;br /&gt;
			$f-&amp;gt;type = $this-&amp;gt;modules-&amp;gt;get(&amp;quot;FieldtypeCheckbox&amp;quot;);&lt;br /&gt;
			$f-&amp;gt;name = $this-&amp;gt;checkboxName;&lt;br /&gt;
			$f-&amp;gt;label = &amp;#039;Publish Page later&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;defaultValue = false;&lt;br /&gt;
			$f-&amp;gt;columnWidth = 50;&lt;br /&gt;
			$f-&amp;gt;icon = &amp;#039;clock-o&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;collapsed = 1;&lt;br /&gt;
			$f-&amp;gt;flags = 4;&lt;br /&gt;
&lt;br /&gt;
			$f-&amp;gt;save(); // save the field&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Uninstall module specific fields&lt;br /&gt;
	*/&lt;br /&gt;
	private function uninstallFields(){&lt;br /&gt;
&lt;br /&gt;
		// find installed fields&lt;br /&gt;
		$fInt = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
		$fCheck = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;checkboxName);&lt;br /&gt;
&lt;br /&gt;
		if($fInt &amp;amp;&amp;amp; $fCheck){&lt;br /&gt;
			$fieldIntUsed = $fInt-&amp;gt;numFieldgroups();&lt;br /&gt;
			$fieldCheckUsed = $fCheck-&amp;gt;numFieldgroups();&lt;br /&gt;
&lt;br /&gt;
			if($fieldIntUsed){&lt;br /&gt;
				// field in use by template&lt;br /&gt;
				$this-&amp;gt;message(&amp;#039;Unable to uninstall field &amp;#039;.$fInt-&amp;gt;name);&lt;br /&gt;
			}else{&lt;br /&gt;
				// delete installed fields&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;delete($fInt);&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;save;&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			if($fieldCheckUsed){&lt;br /&gt;
				// field in use by template&lt;br /&gt;
				$this-&amp;gt;message(&amp;#039;Unable to uninstall field &amp;#039;.$fCheck-&amp;gt;name);&lt;br /&gt;
			}else{&lt;br /&gt;
				// delete installed fields&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;delete($fCheck);&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;save;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Inputfield / Fieldtype ===&lt;br /&gt;
[[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei statt getModuleInfo ===&lt;br /&gt;
Bei größeren Konfigruation (z.B. Admin Page Navigation) sinnvoll.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * ProcessHello.info.php&lt;br /&gt;
 * &lt;br /&gt;
 * Return information about this module.&lt;br /&gt;
 *&lt;br /&gt;
 * If preferred, you can use a getModuleInfo() method in your module file, &lt;br /&gt;
 * or you can use a ModuleName.info.json file (if you prefer JSON definition). &lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
$info = array(&lt;br /&gt;
	// Your module&amp;#039;s title&lt;br /&gt;
	&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello: Process Module Example&amp;#039;, &lt;br /&gt;
	// A 1 sentence description of what your module does&lt;br /&gt;
	&amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;A starting point module skeleton from which to build your own Process module.&amp;#039;, &lt;br /&gt;
	// Module version number: use 1 for 0.0.1 or 100 for 1.0.0, and so on&lt;br /&gt;
	&amp;#039;version&amp;#039; =&amp;gt; 1, &lt;br /&gt;
	// Name of person who created this module (change to your name)&lt;br /&gt;
	&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ryan Cramer&amp;#039;, &lt;br /&gt;
	// Icon to accompany this module (optional), uses font-awesome icon names, minus the &amp;quot;fa-&amp;quot; part&lt;br /&gt;
	&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;thumbs-up&amp;#039;, &lt;br /&gt;
	// URL to more info: change to your full modules.processwire.com URL (if available), or something else if you prefer&lt;br /&gt;
	&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;http://modules.processwire.com/&amp;#039;, &lt;br /&gt;
	// name of permission required of users to execute this Process (optional)&lt;br /&gt;
	&amp;#039;permission&amp;#039; =&amp;gt; &amp;#039;helloworld&amp;#039;, &lt;br /&gt;
	// permissions that you want automatically installed/uninstalled with this module (name =&amp;gt; description)&lt;br /&gt;
	&amp;#039;permissions&amp;#039; =&amp;gt; array(&lt;br /&gt;
		&amp;#039;helloworld&amp;#039; =&amp;gt; &amp;#039;Run the HelloWorld module&amp;#039;&lt;br /&gt;
	), &lt;br /&gt;
	&lt;br /&gt;
	// page that you want created to execute this module&lt;br /&gt;
	&amp;#039;page&amp;#039; =&amp;gt; array(&lt;br /&gt;
		&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;helloworld&amp;#039;,&lt;br /&gt;
		&amp;#039;parent&amp;#039; =&amp;gt; &amp;#039;setup&amp;#039;, &lt;br /&gt;
		&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello World&amp;#039;&lt;br /&gt;
	),&lt;br /&gt;
	// optional extra navigation that appears in admin&lt;br /&gt;
	// if you change this, you&amp;#039;ll need to a Modules &amp;gt; Refresh to see changes&lt;br /&gt;
	&amp;#039;nav&amp;#039; =&amp;gt; array(&lt;br /&gt;
		array(&lt;br /&gt;
			&amp;#039;url&amp;#039; =&amp;gt; &amp;#039;&amp;#039;, &lt;br /&gt;
			&amp;#039;label&amp;#039; =&amp;gt; &amp;#039;Hello&amp;#039;, &lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;smile-o&amp;#039;, &lt;br /&gt;
		), &lt;br /&gt;
		array(&lt;br /&gt;
			&amp;#039;url&amp;#039; =&amp;gt; &amp;#039;something/&amp;#039;, &lt;br /&gt;
			&amp;#039;label&amp;#039; =&amp;gt; &amp;#039;Something&amp;#039;, &lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;beer&amp;#039;, &lt;br /&gt;
		),&lt;br /&gt;
	)&lt;br /&gt;
	// for more options that you may specify here, see the file: /wire/core/Process.php&lt;br /&gt;
	// and the file: /wire/core/Module.php&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Module_schreiben&amp;diff=24846</id>
		<title>ProcessWire - Module schreiben</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Module_schreiben&amp;diff=24846"/>
		<updated>2020-11-04T19:34:36Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Wichtigste Resourcen&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 https://processwire.com/docs/modules/development/ - Guter Ausgangspunkt&lt;br /&gt;
 https://processwire.com/api/ref/module/ - Module API&lt;br /&gt;
 https://processwire.com/api/ref/configurable-module/ - Klasse für Konfigurierbare Module&lt;br /&gt;
 https://processwire.com/docs/modules/types/ - Welche Modultypen gibt es ?&lt;br /&gt;
 https://processwire.com/talk/topic/778-module-dependencies/ - Module die andere Module benötigen&lt;br /&gt;
 https://processwire.com/talk/forum/19-moduleplugin-development/ - Forum zum Thema Module entwickeln&lt;br /&gt;
 http://somatonic.github.io/Captain-Hook/ - Hook Cheatsheet&lt;br /&gt;
 https://processwire.com/blog/posts/new-module-configuration-options/ - Neuere Konfigurationsmöglichkeiten&lt;br /&gt;
 https://processwire.com/docs/start/api-access/ Zugriff auf ProcessWire API Variablen (wire Objekt)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039; Tutorials und Beispiele zum Einstieg &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 https://processwire.com/docs/modules/ - Introduction, Development, Hooks, Types, Pro Modules, Third Party&lt;br /&gt;
 https://github.com/ryancramerdesign/ProcessHello - Modul Skelett Beispiel für eigene Backend (Process) Module&lt;br /&gt;
 https://github.com/ryancramerdesign/FieldtypeMapMarker - Beispiel für ein Fieldtype und Inputfield Modul&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/a-beginners-introduction-to-writing-modules-in-processwire--cms-26862&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Wikiseiten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 [[ProcessWire - Module Snippets]]&lt;br /&gt;
 [[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Weitere Links&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 http://modules.pw/ (Module Creator)&lt;br /&gt;
&lt;br /&gt;
== Wo - Was ? ==&lt;br /&gt;
=== Welche Typen von Modulen gibt es ? ===&lt;br /&gt;
 https://processwire.com/docs/modules/types/&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Fieldtype&amp;#039;&amp;#039;&amp;#039;: Repräsentiert einen Datentyp. Meistens keine Public API, Handelt Daten / Datenbank - [[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Inputfield&amp;#039;&amp;#039;&amp;#039;: Sammelt User Eingaben über ein Formular im Admin Bereich. Im Gegensatz zum Fieldtype geht es hier um das UI im Backend. Das Handling der Daten liegt beim Fieldtype.&lt;br /&gt;
* [[Process Module (ProcessWire)|&amp;#039;&amp;#039;&amp;#039;Process&amp;#039;&amp;#039;&amp;#039; for creating admin processes/applications.]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Textformatter&amp;#039;&amp;#039;&amp;#039; for formatting text.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminTheme&amp;#039;&amp;#039;&amp;#039; for creating themes in the admin.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;WireMail&amp;#039;&amp;#039;&amp;#039; for modules that send email and extend the WireMail class.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tfa&amp;#039;&amp;#039;&amp;#039; for implementing a specific kind of two-factor authentication.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ImageSizerEngine&amp;#039;&amp;#039;&amp;#039; for modules that extend ImageSizerEngine for resizing images.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FileCompiler&amp;#039;&amp;#039;&amp;#039; for modules that extend FileCompilerModule for compilation of files.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FileValidator&amp;#039;&amp;#039;&amp;#039; for modules that extend FileValidatorModule for validation of files.&lt;br /&gt;
&lt;br /&gt;
=== Wie werden Felder in der Datenbank angelegt ? ===&lt;br /&gt;
Dazu nutzt man den Typ &amp;quot;Fieldtype&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Wo rendert man die Ausgabe ? ===&lt;br /&gt;
Bei Ryan Cramers Event Beispiel legt er zwei Klassen Event und EventArray an, die auch die Render Funktionen enthalten.&lt;br /&gt;
=== Namenskonvention ===&lt;br /&gt;
Ein Modulname sollte mit dem Typ den das Modul hat beginnen. Also etwa ProcessMeinAdminModul oder FieldtypeTable. ProcessWire listet das Modul dann in der Entsprechenden Kategorie auf. Wenn man etwas anderes nimmt z.B. LoginRegister dann kommt das Modul unter der neuen Rubrik &amp;quot;Login&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Spezielle Funktionen in Modulen ==&lt;br /&gt;
&lt;br /&gt;
=== getModuleInfo ===&lt;br /&gt;
Ist die einzige Pflichtfunktion in Modulen. Hier werden title, version, summary und weitere Daten hinterlegt. Hier kann man auch angeben ob ein Modul ein Autoload Modul ist.&lt;br /&gt;
&lt;br /&gt;
Statt einer getModuleInfo() Funktion kann man auch eine json Konfiguration als Datei hinterlegen&lt;br /&gt;
&lt;br /&gt;
Siehe Beispiel unten&lt;br /&gt;
&lt;br /&gt;
=== init ===&lt;br /&gt;
 public function init(){}&lt;br /&gt;
Initialisiert das Modul. ProcessWire ruft diese Funktion auf, wenn das Modul geladen ist. Bei Autoload Modulen wird es aufgerufen wenn die ProcessWire API bereit ist. Daher ist es ein guter Ort um Hooks einzubinden.&lt;br /&gt;
&lt;br /&gt;
=== ready ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  public function ready() {&lt;br /&gt;
    if($this-&amp;gt;page-&amp;gt;template == &amp;#039;admin&amp;#039;) {&lt;br /&gt;
      $this-&amp;gt;message($this-&amp;gt;hi());&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird in autoload Modulen aufgerufen wenn die API bereit ist. Nützlich für Hooks:&lt;br /&gt;
&lt;br /&gt;
=== execute ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	/**&lt;br /&gt;
	 * This function is executed when a page with your Process assigned is accessed. &lt;br /&gt;
 	 *&lt;br /&gt;
	 * This can be seen as your main or index function. You&amp;#039;ll probably want to replace&lt;br /&gt;
	 * everything in this function. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___execute() {&lt;br /&gt;
		// greetingType and greeting are automatically populated to this module&lt;br /&gt;
		// and they were defined in ProcessHello.config.php&lt;br /&gt;
		if($this-&amp;gt;greetingType == &amp;#039;message&amp;#039;) {&lt;br /&gt;
			$this-&amp;gt;message($this-&amp;gt;greeting); &lt;br /&gt;
		} else if($this-&amp;gt;greetingType == &amp;#039;warning&amp;#039;) {&lt;br /&gt;
			$this-&amp;gt;warning($this-&amp;gt;greeting); &lt;br /&gt;
		} else {&lt;br /&gt;
			$this-&amp;gt;error($this-&amp;gt;greeting); &lt;br /&gt;
		}&lt;br /&gt;
		// generate some navigation&lt;br /&gt;
		$out = 	&amp;quot;&lt;br /&gt;
			&amp;lt;h2&amp;gt;$this-&amp;gt;greeting&amp;lt;/h2&amp;gt;&lt;br /&gt;
			&amp;lt;dl class=&amp;#039;nav&amp;#039;&amp;gt;&lt;br /&gt;
				&amp;lt;dt&amp;gt;&amp;lt;a href=&amp;#039;./something/&amp;#039;&amp;gt;Do Something&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;&lt;br /&gt;
				&amp;lt;dd&amp;gt;Runs the executeSomething() function.&amp;lt;/dd&amp;gt;&lt;br /&gt;
			&amp;lt;/dl&amp;gt;&lt;br /&gt;
			&amp;quot;;&lt;br /&gt;
		return $out;&lt;br /&gt;
	}	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== executeSomething ===&lt;br /&gt;
Ruft man eine Unterseite des Moduls auf kann man eine eigene execute Funktion nutzen&lt;br /&gt;
___executeSlug wobei Slug für den Url Slug steht. Heißt der slug /field/ dann wird executeField() aufgerufen, falls diese Funktion existiert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	/**&lt;br /&gt;
	 * Called when the URL is this module&amp;#039;s page URL + &amp;quot;/something/&amp;quot;&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___executeSomething() {&lt;br /&gt;
		// set a new headline, replacing the one used by our page&lt;br /&gt;
		// this is optional as PW will auto-generate a headline &lt;br /&gt;
		$this-&amp;gt;headline(&amp;#039;This is something!&amp;#039;); &lt;br /&gt;
		// add a breadcrumb that returns to our main page &lt;br /&gt;
		// this is optional as PW will auto-generate breadcrumbs&lt;br /&gt;
		$this-&amp;gt;breadcrumb(&amp;#039;../&amp;#039;, &amp;#039;Hello&amp;#039;); &lt;br /&gt;
		$out = 	&amp;quot;&lt;br /&gt;
			&amp;lt;h2&amp;gt;Not much to to see here&amp;lt;/h2&amp;gt;&lt;br /&gt;
			&amp;lt;p&amp;gt;&amp;lt;a href=&amp;#039;../&amp;#039;&amp;gt;Go Back&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
			&amp;quot;;&lt;br /&gt;
		return $out; &lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== install &amp;amp; uninstall ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
	 * Called only when your module is installed&lt;br /&gt;
	 *&lt;br /&gt;
	 * If you don&amp;#039;t need anything here, you can simply remove this method. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___install() {&lt;br /&gt;
		parent::___install(); // always remember to call parent method&lt;br /&gt;
	}&lt;br /&gt;
	/**&lt;br /&gt;
	 * Called only when your module is uninstalled&lt;br /&gt;
	 *&lt;br /&gt;
	 * This should return the site to the same state it was in before the module was installed. &lt;br /&gt;
	 *&lt;br /&gt;
	 * If you don&amp;#039;t need anything here, you can simply remove this method. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function ___uninstall() {&lt;br /&gt;
		parent::___uninstall(); // always remember to call parent method&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vererbung und Eigenschaften in Modulen ==&lt;br /&gt;
Modules are not different from PHP classes.&lt;br /&gt;
&lt;br /&gt;
To change the properties of MyModule class from within MyOtherModule class, you can either:&lt;br /&gt;
&lt;br /&gt;
#Make MyOtherModule class extend MyModule. It will thus inherit MyModule&amp;#039;s public and protected properties and methods&lt;br /&gt;
#Make the properties firstName and lastName configurable by passing them as parameters/arguments in MyModule&amp;#039;s constructor method.&lt;br /&gt;
&lt;br /&gt;
== Autoload Module und Hooks ==&lt;br /&gt;
Autoload werden automatisch geladen müssen also nicht in einem Template o.ä. gestartet werden. Daher bieten sie sich an um die Funktionalität von ProcessWire zu erweitern. Als Werkzeug dafür dienen Hooks. Mit Hooks kann man an vielen Stellen den Rendering Process der Seiten beeinflussen. Außerdem kann man für eigene Module ebenfalls Hooks bereitstellen. &lt;br /&gt;
&lt;br /&gt;
=== Hooks ===&lt;br /&gt;
 https://processwire.com/docs/modules/hooks/&lt;br /&gt;
Hooks sind ein mächtiges Werkzeug. Sie geben einem die Möglichkeit an vielen Stellen &amp;quot;einzuhaken&amp;quot; und Funktionalität einzubauen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, function($event) {&lt;br /&gt;
    $event-&amp;gt;return .= &amp;#039;&amp;lt;p&amp;gt;Hallo&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Schreibt am Ende Jeder Seite ein &amp;quot;Hallo&amp;quot;. Das $event Objekt ist ein [https://processwire.com/api/ref/hook-event/ HookEvent]. Im Beispiel fügen wir einfach etwas Markup hinzu. Über $event-&amp;gt;arguments() kann man aber auf ale Argumente zugreifen.&lt;br /&gt;
&lt;br /&gt;
Das gleiche aber nicht mit anonymer Funktion:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  // add hook after Page::render() and make it call the &amp;quot;test&amp;quot; method of $this module&lt;br /&gt;
  $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, $this, &amp;#039;test&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public function test($event) {&lt;br /&gt;
  // modify the return value of Page::render() to include the following:&lt;br /&gt;
  $event-&amp;gt;return .= &amp;#039;&amp;lt;p&amp;gt;Hallo&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hooks zum erweitern von existierenden Klassen nutzen ===&lt;br /&gt;
Mit Hooks kann man in vorhandene Klassen einhaken. Z.B. läßt sich das Page Objekt erweitern.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function ready() {&lt;br /&gt;
  $this-&amp;gt;addHook(&amp;#039;Page::summarize&amp;#039;, $this, &amp;#039;summarize&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
public function summarize($event) {&lt;br /&gt;
  $page = $event-&amp;gt;object; // the $event-&amp;gt;object represents the object hooked (Page)&lt;br /&gt;
  $maxlen = $event-&amp;gt;arguments(0); // first argument is the optional max length&lt;br /&gt;
  if(!$maxlen) $maxlen = 200; // if no $maxlen was present, we&amp;#039;ll use a default of 200&lt;br /&gt;
  $summary = $this-&amp;gt;sanitizer-&amp;gt;truncate($page-&amp;gt;body, $maxlen); // use sanitizer truncate method to create a summary&lt;br /&gt;
  $event-&amp;gt;return = $summary; // populate $summary to $event-&amp;gt;return, the return value&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So kann man ganz einfach eine Zusammenfassung aller Kindseiten in einem Template rendern:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
foreach($page-&amp;gt;children as $item) {&lt;br /&gt;
  $summary = $item-&amp;gt;summarize(150);&lt;br /&gt;
  echo &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;$item-&amp;gt;url&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;$summary&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Autoload Module nur im Admin Bereich laden ===&lt;br /&gt;
&lt;br /&gt;
 &amp;#039;autoload&amp;#039; =&amp;gt; &amp;#039;template=admin&amp;#039; &lt;br /&gt;
statt&lt;br /&gt;
 &amp;#039;autoload&amp;#039; =&amp;gt; true&lt;br /&gt;
&lt;br /&gt;
=== Hook Beispiele ===&lt;br /&gt;
Hook am Ende des Renderings&lt;br /&gt;
 $this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, function($event) {...});&lt;br /&gt;
Füge eine Funktion &amp;quot;summarize&amp;quot; zum Page Objekt hinzu.&lt;br /&gt;
 $this-&amp;gt;addHook(&amp;#039;Page::summarize&amp;#039;, $this, &amp;#039;summarize&amp;#039;);&lt;br /&gt;
Hook auf eine einzelne Instanz (hier pages Objekt)&lt;br /&gt;
 $this-&amp;gt;pages-&amp;gt;addHookAfter(&amp;#039;saved&amp;#039;, function($event){...});&lt;br /&gt;
 $this-&amp;gt;addHook(&amp;#039;Page::method&amp;#039;, ...) // Spricht ALLE Instanzen an - Regelfall&lt;br /&gt;
 $page-&amp;gt;addHook(&amp;#039;method&amp;#039;, ...) // Spricht nur die EINE Instanz der Seite an.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Module Dependencies - voneinander abhängige Module ==&lt;br /&gt;
&lt;br /&gt;
 https://processwire.com/talk/topic/778-module-dependencies/&lt;br /&gt;
Wenn ein Modul nicht ohne ein anderes funktioniert spricht man von Module Dependency. In solchen Fällen kann man in der Modul Info angeben In vielen Fällen besteht ein Modul unter der Haube aus mehreren Einzelmodulen.&lt;br /&gt;
&lt;br /&gt;
Um ProcessWire mitzuteilen dass ein Modul benötigt wird gibt man es in der Moduldefinition an:&lt;br /&gt;
 &amp;#039;requires&amp;#039; =&amp;gt; &amp;quot;LazyCron&amp;quot;  // added this line&lt;br /&gt;
oder auch mehrere als Array&lt;br /&gt;
 &amp;#039;requires&amp;#039; =&amp;gt; array(&amp;quot;LazyCron&amp;quot;, &amp;quot;AdminBar&amp;quot;)  // added this line&lt;br /&gt;
&lt;br /&gt;
ProcessWire kann auch dafür sorgen, dass ein Modul andere &amp;quot;Kindmodule&amp;quot; gleich mitinstalliert bzw. deinstalliert wenn es nicht mehr benötigt wird. Dazu gibt man dem Modul noch die &amp;#039;install&amp;#039; dependency mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
public static function getModuleInfo() {&lt;br /&gt;
   return array(&lt;br /&gt;
       &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Log Master&amp;#039;,&lt;br /&gt;
       &amp;#039;version&amp;#039; =&amp;gt; 101,&lt;br /&gt;
       &amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Lumberjack Bob&amp;#039;,&lt;br /&gt;
       &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Log all actions on your site&amp;#039;,&lt;br /&gt;
       &amp;#039;requires&amp;#039; =&amp;gt; &amp;#039;LazyCron&amp;#039;, &lt;br /&gt;
       &amp;#039;installs&amp;#039; =&amp;gt; &amp;#039;ProcessLogMaster&amp;#039;  // added this line&lt;br /&gt;
       ); &lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProcessWire sieht dann eine Kindabhängigkeit zu diesem Modul und handelt auch das Deinstallieren, wenn das Elternmodul deinstalliert wird.&lt;br /&gt;
&lt;br /&gt;
== CSS und JavaScript in Modulen ==&lt;br /&gt;
Bei Process Modulen möchte man für das Styling etc. im Backend oft CSS und JS Dateien hinzufügen.&lt;br /&gt;
&lt;br /&gt;
Einfach Eine Datei MeinModul.css und / oder MeinModul.js hinzufügen. JQuery ist im Admin bereits geladen daher kann eine MeinModul.js Starter Datei so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This JS file is only loaded when the ProcessHello module is run&lt;br /&gt;
 *&lt;br /&gt;
 * You should delete it if you have no javascript to add.&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
$(document).ready(function() {&lt;br /&gt;
	// do something&lt;br /&gt;
}); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Frontend Rendering Module ===&lt;br /&gt;
A bit old but working&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * FrontEndRender&lt;br /&gt;
 *&lt;br /&gt;
 * Author: Ben Byford&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2010 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class FrontEndRender extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;FrontEndRender&amp;#039;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 0.1,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;Outputs html and static variables to frontend&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ben Byford&amp;#039;,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://github.com/benbyford/PW-starter-modules&amp;#039;&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// protected variable only accessable within module&lt;br /&gt;
	protected $name = &amp;#039;Ben&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* render function to be called in PW template like this:&lt;br /&gt;
	* $FrontEndRender = $modules-&amp;gt;getModule(&amp;#039;FrontEndRender&amp;#039;);&lt;br /&gt;
	* echo &amp;#039;&amp;lt;h1&amp;gt;&amp;#039; . $FrontEndRender-&amp;gt;render() . &amp;#039;&amp;lt;/h1&amp;gt;&amp;#039;;&lt;br /&gt;
	*&lt;br /&gt;
	*/&lt;br /&gt;
	public function render(){&lt;br /&gt;
		return &amp;quot;Hello &amp;quot; . $this-&amp;gt;name;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Hello World Modul ===&lt;br /&gt;
Beispiel Modul mit Hooks (liegt immer in der Standardinstallation)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * ProcessWire &amp;#039;Hello world&amp;#039; demonstration module&lt;br /&gt;
 *&lt;br /&gt;
 * Demonstrates the Module interface and how to add hooks.&lt;br /&gt;
 * &lt;br /&gt;
 * See README file for further links regarding module development.&lt;br /&gt;
 * &lt;br /&gt;
 * This file is licensed under the MIT license&lt;br /&gt;
 * https://processwire.com/about/license/mit/&lt;br /&gt;
 * &lt;br /&gt;
 * ProcessWire 3.x, Copyright 2016 by Ryan Cramer&lt;br /&gt;
 * https://processwire.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class Helloworld extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * getModuleInfo is a module required by all modules to tell ProcessWire about them&lt;br /&gt;
	 *&lt;br /&gt;
	 * @return array&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
&lt;br /&gt;
		return array(&lt;br /&gt;
&lt;br /&gt;
			// The module&amp;#039;s title, typically a little more descriptive than the class name&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello World&amp;#039;, &lt;br /&gt;
&lt;br /&gt;
			// version number &lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 3, &lt;br /&gt;
&lt;br /&gt;
			// summary is brief description of what this module is&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;An example module used for demonstration purposes.&amp;#039;,&lt;br /&gt;
			&lt;br /&gt;
			// Optional URL to more information about the module&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://processwire.com&amp;#039;,&lt;br /&gt;
&lt;br /&gt;
			// singular=true: indicates that only one instance of the module is allowed.&lt;br /&gt;
			// This is usually what you want for modules that attach hooks. &lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true, &lt;br /&gt;
&lt;br /&gt;
			// autoload=true: indicates the module should be started with ProcessWire.&lt;br /&gt;
			// This is necessary for any modules that attach runtime hooks, otherwise those&lt;br /&gt;
			// hooks won&amp;#039;t get attached unless some other code calls the module on it&amp;#039;s own.&lt;br /&gt;
			// Note that autoload modules are almost always also &amp;#039;singular&amp;#039; (seen above).&lt;br /&gt;
			&amp;#039;autoload&amp;#039; =&amp;gt; true, &lt;br /&gt;
		&lt;br /&gt;
			// Optional font-awesome icon name, minus the &amp;#039;fa-&amp;#039; part&lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;smile-o&amp;#039;, &lt;br /&gt;
			);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Initialize the module&lt;br /&gt;
	 *&lt;br /&gt;
	 * ProcessWire calls this when the module is loaded. For &amp;#039;autoload&amp;#039; modules, this will be called&lt;br /&gt;
	 * when ProcessWire&amp;#039;s API is ready. As a result, this is a good place to attach hooks. &lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function init() {&lt;br /&gt;
&lt;br /&gt;
		// add a hook after the $pages-&amp;gt;save, to issue a notice every time a page is saved&lt;br /&gt;
		$this-&amp;gt;pages-&amp;gt;addHookAfter(&amp;#039;save&amp;#039;, $this, &amp;#039;example1&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a hook after each page is rendered and modify the output&lt;br /&gt;
		$this-&amp;gt;addHookAfter(&amp;#039;Page::render&amp;#039;, $this, &amp;#039;example2&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a &amp;#039;hello&amp;#039; method to every page that returns &amp;quot;Hello World&amp;quot;&lt;br /&gt;
		// use &amp;quot;echo $page-&amp;gt;hello();&amp;quot; in your template file to display output&lt;br /&gt;
		$this-&amp;gt;addHook(&amp;#039;Page::hello&amp;#039;, $this, &amp;#039;example3&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
		// add a &amp;#039;hello_world&amp;#039; property to every page that returns &amp;quot;Hello [user]&amp;quot;&lt;br /&gt;
		// use &amp;quot;echo $page-&amp;gt;hello_world;&amp;quot; in your template file to display output&lt;br /&gt;
		$this-&amp;gt;addHookProperty(&amp;#039;Page::hello_world&amp;#039;, $this, &amp;#039;example4&amp;#039;); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example1 hooks into the pages-&amp;gt;save method and displays a notice every time a page is saved&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example1($event) {&lt;br /&gt;
		/** @var Page $page */&lt;br /&gt;
		$page = $event-&amp;gt;arguments[0]; &lt;br /&gt;
		$this-&amp;gt;message(&amp;quot;Hello World! You saved {$page-&amp;gt;path}.&amp;quot;); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example2 hooks into every page after it&amp;#039;s rendered and adds &amp;quot;Hello World&amp;quot; text at the bottom&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example2($event) {&lt;br /&gt;
&lt;br /&gt;
		/** @var Page $page */&lt;br /&gt;
		$page = $event-&amp;gt;object; &lt;br /&gt;
&lt;br /&gt;
		// don&amp;#039;t add this to the admin pages&lt;br /&gt;
		if($page-&amp;gt;template == &amp;#039;admin&amp;#039;) return;&lt;br /&gt;
&lt;br /&gt;
		// add a &amp;quot;Hello World&amp;quot; paragraph right before the closing body tag&lt;br /&gt;
		$event-&amp;gt;return = str_replace(&amp;quot;&amp;lt;/body&amp;gt;&amp;quot;, &amp;quot;&amp;lt;p&amp;gt;Hello World!&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;quot;, $event-&amp;gt;return); &lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example3 adds a &amp;#039;hello&amp;#039; method (not property) to every page that simply returns &amp;quot;Hello World&amp;quot;&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example3($event) {&lt;br /&gt;
		$event-&amp;gt;return = &amp;quot;Hello World&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Example 4 adds a &amp;#039;hello_world&amp;#039; property (not method) to every page that returns &amp;quot;Hello [user]&amp;quot;&lt;br /&gt;
	 * &lt;br /&gt;
	 * @param HookEvent $event&lt;br /&gt;
	 *&lt;br /&gt;
	 */&lt;br /&gt;
	public function example4($event) {&lt;br /&gt;
		$event-&amp;gt;return = &amp;quot;Hello &amp;quot; . $this-&amp;gt;user-&amp;gt;name; &lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Admin Bereich mit eigener Funktionalität erweitern (Modul)===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
* ProcessSimpleAdminPage&lt;br /&gt;
*&lt;br /&gt;
* @author Ben Byford&lt;br /&gt;
* http://www.benbyford.com&lt;br /&gt;
*&lt;br /&gt;
* @see http://www.processwire.com&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
class ProcessSimpleAdminPage extends Process {&lt;br /&gt;
&lt;br /&gt;
    public static function getModuleInfo() {&lt;br /&gt;
        return array(&lt;br /&gt;
            &amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Process Simple Admin Page&amp;#039;,&lt;br /&gt;
            &amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;Simple Process module that adds new admin page with&amp;#039;,&lt;br /&gt;
            &amp;#039;version&amp;#039; =&amp;gt; 001,&lt;br /&gt;
&lt;br /&gt;
            // Modules that extend Process may specify a &amp;#039;page&amp;#039; attribute in the&lt;br /&gt;
            // getModuleInfo(), this page will automatically be given the module&lt;br /&gt;
            // process when added to teh pagetree.&lt;br /&gt;
&lt;br /&gt;
            // I have exampled but commented out the &amp;#039;page&amp;#039; settings below&lt;br /&gt;
            // so that I can show how one might add a page to install() and&lt;br /&gt;
            // uninstall() in this and other modules (that might not extend&lt;br /&gt;
            // Process)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        // 	&amp;#039;page&amp;#039; =&amp;gt; array(&lt;br /&gt;
        // 		&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;site-config&amp;#039;,&lt;br /&gt;
        // 		&amp;#039;parent&amp;#039; =&amp;gt; &amp;#039;admin&amp;#039;,&lt;br /&gt;
        // 		&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Site Config&amp;#039;&lt;br /&gt;
        // 	   )&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function execute() {&lt;br /&gt;
        return &amp;#039;&lt;br /&gt;
            &amp;lt;h2&amp;gt;Edit the text here in the module&amp;lt;/h2&amp;gt;&lt;br /&gt;
            &amp;lt;p&amp;gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mattis eros vitae metus sodales eget suscipit purus rhoncus. Proin ultrices gravida dolor, non porttitor enim interdum vitae. Integer feugiat lacinia tincidunt. Nulla laoreet tristique tristique. Sed elementum justo a nisl elementum sit amet accumsan nisi tempor. Nulla quis eros et massa dignissim imperdiet a vitae purus.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Donec scelerisque pulvinar sem eu lobortis. Maecenas turpis ipsum, tempus dictum pharetra eu, consectetur vitae arcu. Fusce orci mauris, semper at tempus quis, volutpat molestie tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed quam tortor, tincidunt sed semper lacinia, scelerisque dapibus quam. Morbi at nisi luctus lacus auctor ultrices eu eu leo.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Praesent faucibus purus id felis tincidunt dignissim. Sed sit amet ligula mi, eget semper dui. Proin consectetur gravida massa, nec luctus purus hendrerit in. Etiam volutpat, elit non venenatis suscipit, libero neque consectetur diam, id rutrum magna odio ac ligula. Maecenas sollicitudin congue neque fermentum vestibulum. Morbi nec leo nisi. Donec at nisl odio, et porta ligula.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;p&amp;gt;Sed quis arcu nisi, ac tempor augue. Praesent non elit libero, a ullamcorper lorem. Curabitur porta odio eu nunc ultricies interdum id nec risus. Donec nibh nibh, porta eget vehicula ac, aliquet eget ante. Phasellus eget lorem eu eros eleifend ultrices. Cras sit amet neque sit amet nibh fringilla cursus ut id mauris. Praesent quis nunc justo, sed suscipit lectus. Phasellus eget ultrices risus. Curabitur eu semper est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut suscipit, nisl ut imperdiet eleifend, turpis arcu placerat tortor, nec laoreet lacus neque ac tellus. Aenean ac lacus justo, quis ultricies nisi.&amp;lt;/p&amp;gt;&lt;br /&gt;
            &amp;#039;;&lt;br /&gt;
    }&lt;br /&gt;
    public function install(){&lt;br /&gt;
&lt;br /&gt;
        // create new page to add to CMS&lt;br /&gt;
		$page = new Page();&lt;br /&gt;
&lt;br /&gt;
        // add page attributes&lt;br /&gt;
        $page-&amp;gt;template = &amp;quot;admin&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;name = &amp;quot;cms-faq&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;title = &amp;quot;CMS FAQ&amp;quot;;&lt;br /&gt;
        $page-&amp;gt;save();&lt;br /&gt;
&lt;br /&gt;
        // set this module as the page process, this allows us to display the above&lt;br /&gt;
        $page-&amp;gt;process = &amp;#039;ProcessSimpleAdminPage&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
        // get admin page and set as page parent&lt;br /&gt;
        $admin = $this-&amp;gt;pages-&amp;gt;get(&amp;quot;id=2&amp;quot;);&lt;br /&gt;
        $page-&amp;gt;parent = $admin;&lt;br /&gt;
&lt;br /&gt;
        // save page&lt;br /&gt;
        $page-&amp;gt;save();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function uninstall(){&lt;br /&gt;
&lt;br /&gt;
        // delete created page&lt;br /&gt;
        $page = $this-&amp;gt;pages-&amp;gt;get(&amp;quot;name=cms-faq&amp;quot;);&lt;br /&gt;
        if(count($page)) $this-&amp;gt;pages-&amp;gt;delete($page, true);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ProcessWire Textformatter Modul ===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * TextformatterFindReplace&lt;br /&gt;
 *&lt;br /&gt;
 * Author: Ben Byford&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2010 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class TextformatterFindReplace extends Textformatter implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;TextformatterFindReplace&amp;#039;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; 0.1,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;Finds and replaces any instance of config input to config output&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ben Byford&amp;#039;,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;https://github.com/benbyford/PW-starter-modules&amp;#039;&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
     * Find and Replace the input string&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $str The block of text to parse&lt;br /&gt;
     *&lt;br /&gt;
     * The incoming string is replaced with the formatted version of itself.&lt;br /&gt;
	 **/&lt;br /&gt;
&lt;br /&gt;
	public function format(&amp;amp;$str) {&lt;br /&gt;
		$find = $this-&amp;gt;findStr;&lt;br /&gt;
		$str = preg_replace_callback($find, array($this,&amp;quot;replace&amp;quot;), $str);&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// adding three underscores to a function allows other modules to hook it&lt;br /&gt;
	public function ___replace($match) {&lt;br /&gt;
		return $this-&amp;gt;replaceStr;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Admin Funktionalität: Countdown zum Seitenveröffentlichen ===&lt;br /&gt;
 https://webdesign.tutsplus.com/tutorials/extending-the-processwire-admin-using-custom-modules--cms-26863&lt;br /&gt;
&lt;br /&gt;
The module PageDeferredPublish, on clicking one of the &amp;#039;&amp;#039;&amp;#039;Publish Later buttons&amp;#039;&amp;#039;&amp;#039;, sets LazyCron to check that page’s countdown every minute and publishes the page when its countdown reaches 0. This means I can publish a page approximately 24 hours in advance (obviously the checking interval and delay time can be changed to your requirements).&lt;br /&gt;
&lt;br /&gt;
I did this by:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Creating two fields&amp;#039;&amp;#039;&amp;#039; within my install() function: a checkbox field to set to true when a button is checked to indicate the page should countdown, and a countdown field to store the count in seconds for that specific page.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Adding hooks&amp;#039;&amp;#039;&amp;#039; to both &amp;#039;&amp;#039;ProcessPageEdit::buildForm&amp;#039;&amp;#039; and &amp;#039;&amp;#039;ProcessPageListActions::getExtraActions&amp;#039;&amp;#039; enabling me to add the two buttons.&lt;br /&gt;
&lt;br /&gt;
Checking to see if one of the buttons was clicked with my &amp;#039;&amp;#039;&amp;#039;ready() function&amp;#039;&amp;#039;&amp;#039; then setting the corresponding page’s checkbox to true.&lt;br /&gt;
&lt;br /&gt;
Using a &amp;#039;&amp;#039;&amp;#039;LazyCron hook function&amp;#039;&amp;#039;&amp;#039; to check all pages that are unpublished for true checkboxes and then comparing the seconds field to see if the page needs publishing. If not then deduct the elapsed time in seconds.&lt;br /&gt;
&lt;br /&gt;
The result is a &amp;#039;&amp;#039;&amp;#039;module that has settings&amp;#039;&amp;#039;&amp;#039; (the time interval to check and publish at a later time), &amp;#039;&amp;#039;&amp;#039;hooks into the admin&amp;#039;&amp;#039;&amp;#039; using buttons and fields, and enables us to &amp;#039;&amp;#039;&amp;#039;use other modules installe&amp;#039;&amp;#039;&amp;#039;d in PW (i.e. LazyCron).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * DeferredPublish (0.0.1)&lt;br /&gt;
 * DeferredPublish publishes a page after a defined amount of time has elapsed using lazycron.&lt;br /&gt;
 *&lt;br /&gt;
 * @author Ben Byford&lt;br /&gt;
 * http://www.benbyford.com&lt;br /&gt;
 *&lt;br /&gt;
 * ProcessWire 2.x&lt;br /&gt;
 * Copyright (C) 2011 by Ryan Cramer&lt;br /&gt;
 * Licensed under GNU/GPL v2, see LICENSE.TXT&lt;br /&gt;
 *&lt;br /&gt;
 * http://www.processwire.com&lt;br /&gt;
 * http://www.ryancramer.com&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class PageDeferredPublish extends WireData implements Module {&lt;br /&gt;
&lt;br /&gt;
	public static function getModuleInfo() {&lt;br /&gt;
		return array(&lt;br /&gt;
			&amp;#039;title&amp;#039; =&amp;gt; &amp;quot;PageDeferredPublish&amp;quot;,&lt;br /&gt;
			&amp;#039;version&amp;#039; =&amp;gt; &amp;quot;0.0.1&amp;quot;,&lt;br /&gt;
			&amp;#039;summary&amp;#039; =&amp;gt; &amp;quot;PageDeferredPublish&amp;quot;,&lt;br /&gt;
			&amp;#039;author&amp;#039; =&amp;gt; &amp;quot;Ben Byford&amp;quot;,&lt;br /&gt;
			&amp;#039;href&amp;#039; =&amp;gt; &amp;quot;https://github.com/benbyford/PW-intermediate-modules&amp;quot;,&lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;quot;clock-o&amp;quot;,&lt;br /&gt;
			&amp;#039;autoload&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;singular&amp;#039; =&amp;gt; true,&lt;br /&gt;
			&amp;#039;requires&amp;#039; =&amp;gt; &amp;quot;LazyCron&amp;quot;,&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	private $postPubLater 	= null;&lt;br /&gt;
	private $pageID 		= null;&lt;br /&gt;
	private $pagePubLater 	= null;&lt;br /&gt;
	private $currentPage	= null;&lt;br /&gt;
&lt;br /&gt;
	private $submitName 	= &amp;#039;pdp_pub_later_submit&amp;#039;;&lt;br /&gt;
	private $listPageName	= &amp;#039;pdp_pub_later_list&amp;#039;;&lt;br /&gt;
	private $fieldName 		= &amp;#039;pdp_pub_later&amp;#039;;&lt;br /&gt;
	private $checkboxName	= &amp;#039;pdp_pub_later_check&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	private $defaultInterval = &amp;#039;everyMinute&amp;#039;;&lt;br /&gt;
	private $defaultTime 	= 86400;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	public function install(){&lt;br /&gt;
		// add new fields needed for module&lt;br /&gt;
		$this-&amp;gt;installFields();&lt;br /&gt;
	}&lt;br /&gt;
	public function uninstall(){&lt;br /&gt;
		// uninstall fields&lt;br /&gt;
		$this-&amp;gt;uninstallFields();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// initialize the hook in your AutoLoad module&lt;br /&gt;
	public function init() {&lt;br /&gt;
&lt;br /&gt;
		// get defaults from module setting in CMS&lt;br /&gt;
		$this-&amp;gt;defaultTime = $this-&amp;gt;pub_after;&lt;br /&gt;
		$this-&amp;gt;defaultInterval = $this-&amp;gt;cron_check;&lt;br /&gt;
&lt;br /&gt;
		// get admin URL&lt;br /&gt;
		$this-&amp;gt;adminUrl = $this-&amp;gt;wire(&amp;#039;config&amp;#039;)-&amp;gt;urls-&amp;gt;admin;&lt;br /&gt;
&lt;br /&gt;
		// add hooks to CRON, PageList, PageEdit&lt;br /&gt;
	    $this-&amp;gt;addHookAfter(&amp;quot;LazyCron::{$this-&amp;gt;defaultInterval}&amp;quot;, $this, &amp;#039;publishDefferedPages&amp;#039;);&lt;br /&gt;
		$this-&amp;gt;addHook(&amp;quot;ProcessPageListActions::getExtraActions&amp;quot;, $this, &amp;#039;hookPageListActions&amp;#039;);&lt;br /&gt;
		$this-&amp;gt;addHookAfter(&amp;quot;ProcessPageEdit::buildForm&amp;quot;, $this, &amp;quot;editForm&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function ready() {&lt;br /&gt;
&lt;br /&gt;
		// if list button clicked then grab id&lt;br /&gt;
		$this-&amp;gt;pagePubLater = $this-&amp;gt;input-&amp;gt;get($this-&amp;gt;listPageName);&lt;br /&gt;
		$this-&amp;gt;pageID = $this-&amp;gt;input-&amp;gt;id;&lt;br /&gt;
&lt;br /&gt;
		// get page&lt;br /&gt;
		$this-&amp;gt;currentPage = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;pageID);&lt;br /&gt;
&lt;br /&gt;
		// if pagelist pub later submit button clicked&lt;br /&gt;
		if($this-&amp;gt;pagePubLater){&lt;br /&gt;
			$this-&amp;gt;message(&amp;quot;Page {$this-&amp;gt;currentPage-&amp;gt;name} deffered for publish.&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if page edit submit button clicked&lt;br /&gt;
		$this-&amp;gt;postPubLater = $this-&amp;gt;input-&amp;gt;post($this-&amp;gt;submitName);&lt;br /&gt;
		if($this-&amp;gt;postPubLater){&lt;br /&gt;
			$this-&amp;gt;message(&amp;quot;Page {$this-&amp;gt;currentPage-&amp;gt;name} deffered for publish.&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if either deffered publish sumbit found then publish page later&lt;br /&gt;
		if($this-&amp;gt;pagePubLater || $this-&amp;gt;postPubLater){&lt;br /&gt;
			$this-&amp;gt;publishLater();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	*	Hook: ProcessPageEdit::buildForm&lt;br /&gt;
	*&lt;br /&gt;
	*	add Publish Later button to edit page if not yet published&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___editForm(HookEvent $form) {&lt;br /&gt;
&lt;br /&gt;
		// get the InputFieldForm object from the event (return value of buildForm())&lt;br /&gt;
		$form = $form-&amp;gt;return;&lt;br /&gt;
&lt;br /&gt;
		$page = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;input-&amp;gt;get-&amp;gt;id);&lt;br /&gt;
		$check = $page-&amp;gt;get($this-&amp;gt;checkboxName);&lt;br /&gt;
&lt;br /&gt;
		// check if publish button available and therfore unpublished&lt;br /&gt;
		$target = $form-&amp;gt;get(&amp;#039;submit_publish&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
		if($target &amp;amp;&amp;amp; $check == false){&lt;br /&gt;
&lt;br /&gt;
			// get InputfieldText module&lt;br /&gt;
			$submit2 = $this-&amp;gt;modules-&amp;gt;get(&amp;#039;InputfieldSubmit&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;name&amp;#039;, $this-&amp;gt;submitName);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;id&amp;#039;, &amp;#039;publish_later&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;class&amp;#039;, &amp;#039;ui-button ui-widget ui-corner-all head_button_clone ui-state-default ui-priority-secondary&amp;#039;);&lt;br /&gt;
			$submit2-&amp;gt;attr(&amp;#039;value&amp;#039;, &amp;#039;Publish Later&amp;#039;); // Button: save unpublished&lt;br /&gt;
&lt;br /&gt;
			// get form element save and place before&lt;br /&gt;
			$target = $form-&amp;gt;get(&amp;#039;submit_save&amp;#039;);&lt;br /&gt;
			$form-&amp;gt;insertBefore($submit2, $target);&lt;br /&gt;
&lt;br /&gt;
			$form-&amp;gt;return = $form;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public function ___hookPageListActions(HookEvent $event) {&lt;br /&gt;
&lt;br /&gt;
		// get current page&lt;br /&gt;
		$page = $event-&amp;gt;arguments[0];&lt;br /&gt;
&lt;br /&gt;
		// check to see if page is published&lt;br /&gt;
		$pagePub = $page-&amp;gt;is(Page::statusUnpublished);&lt;br /&gt;
&lt;br /&gt;
		// check to see if page template has deffered field&lt;br /&gt;
		$pageHasDefferField = $page-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
&lt;br /&gt;
		$actions = array();&lt;br /&gt;
&lt;br /&gt;
		// don&amp;#039;t get homepage or pages that are already published or are being deffered for publish&lt;br /&gt;
		if($page-&amp;gt;id &amp;gt; 1 &amp;amp;&amp;amp; $pagePub == &amp;quot;published&amp;quot; &amp;amp;&amp;amp; !is_null($pageHasDefferField) &amp;amp;&amp;amp; $page-&amp;gt;get($this-&amp;gt;checkboxName) == false) {&lt;br /&gt;
&lt;br /&gt;
			$actions[&amp;#039;publish_later&amp;#039;] = array(&lt;br /&gt;
				&amp;#039;cn&amp;#039;   =&amp;gt; &amp;#039;PublishLater&amp;#039;,&lt;br /&gt;
				&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;pub later&amp;#039;,&lt;br /&gt;
				&amp;#039;url&amp;#039;  =&amp;gt; &amp;quot;{$this-&amp;gt;adminUrl}?{$this-&amp;gt;listPageName}=1&amp;amp;id={$page-&amp;gt;id}&amp;quot;,&lt;br /&gt;
			);&lt;br /&gt;
		}&lt;br /&gt;
		if(count($actions)) $event-&amp;gt;return = $actions + $event-&amp;gt;return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Publish Page on cron job&lt;br /&gt;
	*&lt;br /&gt;
	* Gets deffered page and publishes&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___publish($page) {&lt;br /&gt;
		$page-&amp;gt;removeStatus(Page::statusUnpublished);&lt;br /&gt;
		$page-&amp;gt;removeStatus(Page::statusHidden);&lt;br /&gt;
		$page-&amp;gt;Save();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Main publish later function&lt;br /&gt;
	*&lt;br /&gt;
	* Gets deffered page and sets fields to be checked be lazy cron&lt;br /&gt;
	*/&lt;br /&gt;
	private function ___publishLater() {&lt;br /&gt;
&lt;br /&gt;
		// get page&lt;br /&gt;
		$page = $this-&amp;gt;pages-&amp;gt;get($this-&amp;gt;pageID);&lt;br /&gt;
&lt;br /&gt;
		// set output formatting to false&lt;br /&gt;
		$page-&amp;gt;of(false);&lt;br /&gt;
&lt;br /&gt;
		//  set field time to settings default time and checkbox to true&lt;br /&gt;
		$page-&amp;gt;set($this-&amp;gt;checkboxName, true);&lt;br /&gt;
		$page-&amp;gt;set($this-&amp;gt;fieldName, $this-&amp;gt;defaultTime);&lt;br /&gt;
&lt;br /&gt;
		// save page&lt;br /&gt;
		$page-&amp;gt;save();&lt;br /&gt;
		$page-&amp;gt;of(true);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Lazy Cron hook function&lt;br /&gt;
	*&lt;br /&gt;
	* Triggers every [set time interval] and checks pages&lt;br /&gt;
	* Publishes page if time runout&lt;br /&gt;
	*&lt;br /&gt;
	* Adds publish page log&lt;br /&gt;
	*/&lt;br /&gt;
	public function ___publishDefferedPages(HookEvent $e){&lt;br /&gt;
&lt;br /&gt;
		// seconds since last lazycron&lt;br /&gt;
		$seconds = $e-&amp;gt;arguments[0];&lt;br /&gt;
&lt;br /&gt;
		// find all pages with deffered field&lt;br /&gt;
		$defferedPages = $this-&amp;gt;pages-&amp;gt;find(&amp;quot;{$this-&amp;gt;checkboxName}=1,include=unpublished&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		// for each page decrease time for deffered field&lt;br /&gt;
		foreach ($defferedPages as $page) {&lt;br /&gt;
&lt;br /&gt;
			// get current page time&lt;br /&gt;
			$timeTillPublish = $page-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
&lt;br /&gt;
			// set time to time minus time past&lt;br /&gt;
			$timeLeft = $timeTillPublish - $seconds;&lt;br /&gt;
&lt;br /&gt;
			// if time passed 0 or less then publish page&lt;br /&gt;
			$page-&amp;gt;of(false);&lt;br /&gt;
			if($timeLeft &amp;lt;= 0){&lt;br /&gt;
				// remove flags and save&lt;br /&gt;
				$this-&amp;gt;publish($page);&lt;br /&gt;
&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;fieldName, 0);&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;checkboxName, 0);&lt;br /&gt;
&lt;br /&gt;
				// log a page has been published&lt;br /&gt;
				$log = wire(&amp;#039;log&amp;#039;);&lt;br /&gt;
				$log-&amp;gt;message(&amp;#039;CRON:&amp;#039;. $seconds .&amp;#039; Pages: &amp;#039;. $page-&amp;gt;name .&amp;#039; published&amp;#039;);&lt;br /&gt;
			}else{&lt;br /&gt;
				$page-&amp;gt;set($this-&amp;gt;fieldName, $timeLeft);&lt;br /&gt;
			}&lt;br /&gt;
			// save page time&lt;br /&gt;
			$page-&amp;gt;Save();&lt;br /&gt;
			$page-&amp;gt;of(true);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Install new module specific fields&lt;br /&gt;
	*/&lt;br /&gt;
	private function installFields(){&lt;br /&gt;
&lt;br /&gt;
		// install pub later checkbox field&lt;br /&gt;
		// find installed fields&lt;br /&gt;
		$f = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
		if($f){&lt;br /&gt;
&lt;br /&gt;
			// if field already found then don&amp;#039;t try and make it&lt;br /&gt;
			$this-&amp;gt;message($this-&amp;gt;fieldName . &amp;#039; field found&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
		}else{&lt;br /&gt;
&lt;br /&gt;
			// create new field object to store crontime&lt;br /&gt;
			$f = new Field();&lt;br /&gt;
			// get a field type&lt;br /&gt;
			$f-&amp;gt;type = $this-&amp;gt;modules-&amp;gt;get(&amp;quot;FieldtypeInteger&amp;quot;);&lt;br /&gt;
			$f-&amp;gt;name = $this-&amp;gt;fieldName;&lt;br /&gt;
			$f-&amp;gt;label = &amp;#039;Publish Time Left&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;defaultValue = $this-&amp;gt;defaultTime;&lt;br /&gt;
			$f-&amp;gt;icon = &amp;#039;clock-o&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;columnWidth = 50;&lt;br /&gt;
			$f-&amp;gt;collapsed = 1;&lt;br /&gt;
			$f-&amp;gt;flags = 4;&lt;br /&gt;
&lt;br /&gt;
			$f-&amp;gt;save(); // save the field&lt;br /&gt;
&lt;br /&gt;
			// create new field object to store whether to publish or not&lt;br /&gt;
			$f = new Field();&lt;br /&gt;
			// get a field type&lt;br /&gt;
			$f-&amp;gt;type = $this-&amp;gt;modules-&amp;gt;get(&amp;quot;FieldtypeCheckbox&amp;quot;);&lt;br /&gt;
			$f-&amp;gt;name = $this-&amp;gt;checkboxName;&lt;br /&gt;
			$f-&amp;gt;label = &amp;#039;Publish Page later&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;defaultValue = false;&lt;br /&gt;
			$f-&amp;gt;columnWidth = 50;&lt;br /&gt;
			$f-&amp;gt;icon = &amp;#039;clock-o&amp;#039;;&lt;br /&gt;
			$f-&amp;gt;collapsed = 1;&lt;br /&gt;
			$f-&amp;gt;flags = 4;&lt;br /&gt;
&lt;br /&gt;
			$f-&amp;gt;save(); // save the field&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/*&lt;br /&gt;
	* Uninstall module specific fields&lt;br /&gt;
	*/&lt;br /&gt;
	private function uninstallFields(){&lt;br /&gt;
&lt;br /&gt;
		// find installed fields&lt;br /&gt;
		$fInt = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;fieldName);&lt;br /&gt;
		$fCheck = $this-&amp;gt;fields-&amp;gt;get($this-&amp;gt;checkboxName);&lt;br /&gt;
&lt;br /&gt;
		if($fInt &amp;amp;&amp;amp; $fCheck){&lt;br /&gt;
			$fieldIntUsed = $fInt-&amp;gt;numFieldgroups();&lt;br /&gt;
			$fieldCheckUsed = $fCheck-&amp;gt;numFieldgroups();&lt;br /&gt;
&lt;br /&gt;
			if($fieldIntUsed){&lt;br /&gt;
				// field in use by template&lt;br /&gt;
				$this-&amp;gt;message(&amp;#039;Unable to uninstall field &amp;#039;.$fInt-&amp;gt;name);&lt;br /&gt;
			}else{&lt;br /&gt;
				// delete installed fields&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;delete($fInt);&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;save;&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			if($fieldCheckUsed){&lt;br /&gt;
				// field in use by template&lt;br /&gt;
				$this-&amp;gt;message(&amp;#039;Unable to uninstall field &amp;#039;.$fCheck-&amp;gt;name);&lt;br /&gt;
			}else{&lt;br /&gt;
				// delete installed fields&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;delete($fCheck);&lt;br /&gt;
				$this-&amp;gt;fields-&amp;gt;save;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Inputfield / Fieldtype ===&lt;br /&gt;
[[ProcessWire - Fieldtype erstellen (Module)]]&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei statt getModuleInfo ===&lt;br /&gt;
Bei größeren Konfigruation (z.B. Admin Page Navigation) sinnvoll.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * ProcessHello.info.php&lt;br /&gt;
 * &lt;br /&gt;
 * Return information about this module.&lt;br /&gt;
 *&lt;br /&gt;
 * If preferred, you can use a getModuleInfo() method in your module file, &lt;br /&gt;
 * or you can use a ModuleName.info.json file (if you prefer JSON definition). &lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
$info = array(&lt;br /&gt;
	// Your module&amp;#039;s title&lt;br /&gt;
	&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello: Process Module Example&amp;#039;, &lt;br /&gt;
	// A 1 sentence description of what your module does&lt;br /&gt;
	&amp;#039;summary&amp;#039; =&amp;gt; &amp;#039;A starting point module skeleton from which to build your own Process module.&amp;#039;, &lt;br /&gt;
	// Module version number: use 1 for 0.0.1 or 100 for 1.0.0, and so on&lt;br /&gt;
	&amp;#039;version&amp;#039; =&amp;gt; 1, &lt;br /&gt;
	// Name of person who created this module (change to your name)&lt;br /&gt;
	&amp;#039;author&amp;#039; =&amp;gt; &amp;#039;Ryan Cramer&amp;#039;, &lt;br /&gt;
	// Icon to accompany this module (optional), uses font-awesome icon names, minus the &amp;quot;fa-&amp;quot; part&lt;br /&gt;
	&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;thumbs-up&amp;#039;, &lt;br /&gt;
	// URL to more info: change to your full modules.processwire.com URL (if available), or something else if you prefer&lt;br /&gt;
	&amp;#039;href&amp;#039; =&amp;gt; &amp;#039;http://modules.processwire.com/&amp;#039;, &lt;br /&gt;
	// name of permission required of users to execute this Process (optional)&lt;br /&gt;
	&amp;#039;permission&amp;#039; =&amp;gt; &amp;#039;helloworld&amp;#039;, &lt;br /&gt;
	// permissions that you want automatically installed/uninstalled with this module (name =&amp;gt; description)&lt;br /&gt;
	&amp;#039;permissions&amp;#039; =&amp;gt; array(&lt;br /&gt;
		&amp;#039;helloworld&amp;#039; =&amp;gt; &amp;#039;Run the HelloWorld module&amp;#039;&lt;br /&gt;
	), &lt;br /&gt;
	&lt;br /&gt;
	// page that you want created to execute this module&lt;br /&gt;
	&amp;#039;page&amp;#039; =&amp;gt; array(&lt;br /&gt;
		&amp;#039;name&amp;#039; =&amp;gt; &amp;#039;helloworld&amp;#039;,&lt;br /&gt;
		&amp;#039;parent&amp;#039; =&amp;gt; &amp;#039;setup&amp;#039;, &lt;br /&gt;
		&amp;#039;title&amp;#039; =&amp;gt; &amp;#039;Hello World&amp;#039;&lt;br /&gt;
	),&lt;br /&gt;
	// optional extra navigation that appears in admin&lt;br /&gt;
	// if you change this, you&amp;#039;ll need to a Modules &amp;gt; Refresh to see changes&lt;br /&gt;
	&amp;#039;nav&amp;#039; =&amp;gt; array(&lt;br /&gt;
		array(&lt;br /&gt;
			&amp;#039;url&amp;#039; =&amp;gt; &amp;#039;&amp;#039;, &lt;br /&gt;
			&amp;#039;label&amp;#039; =&amp;gt; &amp;#039;Hello&amp;#039;, &lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;smile-o&amp;#039;, &lt;br /&gt;
		), &lt;br /&gt;
		array(&lt;br /&gt;
			&amp;#039;url&amp;#039; =&amp;gt; &amp;#039;something/&amp;#039;, &lt;br /&gt;
			&amp;#039;label&amp;#039; =&amp;gt; &amp;#039;Something&amp;#039;, &lt;br /&gt;
			&amp;#039;icon&amp;#039; =&amp;gt; &amp;#039;beer&amp;#039;, &lt;br /&gt;
		),&lt;br /&gt;
	)&lt;br /&gt;
	// for more options that you may specify here, see the file: /wire/core/Process.php&lt;br /&gt;
	// and the file: /wire/core/Module.php&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Apache&amp;diff=24844</id>
		<title>Apache</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Apache&amp;diff=24844"/>
		<updated>2020-10-31T21:58:30Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: /* Virtual Host */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Tipps und Tricks für die Arbeit mit dem Apache Server.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
 htaccess Apache auf dem Mac etc.&lt;br /&gt;
 [[Mac - Apache MySql PHP Server mit Homebrew]] Super flexible Möglichkeit.&lt;br /&gt;
&lt;br /&gt;
== Apache2 und CGI/FastCGI  ==&lt;br /&gt;
[[Apache2 und CGI/FastCGI]]&lt;br /&gt;
&lt;br /&gt;
== Informationen der Apache Umgebung herausfinden ==&lt;br /&gt;
In der Shell &lt;br /&gt;
 httpd -V &lt;br /&gt;
gibt einige Informationen zu Logfiles, Konfigurationsfiles etc. aus.&lt;br /&gt;
Funktioniert auch unter Windows, Mac usw.&lt;br /&gt;
&lt;br /&gt;
==XAMPP auf Mac Apache Port ändern ==&lt;br /&gt;
Problem: In Mac OSX läuft bereits ein Apache auf Port 80. Wenn zusätzlich eine XAMPP Installation als Testumgebung läuft kann das zu langen Wartezeiten führen. &lt;br /&gt;
Lösung: XAMPP auf Port 8080 umstellen. Dazu in &lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;etc/httpd.conf&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
 Listen 8080 &lt;br /&gt;
einstellen. Dann im Browser mit &lt;br /&gt;
 http://localhost:8080&lt;br /&gt;
aufrufen.&lt;br /&gt;
&lt;br /&gt;
== Eigener AMP Server mit Homebrew ==&lt;br /&gt;
[[Mac - Apache MySql PHP Server mit Homebrew]]&lt;br /&gt;
&lt;br /&gt;
== Apache mySQL PHP auf Mac High Sierra ==&lt;br /&gt;
Mit Bordmitteln (Apache und PHP ist Teil von High Sierra mySQL wird dazu installiert)&lt;br /&gt;
[[Apache, PHP, mySQL auf High Sierra]]&lt;br /&gt;
&lt;br /&gt;
== Virtual Host ==&lt;br /&gt;
Virtual Hosts kann man folgendermaßen einrichten:&lt;br /&gt;
&lt;br /&gt;
etc/httpd.conf - diese Zeile auskommentieren (oder einfügen wenn nicht vorhanden)&lt;br /&gt;
 Include etc/extra/httpd-vhosts.conf&lt;br /&gt;
&lt;br /&gt;
Die Virtuellen Hosts können minimal z.b. so aussehen:&lt;br /&gt;
&lt;br /&gt;
httpd-vhosts.conf file in the etc/extra/ &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
DocumentRoot &amp;quot;/Applications/XAMPP/xamppfiles/htdocs/&amp;quot; &lt;br /&gt;
ServerName localhost&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt; &lt;br /&gt;
&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
DocumentRoot &amp;quot;/Applications/XAMPP/xamppfiles/apps/wordpress/htdocs&amp;quot;&lt;br /&gt;
ServerName wordpress.localhost &lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dabei ist der erste der Default Host für alle Domains die nicht explizit vorgegeben sind. Danach kommen beliebig viele Blöcke für Domains oder Subdomains. Für Domains auf dem localhost muss man evtl. die hosts Datei noch anpassen. Einfacher gehts mits subdomain.localhost&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Apache&amp;diff=24843</id>
		<title>Apache</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Apache&amp;diff=24843"/>
		<updated>2020-10-31T21:57:00Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: /* Virtual Host */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Tipps und Tricks für die Arbeit mit dem Apache Server.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
 htaccess Apache auf dem Mac etc.&lt;br /&gt;
 [[Mac - Apache MySql PHP Server mit Homebrew]] Super flexible Möglichkeit.&lt;br /&gt;
&lt;br /&gt;
== Apache2 und CGI/FastCGI  ==&lt;br /&gt;
[[Apache2 und CGI/FastCGI]]&lt;br /&gt;
&lt;br /&gt;
== Informationen der Apache Umgebung herausfinden ==&lt;br /&gt;
In der Shell &lt;br /&gt;
 httpd -V &lt;br /&gt;
gibt einige Informationen zu Logfiles, Konfigurationsfiles etc. aus.&lt;br /&gt;
Funktioniert auch unter Windows, Mac usw.&lt;br /&gt;
&lt;br /&gt;
==XAMPP auf Mac Apache Port ändern ==&lt;br /&gt;
Problem: In Mac OSX läuft bereits ein Apache auf Port 80. Wenn zusätzlich eine XAMPP Installation als Testumgebung läuft kann das zu langen Wartezeiten führen. &lt;br /&gt;
Lösung: XAMPP auf Port 8080 umstellen. Dazu in &lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;etc/httpd.conf&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
 Listen 8080 &lt;br /&gt;
einstellen. Dann im Browser mit &lt;br /&gt;
 http://localhost:8080&lt;br /&gt;
aufrufen.&lt;br /&gt;
&lt;br /&gt;
== Eigener AMP Server mit Homebrew ==&lt;br /&gt;
[[Mac - Apache MySql PHP Server mit Homebrew]]&lt;br /&gt;
&lt;br /&gt;
== Apache mySQL PHP auf Mac High Sierra ==&lt;br /&gt;
Mit Bordmitteln (Apache und PHP ist Teil von High Sierra mySQL wird dazu installiert)&lt;br /&gt;
[[Apache, PHP, mySQL auf High Sierra]]&lt;br /&gt;
&lt;br /&gt;
== Virtual Host ==&lt;br /&gt;
Virtual Hosts kann man folgendermaßen einrichten:&lt;br /&gt;
&lt;br /&gt;
etc/httpd.conf - diese Zeile auskommentieren (oder einfügen wenn nicht vorhanden)&lt;br /&gt;
 Include etc/extra/httpd-vhosts.conf&lt;br /&gt;
&lt;br /&gt;
Die Virtuellen Hosts können minimal z.b. so aussehen:&lt;br /&gt;
&lt;br /&gt;
httpd-vhosts.conf file in the etc/extra/ &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
DocumentRoot &amp;quot;/Applications/XAMPP/xamppfiles/htdocs/&amp;quot; &lt;br /&gt;
ServerName localhost&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt; &lt;br /&gt;
&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
DocumentRoot &amp;quot;/Applications/XAMPP/xamppfiles/apps/wordpress/htdocs&amp;quot;&lt;br /&gt;
ServerName wordpress.localhost &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dabei ist der erste der Default Host für alle Domains die nicht explizit vorgegeben sind. Danach kommen beliebig viele Blöcke für Domains oder Subdomains. Für Domains auf dem localhost muss man evtl. die hosts Datei noch anpassen. Einfacher gehts mits subdomain.localhost&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Apache&amp;diff=24842</id>
		<title>Apache</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Apache&amp;diff=24842"/>
		<updated>2020-10-31T21:56:18Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: /* Virtual Host */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Tipps und Tricks für die Arbeit mit dem Apache Server.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
 htaccess Apache auf dem Mac etc.&lt;br /&gt;
 [[Mac - Apache MySql PHP Server mit Homebrew]] Super flexible Möglichkeit.&lt;br /&gt;
&lt;br /&gt;
== Apache2 und CGI/FastCGI  ==&lt;br /&gt;
[[Apache2 und CGI/FastCGI]]&lt;br /&gt;
&lt;br /&gt;
== Informationen der Apache Umgebung herausfinden ==&lt;br /&gt;
In der Shell &lt;br /&gt;
 httpd -V &lt;br /&gt;
gibt einige Informationen zu Logfiles, Konfigurationsfiles etc. aus.&lt;br /&gt;
Funktioniert auch unter Windows, Mac usw.&lt;br /&gt;
&lt;br /&gt;
==XAMPP auf Mac Apache Port ändern ==&lt;br /&gt;
Problem: In Mac OSX läuft bereits ein Apache auf Port 80. Wenn zusätzlich eine XAMPP Installation als Testumgebung läuft kann das zu langen Wartezeiten führen. &lt;br /&gt;
Lösung: XAMPP auf Port 8080 umstellen. Dazu in &lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;etc/httpd.conf&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
 Listen 8080 &lt;br /&gt;
einstellen. Dann im Browser mit &lt;br /&gt;
 http://localhost:8080&lt;br /&gt;
aufrufen.&lt;br /&gt;
&lt;br /&gt;
== Eigener AMP Server mit Homebrew ==&lt;br /&gt;
[[Mac - Apache MySql PHP Server mit Homebrew]]&lt;br /&gt;
&lt;br /&gt;
== Apache mySQL PHP auf Mac High Sierra ==&lt;br /&gt;
Mit Bordmitteln (Apache und PHP ist Teil von High Sierra mySQL wird dazu installiert)&lt;br /&gt;
[[Apache, PHP, mySQL auf High Sierra]]&lt;br /&gt;
&lt;br /&gt;
== Virtual Host ==&lt;br /&gt;
Virtual Hosts kann man folgendermaßen einrichten:&lt;br /&gt;
&lt;br /&gt;
etc/httpd.conf - diese Zeile auskommentieren (oder einfügen wenn nicht vorhanden)&lt;br /&gt;
 Include etc/extra/httpd-vhosts.conf&lt;br /&gt;
&lt;br /&gt;
Die Virtuellen Hosts können minimal z.b. so aussehen:&lt;br /&gt;
&lt;br /&gt;
httpd-vhosts.conf file in the etc/extra/ &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
DocumentRoot &amp;quot;/Applications/XAMPP/xamppfiles/htdocs/&amp;quot; ServerName localhost&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt; &lt;br /&gt;
&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
DocumentRoot &amp;quot;/Applications/XAMPP/xamppfiles/apps/wordpress/htdocs&amp;quot;&lt;br /&gt;
ServerName wordpress.localhost &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dabei ist der erste der Default Host für alle Domains die nicht explizit vorgegeben sind. Danach kommen beliebig viele Blöcke für Domains oder Subdomains. Für Domains auf dem localhost muss man evtl. die hosts Datei noch anpassen. Einfacher gehts mits subdomain.localhost&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Apache&amp;diff=24841</id>
		<title>Apache</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Apache&amp;diff=24841"/>
		<updated>2020-10-31T21:55:16Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Tipps und Tricks für die Arbeit mit dem Apache Server.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
 htaccess Apache auf dem Mac etc.&lt;br /&gt;
 [[Mac - Apache MySql PHP Server mit Homebrew]] Super flexible Möglichkeit.&lt;br /&gt;
&lt;br /&gt;
== Apache2 und CGI/FastCGI  ==&lt;br /&gt;
[[Apache2 und CGI/FastCGI]]&lt;br /&gt;
&lt;br /&gt;
== Informationen der Apache Umgebung herausfinden ==&lt;br /&gt;
In der Shell &lt;br /&gt;
 httpd -V &lt;br /&gt;
gibt einige Informationen zu Logfiles, Konfigurationsfiles etc. aus.&lt;br /&gt;
Funktioniert auch unter Windows, Mac usw.&lt;br /&gt;
&lt;br /&gt;
==XAMPP auf Mac Apache Port ändern ==&lt;br /&gt;
Problem: In Mac OSX läuft bereits ein Apache auf Port 80. Wenn zusätzlich eine XAMPP Installation als Testumgebung läuft kann das zu langen Wartezeiten führen. &lt;br /&gt;
Lösung: XAMPP auf Port 8080 umstellen. Dazu in &lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;etc/httpd.conf&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
 Listen 8080 &lt;br /&gt;
einstellen. Dann im Browser mit &lt;br /&gt;
 http://localhost:8080&lt;br /&gt;
aufrufen.&lt;br /&gt;
&lt;br /&gt;
== Eigener AMP Server mit Homebrew ==&lt;br /&gt;
[[Mac - Apache MySql PHP Server mit Homebrew]]&lt;br /&gt;
&lt;br /&gt;
== Apache mySQL PHP auf Mac High Sierra ==&lt;br /&gt;
Mit Bordmitteln (Apache und PHP ist Teil von High Sierra mySQL wird dazu installiert)&lt;br /&gt;
[[Apache, PHP, mySQL auf High Sierra]]&lt;br /&gt;
&lt;br /&gt;
== Virtual Host ==&lt;br /&gt;
Virtual Hosts kann man folgendermaßen einrichten:&lt;br /&gt;
&lt;br /&gt;
etc/httpd.conf - diese Zeile auskommentieren (oder einfügen wenn nicht vorhanden)&lt;br /&gt;
 Include etc/extra/httpd-vhosts.conf&lt;br /&gt;
&lt;br /&gt;
Die Virtuellen Hosts können minimal z.b. so aussehen:&lt;br /&gt;
&lt;br /&gt;
httpd-vhosts.conf file in the etc/extra/ &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
DocumentRoot &amp;quot;/Applications/XAMPP/xamppfiles/htdocs/&amp;quot; ServerName localhost&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt; &lt;br /&gt;
&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
DocumentRoot &amp;quot;/Applications/XAMPP/xamppfiles/apps/wordpress/htdocs&amp;quot;&lt;br /&gt;
ServerName wordpress.localhost &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dabei ist der erste der Default Host für alle Domains die nicht explizit vorgegeben sind. Danach kommen beliebig viele Blöcke für Domains.&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_N%C3%BCtzliche_Module&amp;diff=24840</id>
		<title>ProcessWire - Nützliche Module</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_N%C3%BCtzliche_Module&amp;diff=24840"/>
		<updated>2020-10-28T19:44:10Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: /* Bedienungshilfen / Backend / Fieldtypes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Mal anschauen ==&lt;br /&gt;
 https://modules.processwire.com/modules/process-cache-control/&lt;br /&gt;
 https://modules.processwire.com/modules/inputfield-selector-select-id/ SeitenID über Seitenbaum in Modalwindow holen&lt;br /&gt;
 https://modules.processwire.com/modules/markup-sitemap-xml/&lt;br /&gt;
 https://modules.processwire.com/modules/process-page-field-select-creator/&lt;br /&gt;
 https://modules.processwire.com/modules/pro-cache/&lt;br /&gt;
 https://modules.processwire.com/modules/fieldtype-page-table-extended/&lt;br /&gt;
 https://modules.processwire.com/modules/fieldtype-rock-awesome/ FontAwsome Icons einfügen&lt;br /&gt;
 https://modules.processwire.com/modules/rest-api/ REST&lt;br /&gt;
 https://modules.processwire.com/modules/process-graph-ql/&lt;br /&gt;
 https://modules.processwire.com/modules/maintenance-mode/&lt;br /&gt;
 https://modules.processwire.com/modules/fieldtype-secure-file/&lt;br /&gt;
 https://modules.processwire.com/modules/mobile-detect/ mal schauen wie es gemacht ist&lt;br /&gt;
 https://modules.processwire.com/modules/search-engine/&lt;br /&gt;
 https://modules.processwire.com/modules/cronjob-empty-trash/ schauen wie es gemacht ist&lt;br /&gt;
 https://modules.processwire.com/modules/process-general-settings/ anschauen&lt;br /&gt;
 https://modules.processwire.com/modules/file-validator-svg-sanitizer/&lt;br /&gt;
 https://modules.processwire.com/modules/download-guard/ Download Link&lt;br /&gt;
 https://modules.processwire.com/modules/payment-stripe/ Stripe Erweiterung für Payment Modul&lt;br /&gt;
 https://modules.processwire.com/modules/payment-module/ &lt;br /&gt;
 https://modules.processwire.com/modules/payment-paypal/ Papal Erweiterung für Payment Modul&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dies ist keine vollständige Liste aber mal eine kleine Hilfe auch um Kunden Module anbieten zu können...&lt;br /&gt;
 * Cool&lt;br /&gt;
 ** Sehr Hilfreich - Killerfeatures für Kunden&lt;br /&gt;
 *** Musthave Ohne geht&amp;#039;s nicht&lt;br /&gt;
== Development ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessAdminActions&amp;#039;&amp;#039;&amp;#039; *** - Musthave bei komplexen Projekten. Kann viele Dinge als Batch erledigen und spart unendlich Zeit.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;GithubConnect&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ConnectPageFields&amp;#039;&amp;#039;&amp;#039; 2 Wege Verbindung für Datenfelder. Kein richtiges m:n, hält aber die Felder synchron&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;jQueryDataTables&amp;#039;&amp;#039;&amp;#039; - Datatables in eigenen Modulen verwenden https://modules.processwire.com/modules/jquery-data-tables/&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;HelperFieldLinks&amp;#039;&amp;#039;&amp;#039; - Infos zu Feldern anzeigen und Shortcuts zu den Templates und Felddefinitionen die dazugehören.&lt;br /&gt;
&lt;br /&gt;
=== Debugging ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TracyDebugger&amp;#039;&amp;#039;&amp;#039; *** - für programmierlastige Projekte das Debugger Tool der Wahl&lt;br /&gt;
&lt;br /&gt;
=== Daten Im- / Exportieren ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ImportPagesCSV&amp;#039;&amp;#039;&amp;#039; *** - Importiert CSV Daten als Seiten in ProcessWire&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TableCsvImportExport&amp;#039;&amp;#039;&amp;#039; - Importiert CSV Daten in Table Fields&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;[[DataSet - ProcessWire Modul|DataSet]]&amp;#039;&amp;#039;&amp;#039; - Importiert CSV und XML Daten. Config-Datei für Anweisungen. Kann mit Tasker auch als Cronjob laufen. Für große Datenssätze. https://github.com/mtwebit/DataSet&lt;br /&gt;
&lt;br /&gt;
== Administration / Verwaltung ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminRestrictBranch&amp;#039;&amp;#039;&amp;#039; - Redakteure auf einen Seitenzweig beschränken&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ModulesManager&amp;#039;&amp;#039;&amp;#039; - Zugriff auf das offizielle Modulverzeichnis aus dem Backend heraus&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageReferencesTab&amp;#039;&amp;#039;&amp;#039; - Seitenverwaltung &amp;quot;Welche Seiten verweisen auf diese mittels PageReference Field&amp;quot;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;EmailNewUser&amp;#039;&amp;#039;&amp;#039; - User über seinen Account Informieren. Nutzen mit &amp;#039;&amp;#039;&amp;#039;PasswordForceChange&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessWireUpgrade&amp;#039;&amp;#039;&amp;#039; ** - Informiert über Upgrades - nützlich wenn man Updates als kostnpfl. Service anbieten möchte&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessJumplinks&amp;#039;&amp;#039;&amp;#039; * - Redirects verwalten&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageRenameOptions&amp;#039;&amp;#039;&amp;#039; - Ändert den Seitennamen bei Änderung des Titels. Am besten mit PagePathHistory verwenden wg. broken Links.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RestrictRepeaterMatrix&amp;#039;&amp;#039;&amp;#039; Zugriff auf Repeater Matrix Felder regulieren [[RestrictRepeaterMatrix (ProcessWire Modul)]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TemplatesChildPages&amp;#039;&amp;#039;&amp;#039; Zugriff auf Kindseiten einschränken - erweitert Zugriffsregeln auf Seitenbasis, statt nur auf Templatebasis&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CronjobDatabaseBackup&amp;#039;&amp;#039;&amp;#039; Automatische Datenbank Backups - nutzt LazyCron&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminPageFieldEditLinks&amp;#039;&amp;#039;&amp;#039; - Anlegen und Verändern von Seiten die auf diese Zeigen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ConnectPageFields&amp;#039;&amp;#039;&amp;#039; - Zweiwege Verbindung von Page References (jede Seite zeigt auf die andere)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessPageFieldSelectCreator&amp;#039;&amp;#039;&amp;#039; - Erzeugt Templates, Seiten und Felder für Select Strukturen z.B. Parentseite RoomTypes und Kindseiten Single Double Suite. &lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminLinksInFrontend&amp;#039;&amp;#039;&amp;#039; - Einstellbare Admin Links für das Bearbeiten der Seite + User Switcher...&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Duplicator&amp;#039;&amp;#039;&amp;#039; - Duplizieren von Installationen inklusive Datenbank. Gut für regelmäßige Backups auch Crongesteuert und in die Cloud. Vorsicht beim Duplizieren für andere Websites, das Salz für die Verschlüsselung bleibt dann gleich.&lt;br /&gt;
&lt;br /&gt;
== Navigation / Menüs ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessMenuBuilder&amp;#039;&amp;#039;&amp;#039; - Manuelle Custom Menu Erstellung - sinnvoll bei sehr individuellen Navigationen. &lt;br /&gt;
&lt;br /&gt;
== Hilfe für Redakteure ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AssistedURL&amp;#039;&amp;#039;&amp;#039; - Linkhilfe Adrians Fork ist oft weiter (https://github.com/adrianbj/processwire-fieldtype-assisted-url)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PrevNextTabs&amp;#039;&amp;#039;&amp;#039; - Abkürzung zur nächsten / vorigen Seite im Backend. Sinnvoll wenn viele Seiten bearbeitet werden müssen.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CkeLinkFiles&amp;#039;&amp;#039;&amp;#039; - Dateilinks leichter im Editor einfügen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SchedulePages&amp;#039;&amp;#039;&amp;#039; - Seiten auf Termin veröffentlichen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ImageCropRatios&amp;#039;&amp;#039;&amp;#039; - Super nützlich für Bildcropping mit Aspect Ratio (vorgegebene Seitenverhältnisse)&lt;br /&gt;
&lt;br /&gt;
== Sicherheit und Recht ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;EmailObfuscation&amp;#039;&amp;#039;&amp;#039; **&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupCookieConsent&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CookieManagementBanner&amp;#039;&amp;#039;&amp;#039; - von Adrian&lt;br /&gt;
&lt;br /&gt;
== Bedienungshilfen / Backend / Fieldtypes==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AssistedUrl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MinimalFieldset&amp;#039;&amp;#039;&amp;#039; - läßt flexiblere Gestaltung der Felder im Backend zu.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageListSelectMultipleQuickly&amp;#039;&amp;#039;&amp;#039; Mehrere Seiten auwählen ohne jedesmal den Baum neu zu öffnen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageFieldInfo&amp;#039;&amp;#039;&amp;#039; - zusätzliche Infos bei Page Select Checkboxen anzeigen (bei hover und wenn gecheckt)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FieldtypeTime&amp;#039;&amp;#039;&amp;#039; - Feld zum Speichern von Zeit und Zeitintervallen, Es gibt noch ein weiteres schickes Zeitfeld mit Eingabehilfe (Genbänkle oder Yoga Namaste ? - TODO)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RuntimeMarkup&amp;#039;&amp;#039;&amp;#039; - Feld das PHP Code ausführen und das Ergebnis im Backend anzeigen kann. So kann man dynamischen Inhalt im Backend anzeigen z.B. Informationen aus Kindseiten etc.  &lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FieldtypeSelectExtOption&amp;#039;&amp;#039;&amp;#039; - Select Felder bei dem die Optionen aus einer externen Quelle kommen können (z.B. eine Tabelle)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RuntimeMarkup&amp;#039;&amp;#039;&amp;#039; - Das Feld führt PHP-Code aus. Der Output wird dann an der Stelle des Felds im Backend ausgegeben. Nützlich um z.B. Referenzen oder Infos anzuzeigen.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminPageFieldEditLinks&amp;#039;&amp;#039;&amp;#039; - Mit dem Feld kann man Referenzen auf diese Seite direkt in einem Modal bearbeiten ohne extra die referenzierende Seite aufzurufen. Kann viel Arbeit sparen.&lt;br /&gt;
&lt;br /&gt;
== Markup etc. erzeugen ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Pages2Pdf&amp;#039;&amp;#039;&amp;#039; - Wrapper für mPdf Library zur PDF Erzeugung&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RockPdf&amp;#039;&amp;#039;&amp;#039; - Wrapper für mPdf Library von Bernhard Baumrock (https://github.com/BernhardBaumrock/RockPDF, https://modules.processwire.com/modules/rock-pdf/, https://processwire.com/talk/topic/19468-360%C2%B0-feedbacksurvey-tool/)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterHannaCode&amp;#039;&amp;#039;&amp;#039; ** - Snippets für den Editor erstellen, die dann komplexeren Markup erzeugen können (Killer für Wordpress-Lovers) &lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterAutoAnchor&amp;#039;&amp;#039;&amp;#039; - Erzeugt automatisch Ids und Slugs in den Überschrift Elementen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterSoundmanager&amp;#039;&amp;#039;&amp;#039; - Formatter für den Soundmanager2 Player - kann auch Multitrack und krasse Visualisierungen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FieldtypePhone&amp;#039;&amp;#039;&amp;#039; - Standard Telefonformatierung (https://github.com/adrianbj/FieldtypePhone)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterFileInfo&amp;#039;&amp;#039;&amp;#039; - Dateiinfo Textformatter&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;InputfieldMarkupCKEditor&amp;#039;&amp;#039;&amp;#039; - Text in Formbuilder Formularen einfügen&lt;br /&gt;
&lt;br /&gt;
== Social Functionality Community Stuff ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;NewsletterSubscription&amp;#039;&amp;#039;&amp;#039; - Double Opt In Funktionalität für Newsletter etc.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;LoginRegister&amp;#039;&amp;#039;&amp;#039; - Ryans Self Registration Beispiel&lt;br /&gt;
&lt;br /&gt;
== SEO Module ==&lt;br /&gt;
* SEOMaestro - Quasi Nachfolger von MarkupSEO ?&lt;br /&gt;
* ProcessJumplinks - Manage Referers Basiert auf dem älteren &lt;br /&gt;
* MarkupRSS&lt;br /&gt;
* MarkupSitemap Erweiterte Version von MarkupSitemapXML. Kann auch Multilanguage Sites Managen.&lt;br /&gt;
* Process404Page - Load search results into 404 page using terms from the failed URL&lt;br /&gt;
* https://modules.processwire.com/modules/profields-autolinks/ - Generiert automatisch Links&lt;br /&gt;
* SearchEngineReferrerTracker - speichert Keywords über die Besucher von Suchmaschinen gekommen sind. Matomo kann das auch, dies wäre aber eine einfache Lösung.&lt;br /&gt;
&lt;br /&gt;
== DSGVO ==&lt;br /&gt;
* MarkupCookieConsent - noch nicht getestet&lt;br /&gt;
&lt;br /&gt;
== Structured Data - Schema.org ==&lt;br /&gt;
* MarkupJsonLDSchema&lt;br /&gt;
&lt;br /&gt;
== Mal Testen ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessCustomUploadNames&amp;#039;&amp;#039;&amp;#039; - Renaming Rulse for Pages and other fields.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessBlog&amp;#039;&amp;#039;&amp;#039; - Blog Modul von Ryan (für das Blog Profile entwickelt)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupSocialShareButtons&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupPlyrMediaPlayer&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;InstagramFeed&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MediaLibrary&amp;#039;&amp;#039;&amp;#039; - Medienzugriff über Libraries. Auswahl in übergeordneten Seiten möglich.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FrontEndEditLightbox&amp;#039;&amp;#039;&amp;#039; - Frontend Editing der aktuellen Seite in einer Lightbox&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Sassify&amp;#039;&amp;#039;&amp;#039; - Kompiliert Sass/SCSS/Compass - evtl. praktisch während der Entwicklungsphase&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Oauth2Login&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupSitemap&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Blackhole&amp;#039;&amp;#039;&amp;#039; - Lockt Bots die robots.txt missachten in ein Blackhole -&amp;gt; werden gebannt&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminThemeBoss&amp;#039;&amp;#039;&amp;#039; - Platzsparendes zurückhaltendes uikit 3 Theme. Setzt auf dem Standard Theme auf&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MillSite&amp;#039;&amp;#039;&amp;#039; - Milligram SiteProfile mit einigen Zusatzfeatures&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MillBlog&amp;#039;&amp;#039;&amp;#039; - Milligram Framework Blog SiteProfile&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SeoMaestro&amp;#039;&amp;#039;&amp;#039; - SEO Tool noch Alpha (2019-02)&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_N%C3%BCtzliche_Module&amp;diff=24839</id>
		<title>ProcessWire - Nützliche Module</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_N%C3%BCtzliche_Module&amp;diff=24839"/>
		<updated>2020-10-28T19:42:36Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: /* Bedienungshilfen / Backend / Fieldtypes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Mal anschauen ==&lt;br /&gt;
 https://modules.processwire.com/modules/process-cache-control/&lt;br /&gt;
 https://modules.processwire.com/modules/inputfield-selector-select-id/ SeitenID über Seitenbaum in Modalwindow holen&lt;br /&gt;
 https://modules.processwire.com/modules/markup-sitemap-xml/&lt;br /&gt;
 https://modules.processwire.com/modules/process-page-field-select-creator/&lt;br /&gt;
 https://modules.processwire.com/modules/pro-cache/&lt;br /&gt;
 https://modules.processwire.com/modules/fieldtype-page-table-extended/&lt;br /&gt;
 https://modules.processwire.com/modules/fieldtype-rock-awesome/ FontAwsome Icons einfügen&lt;br /&gt;
 https://modules.processwire.com/modules/rest-api/ REST&lt;br /&gt;
 https://modules.processwire.com/modules/process-graph-ql/&lt;br /&gt;
 https://modules.processwire.com/modules/maintenance-mode/&lt;br /&gt;
 https://modules.processwire.com/modules/fieldtype-secure-file/&lt;br /&gt;
 https://modules.processwire.com/modules/mobile-detect/ mal schauen wie es gemacht ist&lt;br /&gt;
 https://modules.processwire.com/modules/search-engine/&lt;br /&gt;
 https://modules.processwire.com/modules/cronjob-empty-trash/ schauen wie es gemacht ist&lt;br /&gt;
 https://modules.processwire.com/modules/process-general-settings/ anschauen&lt;br /&gt;
 https://modules.processwire.com/modules/file-validator-svg-sanitizer/&lt;br /&gt;
 https://modules.processwire.com/modules/download-guard/ Download Link&lt;br /&gt;
 https://modules.processwire.com/modules/payment-stripe/ Stripe Erweiterung für Payment Modul&lt;br /&gt;
 https://modules.processwire.com/modules/payment-module/ &lt;br /&gt;
 https://modules.processwire.com/modules/payment-paypal/ Papal Erweiterung für Payment Modul&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dies ist keine vollständige Liste aber mal eine kleine Hilfe auch um Kunden Module anbieten zu können...&lt;br /&gt;
 * Cool&lt;br /&gt;
 ** Sehr Hilfreich - Killerfeatures für Kunden&lt;br /&gt;
 *** Musthave Ohne geht&amp;#039;s nicht&lt;br /&gt;
== Development ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessAdminActions&amp;#039;&amp;#039;&amp;#039; *** - Musthave bei komplexen Projekten. Kann viele Dinge als Batch erledigen und spart unendlich Zeit.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;GithubConnect&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ConnectPageFields&amp;#039;&amp;#039;&amp;#039; 2 Wege Verbindung für Datenfelder. Kein richtiges m:n, hält aber die Felder synchron&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;jQueryDataTables&amp;#039;&amp;#039;&amp;#039; - Datatables in eigenen Modulen verwenden https://modules.processwire.com/modules/jquery-data-tables/&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;HelperFieldLinks&amp;#039;&amp;#039;&amp;#039; - Infos zu Feldern anzeigen und Shortcuts zu den Templates und Felddefinitionen die dazugehören.&lt;br /&gt;
&lt;br /&gt;
=== Debugging ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TracyDebugger&amp;#039;&amp;#039;&amp;#039; *** - für programmierlastige Projekte das Debugger Tool der Wahl&lt;br /&gt;
&lt;br /&gt;
=== Daten Im- / Exportieren ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ImportPagesCSV&amp;#039;&amp;#039;&amp;#039; *** - Importiert CSV Daten als Seiten in ProcessWire&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TableCsvImportExport&amp;#039;&amp;#039;&amp;#039; - Importiert CSV Daten in Table Fields&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;[[DataSet - ProcessWire Modul|DataSet]]&amp;#039;&amp;#039;&amp;#039; - Importiert CSV und XML Daten. Config-Datei für Anweisungen. Kann mit Tasker auch als Cronjob laufen. Für große Datenssätze. https://github.com/mtwebit/DataSet&lt;br /&gt;
&lt;br /&gt;
== Administration / Verwaltung ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminRestrictBranch&amp;#039;&amp;#039;&amp;#039; - Redakteure auf einen Seitenzweig beschränken&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ModulesManager&amp;#039;&amp;#039;&amp;#039; - Zugriff auf das offizielle Modulverzeichnis aus dem Backend heraus&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageReferencesTab&amp;#039;&amp;#039;&amp;#039; - Seitenverwaltung &amp;quot;Welche Seiten verweisen auf diese mittels PageReference Field&amp;quot;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;EmailNewUser&amp;#039;&amp;#039;&amp;#039; - User über seinen Account Informieren. Nutzen mit &amp;#039;&amp;#039;&amp;#039;PasswordForceChange&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessWireUpgrade&amp;#039;&amp;#039;&amp;#039; ** - Informiert über Upgrades - nützlich wenn man Updates als kostnpfl. Service anbieten möchte&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessJumplinks&amp;#039;&amp;#039;&amp;#039; * - Redirects verwalten&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageRenameOptions&amp;#039;&amp;#039;&amp;#039; - Ändert den Seitennamen bei Änderung des Titels. Am besten mit PagePathHistory verwenden wg. broken Links.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RestrictRepeaterMatrix&amp;#039;&amp;#039;&amp;#039; Zugriff auf Repeater Matrix Felder regulieren [[RestrictRepeaterMatrix (ProcessWire Modul)]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TemplatesChildPages&amp;#039;&amp;#039;&amp;#039; Zugriff auf Kindseiten einschränken - erweitert Zugriffsregeln auf Seitenbasis, statt nur auf Templatebasis&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CronjobDatabaseBackup&amp;#039;&amp;#039;&amp;#039; Automatische Datenbank Backups - nutzt LazyCron&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminPageFieldEditLinks&amp;#039;&amp;#039;&amp;#039; - Anlegen und Verändern von Seiten die auf diese Zeigen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ConnectPageFields&amp;#039;&amp;#039;&amp;#039; - Zweiwege Verbindung von Page References (jede Seite zeigt auf die andere)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessPageFieldSelectCreator&amp;#039;&amp;#039;&amp;#039; - Erzeugt Templates, Seiten und Felder für Select Strukturen z.B. Parentseite RoomTypes und Kindseiten Single Double Suite. &lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminLinksInFrontend&amp;#039;&amp;#039;&amp;#039; - Einstellbare Admin Links für das Bearbeiten der Seite + User Switcher...&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Duplicator&amp;#039;&amp;#039;&amp;#039; - Duplizieren von Installationen inklusive Datenbank. Gut für regelmäßige Backups auch Crongesteuert und in die Cloud. Vorsicht beim Duplizieren für andere Websites, das Salz für die Verschlüsselung bleibt dann gleich.&lt;br /&gt;
&lt;br /&gt;
== Navigation / Menüs ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessMenuBuilder&amp;#039;&amp;#039;&amp;#039; - Manuelle Custom Menu Erstellung - sinnvoll bei sehr individuellen Navigationen. &lt;br /&gt;
&lt;br /&gt;
== Hilfe für Redakteure ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AssistedURL&amp;#039;&amp;#039;&amp;#039; - Linkhilfe Adrians Fork ist oft weiter (https://github.com/adrianbj/processwire-fieldtype-assisted-url)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PrevNextTabs&amp;#039;&amp;#039;&amp;#039; - Abkürzung zur nächsten / vorigen Seite im Backend. Sinnvoll wenn viele Seiten bearbeitet werden müssen.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CkeLinkFiles&amp;#039;&amp;#039;&amp;#039; - Dateilinks leichter im Editor einfügen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SchedulePages&amp;#039;&amp;#039;&amp;#039; - Seiten auf Termin veröffentlichen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ImageCropRatios&amp;#039;&amp;#039;&amp;#039; - Super nützlich für Bildcropping mit Aspect Ratio (vorgegebene Seitenverhältnisse)&lt;br /&gt;
&lt;br /&gt;
== Sicherheit und Recht ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;EmailObfuscation&amp;#039;&amp;#039;&amp;#039; **&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupCookieConsent&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CookieManagementBanner&amp;#039;&amp;#039;&amp;#039; - von Adrian&lt;br /&gt;
&lt;br /&gt;
== Bedienungshilfen / Backend / Fieldtypes==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AssistedUrl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MinimalFieldset&amp;#039;&amp;#039;&amp;#039; - läßt flexiblere Gestaltung der Felder im Backend zu.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageListSelectMultipleQuickly&amp;#039;&amp;#039;&amp;#039; Mehrere Seiten auwählen ohne jedesmal den Baum neu zu öffnen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageFieldInfo&amp;#039;&amp;#039;&amp;#039; - zusätzliche Infos bei Page Select Checkboxen anzeigen (bei hover und wenn gecheckt)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FieldtypeTime&amp;#039;&amp;#039;&amp;#039; - Feld zum Speichern von Zeit und Zeitintervallen, Es gibt noch ein weiteres schickes Zeitfeld mit Eingabehilfe (Genbänkle oder Yoga Namaste ? - TODO)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RuntimeMarkup&amp;#039;&amp;#039;&amp;#039; - Feld das PHP Code ausführen und das Ergebnis im Backend anzeigen kann. So kann man dynamischen Inhalt im Backend anzeigen z.B. Informationen aus Kindseiten etc.  &lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FieldtypeSelectExtOption&amp;#039;&amp;#039;&amp;#039; - Select Felder bei dem die Optionen aus einer externen Quelle kommen können (z.B. eine Tabelle)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RuntimeMarkup&amp;#039;&amp;#039;&amp;#039; - Das Feld führt PHP-Code aus. Der Output wird dann an der Stelle des Felds im Backend ausgegeben. Nützlich um z.B. Referenzen oder Infos anzuzeigen.&lt;br /&gt;
&lt;br /&gt;
== Markup etc. erzeugen ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Pages2Pdf&amp;#039;&amp;#039;&amp;#039; - Wrapper für mPdf Library zur PDF Erzeugung&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RockPdf&amp;#039;&amp;#039;&amp;#039; - Wrapper für mPdf Library von Bernhard Baumrock (https://github.com/BernhardBaumrock/RockPDF, https://modules.processwire.com/modules/rock-pdf/, https://processwire.com/talk/topic/19468-360%C2%B0-feedbacksurvey-tool/)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterHannaCode&amp;#039;&amp;#039;&amp;#039; ** - Snippets für den Editor erstellen, die dann komplexeren Markup erzeugen können (Killer für Wordpress-Lovers) &lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterAutoAnchor&amp;#039;&amp;#039;&amp;#039; - Erzeugt automatisch Ids und Slugs in den Überschrift Elementen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterSoundmanager&amp;#039;&amp;#039;&amp;#039; - Formatter für den Soundmanager2 Player - kann auch Multitrack und krasse Visualisierungen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FieldtypePhone&amp;#039;&amp;#039;&amp;#039; - Standard Telefonformatierung (https://github.com/adrianbj/FieldtypePhone)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterFileInfo&amp;#039;&amp;#039;&amp;#039; - Dateiinfo Textformatter&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;InputfieldMarkupCKEditor&amp;#039;&amp;#039;&amp;#039; - Text in Formbuilder Formularen einfügen&lt;br /&gt;
&lt;br /&gt;
== Social Functionality Community Stuff ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;NewsletterSubscription&amp;#039;&amp;#039;&amp;#039; - Double Opt In Funktionalität für Newsletter etc.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;LoginRegister&amp;#039;&amp;#039;&amp;#039; - Ryans Self Registration Beispiel&lt;br /&gt;
&lt;br /&gt;
== SEO Module ==&lt;br /&gt;
* SEOMaestro - Quasi Nachfolger von MarkupSEO ?&lt;br /&gt;
* ProcessJumplinks - Manage Referers Basiert auf dem älteren &lt;br /&gt;
* MarkupRSS&lt;br /&gt;
* MarkupSitemap Erweiterte Version von MarkupSitemapXML. Kann auch Multilanguage Sites Managen.&lt;br /&gt;
* Process404Page - Load search results into 404 page using terms from the failed URL&lt;br /&gt;
* https://modules.processwire.com/modules/profields-autolinks/ - Generiert automatisch Links&lt;br /&gt;
* SearchEngineReferrerTracker - speichert Keywords über die Besucher von Suchmaschinen gekommen sind. Matomo kann das auch, dies wäre aber eine einfache Lösung.&lt;br /&gt;
&lt;br /&gt;
== DSGVO ==&lt;br /&gt;
* MarkupCookieConsent - noch nicht getestet&lt;br /&gt;
&lt;br /&gt;
== Structured Data - Schema.org ==&lt;br /&gt;
* MarkupJsonLDSchema&lt;br /&gt;
&lt;br /&gt;
== Mal Testen ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessCustomUploadNames&amp;#039;&amp;#039;&amp;#039; - Renaming Rulse for Pages and other fields.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessBlog&amp;#039;&amp;#039;&amp;#039; - Blog Modul von Ryan (für das Blog Profile entwickelt)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupSocialShareButtons&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupPlyrMediaPlayer&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;InstagramFeed&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MediaLibrary&amp;#039;&amp;#039;&amp;#039; - Medienzugriff über Libraries. Auswahl in übergeordneten Seiten möglich.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FrontEndEditLightbox&amp;#039;&amp;#039;&amp;#039; - Frontend Editing der aktuellen Seite in einer Lightbox&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Sassify&amp;#039;&amp;#039;&amp;#039; - Kompiliert Sass/SCSS/Compass - evtl. praktisch während der Entwicklungsphase&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Oauth2Login&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupSitemap&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Blackhole&amp;#039;&amp;#039;&amp;#039; - Lockt Bots die robots.txt missachten in ein Blackhole -&amp;gt; werden gebannt&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminThemeBoss&amp;#039;&amp;#039;&amp;#039; - Platzsparendes zurückhaltendes uikit 3 Theme. Setzt auf dem Standard Theme auf&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MillSite&amp;#039;&amp;#039;&amp;#039; - Milligram SiteProfile mit einigen Zusatzfeatures&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MillBlog&amp;#039;&amp;#039;&amp;#039; - Milligram Framework Blog SiteProfile&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SeoMaestro&amp;#039;&amp;#039;&amp;#039; - SEO Tool noch Alpha (2019-02)&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_N%C3%BCtzliche_Module&amp;diff=24838</id>
		<title>ProcessWire - Nützliche Module</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_N%C3%BCtzliche_Module&amp;diff=24838"/>
		<updated>2020-10-28T08:21:25Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: /* Social Functionality Community Stuff */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Mal anschauen ==&lt;br /&gt;
 https://modules.processwire.com/modules/process-cache-control/&lt;br /&gt;
 https://modules.processwire.com/modules/inputfield-selector-select-id/ SeitenID über Seitenbaum in Modalwindow holen&lt;br /&gt;
 https://modules.processwire.com/modules/markup-sitemap-xml/&lt;br /&gt;
 https://modules.processwire.com/modules/process-page-field-select-creator/&lt;br /&gt;
 https://modules.processwire.com/modules/pro-cache/&lt;br /&gt;
 https://modules.processwire.com/modules/fieldtype-page-table-extended/&lt;br /&gt;
 https://modules.processwire.com/modules/fieldtype-rock-awesome/ FontAwsome Icons einfügen&lt;br /&gt;
 https://modules.processwire.com/modules/rest-api/ REST&lt;br /&gt;
 https://modules.processwire.com/modules/process-graph-ql/&lt;br /&gt;
 https://modules.processwire.com/modules/maintenance-mode/&lt;br /&gt;
 https://modules.processwire.com/modules/fieldtype-secure-file/&lt;br /&gt;
 https://modules.processwire.com/modules/mobile-detect/ mal schauen wie es gemacht ist&lt;br /&gt;
 https://modules.processwire.com/modules/search-engine/&lt;br /&gt;
 https://modules.processwire.com/modules/cronjob-empty-trash/ schauen wie es gemacht ist&lt;br /&gt;
 https://modules.processwire.com/modules/process-general-settings/ anschauen&lt;br /&gt;
 https://modules.processwire.com/modules/file-validator-svg-sanitizer/&lt;br /&gt;
 https://modules.processwire.com/modules/download-guard/ Download Link&lt;br /&gt;
 https://modules.processwire.com/modules/payment-stripe/ Stripe Erweiterung für Payment Modul&lt;br /&gt;
 https://modules.processwire.com/modules/payment-module/ &lt;br /&gt;
 https://modules.processwire.com/modules/payment-paypal/ Papal Erweiterung für Payment Modul&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dies ist keine vollständige Liste aber mal eine kleine Hilfe auch um Kunden Module anbieten zu können...&lt;br /&gt;
 * Cool&lt;br /&gt;
 ** Sehr Hilfreich - Killerfeatures für Kunden&lt;br /&gt;
 *** Musthave Ohne geht&amp;#039;s nicht&lt;br /&gt;
== Development ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessAdminActions&amp;#039;&amp;#039;&amp;#039; *** - Musthave bei komplexen Projekten. Kann viele Dinge als Batch erledigen und spart unendlich Zeit.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;GithubConnect&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ConnectPageFields&amp;#039;&amp;#039;&amp;#039; 2 Wege Verbindung für Datenfelder. Kein richtiges m:n, hält aber die Felder synchron&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;jQueryDataTables&amp;#039;&amp;#039;&amp;#039; - Datatables in eigenen Modulen verwenden https://modules.processwire.com/modules/jquery-data-tables/&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;HelperFieldLinks&amp;#039;&amp;#039;&amp;#039; - Infos zu Feldern anzeigen und Shortcuts zu den Templates und Felddefinitionen die dazugehören.&lt;br /&gt;
&lt;br /&gt;
=== Debugging ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TracyDebugger&amp;#039;&amp;#039;&amp;#039; *** - für programmierlastige Projekte das Debugger Tool der Wahl&lt;br /&gt;
&lt;br /&gt;
=== Daten Im- / Exportieren ===&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ImportPagesCSV&amp;#039;&amp;#039;&amp;#039; *** - Importiert CSV Daten als Seiten in ProcessWire&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TableCsvImportExport&amp;#039;&amp;#039;&amp;#039; - Importiert CSV Daten in Table Fields&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;[[DataSet - ProcessWire Modul|DataSet]]&amp;#039;&amp;#039;&amp;#039; - Importiert CSV und XML Daten. Config-Datei für Anweisungen. Kann mit Tasker auch als Cronjob laufen. Für große Datenssätze. https://github.com/mtwebit/DataSet&lt;br /&gt;
&lt;br /&gt;
== Administration / Verwaltung ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminRestrictBranch&amp;#039;&amp;#039;&amp;#039; - Redakteure auf einen Seitenzweig beschränken&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ModulesManager&amp;#039;&amp;#039;&amp;#039; - Zugriff auf das offizielle Modulverzeichnis aus dem Backend heraus&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageReferencesTab&amp;#039;&amp;#039;&amp;#039; - Seitenverwaltung &amp;quot;Welche Seiten verweisen auf diese mittels PageReference Field&amp;quot;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;EmailNewUser&amp;#039;&amp;#039;&amp;#039; - User über seinen Account Informieren. Nutzen mit &amp;#039;&amp;#039;&amp;#039;PasswordForceChange&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessWireUpgrade&amp;#039;&amp;#039;&amp;#039; ** - Informiert über Upgrades - nützlich wenn man Updates als kostnpfl. Service anbieten möchte&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessJumplinks&amp;#039;&amp;#039;&amp;#039; * - Redirects verwalten&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageRenameOptions&amp;#039;&amp;#039;&amp;#039; - Ändert den Seitennamen bei Änderung des Titels. Am besten mit PagePathHistory verwenden wg. broken Links.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RestrictRepeaterMatrix&amp;#039;&amp;#039;&amp;#039; Zugriff auf Repeater Matrix Felder regulieren [[RestrictRepeaterMatrix (ProcessWire Modul)]]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TemplatesChildPages&amp;#039;&amp;#039;&amp;#039; Zugriff auf Kindseiten einschränken - erweitert Zugriffsregeln auf Seitenbasis, statt nur auf Templatebasis&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CronjobDatabaseBackup&amp;#039;&amp;#039;&amp;#039; Automatische Datenbank Backups - nutzt LazyCron&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminPageFieldEditLinks&amp;#039;&amp;#039;&amp;#039; - Anlegen und Verändern von Seiten die auf diese Zeigen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ConnectPageFields&amp;#039;&amp;#039;&amp;#039; - Zweiwege Verbindung von Page References (jede Seite zeigt auf die andere)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessPageFieldSelectCreator&amp;#039;&amp;#039;&amp;#039; - Erzeugt Templates, Seiten und Felder für Select Strukturen z.B. Parentseite RoomTypes und Kindseiten Single Double Suite. &lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminLinksInFrontend&amp;#039;&amp;#039;&amp;#039; - Einstellbare Admin Links für das Bearbeiten der Seite + User Switcher...&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Duplicator&amp;#039;&amp;#039;&amp;#039; - Duplizieren von Installationen inklusive Datenbank. Gut für regelmäßige Backups auch Crongesteuert und in die Cloud. Vorsicht beim Duplizieren für andere Websites, das Salz für die Verschlüsselung bleibt dann gleich.&lt;br /&gt;
&lt;br /&gt;
== Navigation / Menüs ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessMenuBuilder&amp;#039;&amp;#039;&amp;#039; - Manuelle Custom Menu Erstellung - sinnvoll bei sehr individuellen Navigationen. &lt;br /&gt;
&lt;br /&gt;
== Hilfe für Redakteure ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AssistedURL&amp;#039;&amp;#039;&amp;#039; - Linkhilfe Adrians Fork ist oft weiter (https://github.com/adrianbj/processwire-fieldtype-assisted-url)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PrevNextTabs&amp;#039;&amp;#039;&amp;#039; - Abkürzung zur nächsten / vorigen Seite im Backend. Sinnvoll wenn viele Seiten bearbeitet werden müssen.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CkeLinkFiles&amp;#039;&amp;#039;&amp;#039; - Dateilinks leichter im Editor einfügen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SchedulePages&amp;#039;&amp;#039;&amp;#039; - Seiten auf Termin veröffentlichen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ImageCropRatios&amp;#039;&amp;#039;&amp;#039; - Super nützlich für Bildcropping mit Aspect Ratio (vorgegebene Seitenverhältnisse)&lt;br /&gt;
&lt;br /&gt;
== Sicherheit und Recht ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;EmailObfuscation&amp;#039;&amp;#039;&amp;#039; **&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupCookieConsent&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CookieManagementBanner&amp;#039;&amp;#039;&amp;#039; - von Adrian&lt;br /&gt;
&lt;br /&gt;
== Bedienungshilfen / Backend / Fieldtypes==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AssistedUrl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MinimalFieldset&amp;#039;&amp;#039;&amp;#039; - läßt flexiblere Gestaltung der Felder im Backend zu.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageListSelectMultipleQuickly&amp;#039;&amp;#039;&amp;#039; Mehrere Seiten auwählen ohne jedesmal den Baum neu zu öffnen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;PageFieldInfo&amp;#039;&amp;#039;&amp;#039; - zusätzliche Infos bei Page Select Checkboxen anzeigen (bei hover und wenn gecheckt)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FieldtypeTime&amp;#039;&amp;#039;&amp;#039; - Feld zum Speichern von Zeit und Zeitintervallen, Es gibt noch ein weiteres schickes Zeitfeld mit Eingabehilfe (Genbänkle oder Yoga Namaste ? - TODO)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RuntimeMarkup&amp;#039;&amp;#039;&amp;#039; - Feld das PHP Code ausführen und das Ergebnis im Backend anzeigen kann. So kann man dynamischen Inhalt im Backend anzeigen z.B. Informationen aus Kindseiten etc.  &lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FieldtypeSelectExtOption&amp;#039;&amp;#039;&amp;#039; - Select Felder bei dem die Optionen aus einer externen Quelle kommen können (z.B. eine Tabelle)&lt;br /&gt;
&lt;br /&gt;
== Markup etc. erzeugen ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Pages2Pdf&amp;#039;&amp;#039;&amp;#039; - Wrapper für mPdf Library zur PDF Erzeugung&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RockPdf&amp;#039;&amp;#039;&amp;#039; - Wrapper für mPdf Library von Bernhard Baumrock (https://github.com/BernhardBaumrock/RockPDF, https://modules.processwire.com/modules/rock-pdf/, https://processwire.com/talk/topic/19468-360%C2%B0-feedbacksurvey-tool/)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterHannaCode&amp;#039;&amp;#039;&amp;#039; ** - Snippets für den Editor erstellen, die dann komplexeren Markup erzeugen können (Killer für Wordpress-Lovers) &lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterAutoAnchor&amp;#039;&amp;#039;&amp;#039; - Erzeugt automatisch Ids und Slugs in den Überschrift Elementen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterSoundmanager&amp;#039;&amp;#039;&amp;#039; - Formatter für den Soundmanager2 Player - kann auch Multitrack und krasse Visualisierungen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FieldtypePhone&amp;#039;&amp;#039;&amp;#039; - Standard Telefonformatierung (https://github.com/adrianbj/FieldtypePhone)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;TextformatterFileInfo&amp;#039;&amp;#039;&amp;#039; - Dateiinfo Textformatter&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;InputfieldMarkupCKEditor&amp;#039;&amp;#039;&amp;#039; - Text in Formbuilder Formularen einfügen&lt;br /&gt;
&lt;br /&gt;
== Social Functionality Community Stuff ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;NewsletterSubscription&amp;#039;&amp;#039;&amp;#039; - Double Opt In Funktionalität für Newsletter etc.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;LoginRegister&amp;#039;&amp;#039;&amp;#039; - Ryans Self Registration Beispiel&lt;br /&gt;
&lt;br /&gt;
== SEO Module ==&lt;br /&gt;
* SEOMaestro - Quasi Nachfolger von MarkupSEO ?&lt;br /&gt;
* ProcessJumplinks - Manage Referers Basiert auf dem älteren &lt;br /&gt;
* MarkupRSS&lt;br /&gt;
* MarkupSitemap Erweiterte Version von MarkupSitemapXML. Kann auch Multilanguage Sites Managen.&lt;br /&gt;
* Process404Page - Load search results into 404 page using terms from the failed URL&lt;br /&gt;
* https://modules.processwire.com/modules/profields-autolinks/ - Generiert automatisch Links&lt;br /&gt;
* SearchEngineReferrerTracker - speichert Keywords über die Besucher von Suchmaschinen gekommen sind. Matomo kann das auch, dies wäre aber eine einfache Lösung.&lt;br /&gt;
&lt;br /&gt;
== DSGVO ==&lt;br /&gt;
* MarkupCookieConsent - noch nicht getestet&lt;br /&gt;
&lt;br /&gt;
== Structured Data - Schema.org ==&lt;br /&gt;
* MarkupJsonLDSchema&lt;br /&gt;
&lt;br /&gt;
== Mal Testen ==&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessCustomUploadNames&amp;#039;&amp;#039;&amp;#039; - Renaming Rulse for Pages and other fields.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;ProcessBlog&amp;#039;&amp;#039;&amp;#039; - Blog Modul von Ryan (für das Blog Profile entwickelt)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupSocialShareButtons&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupPlyrMediaPlayer&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;InstagramFeed&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MediaLibrary&amp;#039;&amp;#039;&amp;#039; - Medienzugriff über Libraries. Auswahl in übergeordneten Seiten möglich.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;FrontEndEditLightbox&amp;#039;&amp;#039;&amp;#039; - Frontend Editing der aktuellen Seite in einer Lightbox&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Sassify&amp;#039;&amp;#039;&amp;#039; - Kompiliert Sass/SCSS/Compass - evtl. praktisch während der Entwicklungsphase&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Oauth2Login&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MarkupSitemap&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Blackhole&amp;#039;&amp;#039;&amp;#039; - Lockt Bots die robots.txt missachten in ein Blackhole -&amp;gt; werden gebannt&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;AdminThemeBoss&amp;#039;&amp;#039;&amp;#039; - Platzsparendes zurückhaltendes uikit 3 Theme. Setzt auf dem Standard Theme auf&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MillSite&amp;#039;&amp;#039;&amp;#039; - Milligram SiteProfile mit einigen Zusatzfeatures&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;MillBlog&amp;#039;&amp;#039;&amp;#039; - Milligram Framework Blog SiteProfile&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SeoMaestro&amp;#039;&amp;#039;&amp;#039; - SEO Tool noch Alpha (2019-02)&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Navigation_Snippets&amp;diff=24837</id>
		<title>ProcessWire - Navigation Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Navigation_Snippets&amp;diff=24837"/>
		<updated>2020-10-28T07:53:03Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: /* Nested List ausgehend von einer Seite (meistens Homepage) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== TODO Seite aufräumen ==&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
 [[Processwire Module: MarkupSimpleNavigation]] automatisch Navigation aus Seitenbaum erstellen&lt;br /&gt;
 [[Aligator (ProcessWire)]] - automatische Navigation, gut wenn manipuliert werden muss.&lt;br /&gt;
 [[Menu Builder (ProcessWire)]] - Menüs im Backend erstellen (Wordpress like)&lt;br /&gt;
&lt;br /&gt;
== Navigation in Pagewire - Einführung ==&lt;br /&gt;
=== Navigationstypen allgemein ===&lt;br /&gt;
Es gibt verschiedene &amp;#039;&amp;#039;&amp;#039;Typen von Navigationen&amp;#039;&amp;#039;&amp;#039;. In Processwire hat man ein &amp;#039;&amp;#039;&amp;#039;Pages Objekt&amp;#039;&amp;#039;&amp;#039;, indem auch Zugriff auf Kind- und Elternseiten möglich sind. Es bildet also immer die Sitestruktur ab. Daher übergibt man an die unten aufgeführten Funktionen entweder die Homepage oder die aktuelle Seite.&lt;br /&gt;
&lt;br /&gt;
Unter dem Aspekt auf welcher Seite man sich befindet kann man unterscheiden zwischen:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;absolute Navigation&amp;#039;&amp;#039;&amp;#039; normalerweise ausgehend von der Rootseite. diese ist dann auf allen Seiten gleich.&lt;br /&gt;
** z.B. alle Seiten des ersten Levels stehen in der Hauptnavigation egal auf welcher Seite ich im Moment bin&lt;br /&gt;
** z.B. verschachtelte Liste mit 2 oder mehr Leveln für Dropdown Navigationen wie Superfish, Megamenüs (mit zusätzlichen Infos...) oder Bootstrap Navigationen.&lt;br /&gt;
** Sitemap&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Navigation relativ zur Seite&amp;#039;&amp;#039;&amp;#039; Diese kann sich von Seite zu Seite unterscheiden.&lt;br /&gt;
** Alle &amp;#039;&amp;#039;&amp;#039;Seiten der aktuellen Ebene&amp;#039;&amp;#039;&amp;#039; (oft kombiniert mit Breadcrumb / Hier-bin-ich) ) &lt;br /&gt;
** Hauptebene &amp;#039;&amp;#039;&amp;#039;und&amp;#039;&amp;#039;&amp;#039; aktueller Level&lt;br /&gt;
** Alle Ebenen &amp;#039;&amp;#039;&amp;#039;bis zur aktuellen Seite + deren Unterseiten&amp;#039;&amp;#039;&amp;#039; falls vorhanden. &lt;br /&gt;
In letzten Fall könnte man auch Varianten bauen in denen eine Verschachtelte Liste erzeugt wird aber nur bestimmte Teile absolut Positioniert angezeigt werden und andere versteckt werden. Manchmal möchte man bestimmte Level aber auch an anderer Position zeigen (z.B. Sidebar)&lt;br /&gt;
In der Praxis hat man in der Regel&lt;br /&gt;
* Mindestens eine Hauptnavigation mit allen Seiten der 1. Ebene oder eine Hauptnavigation mit mehreren Ebenen für Dropdown Navigationen, mobile Navigation oder auch Sitemapartige Navigationen für den Footer (oft mit kleinen Beschreibungen).&lt;br /&gt;
* Eine Metanavigation mit Service Seiten wie Kontakt, Impressum etc. oft ist diese im Footer.&lt;br /&gt;
&lt;br /&gt;
=== Unterschiede zwischen Verstecken, Veröffentlichen, Sperren ===&lt;br /&gt;
In Processwire sind diese Begriffe mit Userrechten verknüpft. Eine unveröffentlichte Seite kann also durchaus im Frontend aufgerufen werden (es sei denn man regelt das anders.) Vielmehr geht es darum das man User Rollen so gestalten kann, dass man z.B. einem User nur erlaubt unveröffentlichte Seiten zu editieren.&lt;br /&gt;
&lt;br /&gt;
Denoch gibt es auch ein paar weitere Unterschiede.&lt;br /&gt;
&lt;br /&gt;
Gesperrt -&amp;gt; Man kann die Seite nicht zum Editieren aufrufen. Über die Url kann Sie aufgerufen werden.&lt;br /&gt;
&lt;br /&gt;
Unpublished -&amp;gt; Die Seite kann sobald sie gespeichert ist auch aufgerufen werden, WENN der User berechtigt ist. Nicht für Guest User (der normale Viewer)&lt;br /&gt;
&lt;br /&gt;
TODO checken ob die Tabelle so für nicht angemeldete User stimmt.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  !! Im Menü ($pages-&amp;gt;find) !! Über URL erreichbar($pages-&amp;gt;get) !! Ausgabe im Frontend !! &lt;br /&gt;
|-&lt;br /&gt;
| Unpublished / Unveröffentlicht || Nein || Nur User mit passenden Rechten. Gäste -&amp;gt; leere Seite ||&lt;br /&gt;
|-&lt;br /&gt;
| Hidden / Versteckt || Nein || Ja || Ja - leere Seite (keine Feldausgabe)&lt;br /&gt;
|-&lt;br /&gt;
| Locked / Gesperrt || Ja || Ja  || Ja&lt;br /&gt;
|-&lt;br /&gt;
| Trash || Nein || Nein ||&lt;br /&gt;
|}&lt;br /&gt;
==== Seiten auf unveröffentlicht stellen ====&lt;br /&gt;
https://processwire.com/talk/topic/29-how-to-unpublish-a-page-without-deleting-it/&lt;br /&gt;
&lt;br /&gt;
Was soll man tun wenn man eine Seite tatsächlich nicht mehr anzeigen will, sie aber noch nicht wegwerfen will?&lt;br /&gt;
Ryan schlägt folgendes vor:&lt;br /&gt;
* Mülleimer&lt;br /&gt;
* Remove Guest Role in Template&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
=== Basic Navigation ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
  // get the homepage object&lt;br /&gt;
  $homePage = $pages-&amp;gt;get(&amp;quot;/&amp;quot;);&lt;br /&gt;
  // get PageArray of homepage object and child page objects&lt;br /&gt;
  $navItems = $homePage-&amp;gt;and($homePage-&amp;gt;children);&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
Now you have a PageArray with the required items, you can iterate over them one at a time, and print the title of the page and the link to the page itself and wrap the whole thing in your list tag.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul class=&amp;quot;nav&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
  // get the homepage object&lt;br /&gt;
  $homePage = $pages-&amp;gt;get(&amp;quot;/&amp;quot;);&lt;br /&gt;
  // get PageArray of homepage object and child page objects&lt;br /&gt;
  $navItems = $homePage-&amp;gt;and($homePage-&amp;gt;children);&lt;br /&gt;
  // or if you don&amp;#039;t want the home link&lt;br /&gt;
  // $navItems = $homePage-&amp;gt;children;&lt;br /&gt;
  // iterate over the $navItems PageArray&lt;br /&gt;
  foreach ($navItems as $navItem):&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;li class=&amp;quot;nav-item&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;a class=&amp;quot;nav-link&amp;quot; href=&amp;quot;&amp;lt;?php echo $navItem-&amp;gt;url; ?&amp;gt;&amp;quot;&amp;gt;&amp;lt;?php echo $navItem-&amp;gt;title; ?&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;?php endforeach; ?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Basic mit active Class ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;ul class=&amp;quot;nav&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
  // get the homepage object&lt;br /&gt;
  $homePage = $pages-&amp;gt;get(&amp;quot;/&amp;quot;);&lt;br /&gt;
  // get PageArray of homepage object and child page objects&lt;br /&gt;
  $navItems = $homePage-&amp;gt;and($homePage-&amp;gt;children);&lt;br /&gt;
  // or if you don&amp;#039;t want the home link&lt;br /&gt;
  // $navItems = $homePage-&amp;gt;children;&lt;br /&gt;
  // iterate over the $navItems PageArray&lt;br /&gt;
  foreach ($navItems as $navItem):&lt;br /&gt;
&lt;br /&gt;
// if the id of the page currently being&lt;br /&gt;
// iterated equals the id of the current page&lt;br /&gt;
$activeClass = ($navItem-&amp;gt;id == $page-&amp;gt;id) ? &amp;quot; active&amp;quot; : &amp;quot;&amp;quot;;&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;li class=&amp;quot;nav-item&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;a class=&amp;quot;nav-link&amp;lt;?php echo $activeClass; ?&amp;gt;&amp;quot; href=&amp;quot;&amp;lt;?php echo $navItem-&amp;gt;url; ?&amp;gt;&amp;quot;&amp;gt;&amp;lt;?php echo $navItem-&amp;gt;title; ?&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;?php endforeach; ?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Child Menu ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul class=&amp;quot;sub-menu&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
  // get children of the parent of the current page&lt;br /&gt;
  $childPages = $page-&amp;gt;parent-&amp;gt;children;&lt;br /&gt;
&lt;br /&gt;
  // iterate over the $navItems PageArray&lt;br /&gt;
  foreach ($childPages as $childPage):&lt;br /&gt;
&lt;br /&gt;
  // if the id of the page currently being&lt;br /&gt;
  // iterated equals the id of the current page&lt;br /&gt;
  $activeClass = ($navItem-&amp;gt;id == $page-&amp;gt;id) ? &amp;quot; active&amp;quot; : &amp;quot;&amp;quot;;&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;li class=&amp;quot;nav-item&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;a class=&amp;quot;nav-link&amp;lt;?php echo $activeClass; ?&amp;gt;&amp;quot; href=&amp;quot;&amp;lt;?php echo $childPage-&amp;gt;url; ?&amp;gt;&amp;quot;&amp;gt;&amp;lt;?php echo $childPage-&amp;gt;title; ?&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;?php endforeach; ?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Page Level ===&lt;br /&gt;
In which level in page tree we are?&lt;br /&gt;
 $level = count($page-&amp;gt;parents);&lt;br /&gt;
&lt;br /&gt;
=== Link to Subpage und Platzhalter (Spacer) ===&lt;br /&gt;
Kann man gut für Superfish Menüs etc. benutzen. Bildet das Verhalten von Shortcuts und Spacern aus TYPO3 nach.&lt;br /&gt;
&lt;br /&gt;
Anpassung der renderNavTree() Funktion von Ryan Cramer. Options Field Installieren und als globales Feld &amp;quot;navigation_type&amp;quot; mit den Optionen &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1=normal|Normal&lt;br /&gt;
2=doNotLink|Do not link&lt;br /&gt;
3=linkToFirstChild|Link to first childpage&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
konfigurieren. Dann Funktion etwa so anpassen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
// cycle through all the items&lt;br /&gt;
	foreach($items as $item) {&lt;br /&gt;
&lt;br /&gt;
		// markup for the list item...&lt;br /&gt;
		// if current item is the same as the page being viewed, add a &amp;quot;current&amp;quot; class to it&lt;br /&gt;
		$out .= $item-&amp;gt;id == wire(&amp;#039;page&amp;#039;)-&amp;gt;id ? &amp;quot;&amp;lt;li class=&amp;#039;current&amp;#039;&amp;gt;&amp;quot; : &amp;quot;&amp;lt;li&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
		// markup for the link&lt;br /&gt;
		$navigation_type = $item-&amp;gt;navigation_type-&amp;gt;id;&lt;br /&gt;
		switch ( $navigation_type ) {&lt;br /&gt;
			case 2: // do not link&lt;br /&gt;
				$out .= &amp;quot;&amp;lt;span class=&amp;#039;spacer&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
				break;&lt;br /&gt;
			case 3: // link to subpage&lt;br /&gt;
				if( $item-&amp;gt;hasChildren() ){&lt;br /&gt;
					$out .= &amp;#039;&amp;lt;a href=&amp;quot;&amp;#039;.$item-&amp;gt;child-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/a&amp;gt;&amp;#039;;&lt;br /&gt;
				}else{&lt;br /&gt;
					$out .= &amp;quot;&amp;lt;span class=&amp;#039;spacer&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
				}&lt;br /&gt;
				break;&lt;br /&gt;
			default:&lt;br /&gt;
				$out .= &amp;quot;&amp;lt;a href=&amp;#039;$item-&amp;gt;url&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/a&amp;gt;&amp;quot;;&lt;br /&gt;
				break;&lt;br /&gt;
		}&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Redirect (301) ===&lt;br /&gt;
==== Redirect zu erster Unterseite ====&lt;br /&gt;
https://processwire.com/talk/topic/15-how-do-i-create-a-page-that-redirects-to-its-first-child/&lt;br /&gt;
&lt;br /&gt;
Field &amp;#039;&amp;#039;redirects_to_first_child&amp;#039;&amp;#039; erstellen und im Template einfügen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php &lt;br /&gt;
  if($page-&amp;gt;numChildren &amp;amp;&amp;amp; $page-&amp;gt;redirects_to_first_child) &lt;br /&gt;
  $session-&amp;gt;redirect($page-&amp;gt;child()-&amp;gt;url); &lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Erzeugt 301 Weiterleitung&lt;br /&gt;
&lt;br /&gt;
Anderer Ansatz wäre evtl. den Link bei der Menügenerierung direkt zu generieren. finde ich persönlich besser siehe &amp;#039;&amp;#039;Link to subpage und Platzhalter&amp;#039;&amp;#039; Beispiel. Allerdings sollte man dann vielleicht die Seite trotzdem per 301 Weiterleiten, falls die URL mal direkt aufgerufen wird oder bei Google gelistet ist.&lt;br /&gt;
&lt;br /&gt;
==== Redirect zu anderer Seite in der Navigation ====&lt;br /&gt;
https://processwire.com/talk/topic/762-howto-menu-item-that-links-to-another-page/&lt;br /&gt;
&lt;br /&gt;
1. Create a new field and call it &amp;#039;redirect_url&amp;#039; or something like that, and use the &amp;#039;URL&amp;#039; fieldtype. &lt;br /&gt;
&lt;br /&gt;
2. Add that field to your template where you&amp;#039;d want to use it, or create a new template just for the purpose, like a template named &amp;#039;redirect&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
3. Edit the page that you want to be a symlink and populate the &amp;#039;redirect_url&amp;#039; field with the URL you want it to redirect to.&lt;br /&gt;
&lt;br /&gt;
4. In your nav-generation code that links to the pages, do something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$url = $subpage-&amp;gt;get(&amp;quot;redirect_url|url&amp;quot;); // use redirect_url if there, otherwise use url&lt;br /&gt;
echo &amp;quot;&amp;lt;a href=&amp;#039;$url&amp;#039;&amp;gt;{$subpage-&amp;gt;title}&amp;lt;/a&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
5. You might also want to add this to your template that has the &amp;#039;redirect_url&amp;#039; field: just in case there&amp;#039;s anything linking to it directly. That way it&amp;#039;ll send people to the right place either way:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 if($page-&amp;gt;redirect_url) $session-&amp;gt;redirect($page-&amp;gt;redirect_url); &lt;br /&gt;
&lt;br /&gt;
=== Breadcrumb ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	&amp;lt;!-- breadcrumbs --&amp;gt;&lt;br /&gt;
	&amp;lt;div class=&amp;#039;breadcrumbs&amp;#039;&amp;gt;&amp;lt;?php &lt;br /&gt;
		// breadcrumbs are the current page&amp;#039;s parents&lt;br /&gt;
		foreach($page-&amp;gt;parents() as $item) {&lt;br /&gt;
			echo &amp;quot;&amp;lt;span&amp;gt;&amp;lt;a href=&amp;#039;$item-&amp;gt;url&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt; &amp;quot;; &lt;br /&gt;
		}&lt;br /&gt;
		// optionally output the current page as the last item&lt;br /&gt;
		echo &amp;quot;&amp;lt;span&amp;gt;$page-&amp;gt;title&amp;lt;/span&amp;gt; &amp;quot;; &lt;br /&gt;
	?&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== One Level Navigation Bar ===&lt;br /&gt;
[[ProcessWire - One Level Navigation]]&lt;br /&gt;
=== Nächste Seite / Next Page Navigation ===&lt;br /&gt;
Beispiel 1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if($page-&amp;gt;next-&amp;gt;id){&lt;br /&gt;
  $next = &amp;#039;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;next&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;i&amp;gt;Next:&amp;lt;/i&amp;gt;&amp;amp;nbsp;&lt;br /&gt;
      &amp;lt;a class=&amp;quot;ajax-link&amp;quot; name=&amp;quot;&amp;#039;.$page-&amp;gt;next-&amp;gt;title.&amp;#039;&amp;quot; href=&amp;quot;&amp;#039;. $page-&amp;gt;next-&amp;gt;url .&amp;#039;&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;#039;. $page-&amp;gt;next-&amp;gt;title .&amp;#039;&amp;lt;span class=&amp;quot;fa fa-arrow-right&amp;quot;&amp;gt;&amp;lt;span&amp;gt;&lt;br /&gt;
      &amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel 2 (mit zurück zur Elternseite)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$next = &amp;#039;&amp;#039;;&lt;br /&gt;
if($page-&amp;gt;next-&amp;gt;id){&lt;br /&gt;
  $next = &amp;#039;&lt;br /&gt;
  &amp;lt;a href=&amp;quot;&amp;#039;.$page-&amp;gt;next-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;i class=&amp;quot;fa fa-angle-right&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&lt;br /&gt;
  &amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$prev = &amp;#039;&amp;#039;;&lt;br /&gt;
if($page-&amp;gt;prev-&amp;gt;id){&lt;br /&gt;
  $prev = &amp;#039;&lt;br /&gt;
  &amp;lt;a href=&amp;quot;&amp;#039;.$page-&amp;gt;prev-&amp;gt;url.&amp;#039;&amp;quot; class=&amp;quot;w-inline-block paginaton-but&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;i class=&amp;quot;fa fa-angle-left&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&lt;br /&gt;
  &amp;lt;/a&amp;gt;&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$pagination = &amp;#039;&lt;br /&gt;
&amp;lt;div class=&amp;quot;container pagination&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;div class=&amp;quot;col col-md-4&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;align-center&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;#039;.$prev.&amp;#039;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div class=&amp;quot;col col-md-4&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;align-center&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;a href=&amp;quot;&amp;#039;.$page-&amp;gt;parent-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;i class=&amp;quot;fa fa-th&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&lt;br /&gt;
        &amp;lt;/a&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div class=&amp;quot;col col-md-4&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;align-right center&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;#039;.$next.&amp;#039;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
echo $pagination;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zurück zur Elternseite ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;back&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;&amp;#039;.$page-&amp;gt;parent()-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;zurück&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kindseiten mit $page-&amp;gt;children ===&lt;br /&gt;
 &amp;lt;?=$page-&amp;gt;children?&amp;gt;&lt;br /&gt;
Output&lt;br /&gt;
 5723,4958,5937&lt;br /&gt;
&lt;br /&gt;
Beispiel&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
foreach($page-&amp;gt;children as $child)&lt;br /&gt;
  echo &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;{$child-&amp;gt;url}&amp;#039;&amp;gt;{$child-&amp;gt;title}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
?&amp;gt; &lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Ergebnis:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;/about/contact/&amp;#039;&amp;gt;Contact Us&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;/about/press/&amp;#039;&amp;gt;Press Releases&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;/about/staff/&amp;#039;&amp;gt;Our Staff&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Children Tree ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function listChildrenTree($children, $current, $w) {&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;&amp;lt;ul&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
foreach($children as $page) {&lt;br /&gt;
&lt;br /&gt;
	$class = &amp;#039;&amp;#039;;&lt;br /&gt;
	if($page === $current || $current-&amp;gt;parents-&amp;gt;slice(1)-&amp;gt;has($page) ) {&lt;br /&gt;
		$class = &amp;quot;class=&amp;#039;on&amp;#039; style=&amp;#039;font-weight:bold&amp;#039;&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	$rootid = $w-&amp;gt;pages-&amp;gt;get(&amp;quot;/&amp;quot;)-&amp;gt;id;&lt;br /&gt;
&lt;br /&gt;
	echo &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;{$page-&amp;gt;url}&amp;#039; $class&amp;gt;&amp;quot;;&lt;br /&gt;
	if($page-&amp;gt;id == $rootid) echo &amp;quot;&amp;lt;img src=&amp;#039;&amp;quot; . $w-&amp;gt;config-&amp;gt;urls-&amp;gt;templates . &amp;quot;styles/images/home.png&amp;#039; width=&amp;#039;24&amp;#039; height=&amp;#039;28&amp;#039; alt=&amp;#039;&amp;#039; /&amp;gt;&amp;quot;;&lt;br /&gt;
	echo &amp;quot;{$page-&amp;gt;title}&amp;lt;/a&amp;gt; &amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	if($page-&amp;gt;numChildren &amp;amp;&amp;amp; $page-&amp;gt;id != $rootid) listChildrenTree($page-&amp;gt;children, $current, $w);&lt;br /&gt;
&lt;br /&gt;
	echo &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
echo &amp;quot;&amp;lt;/ul&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$children = $pages-&amp;gt;get(&amp;quot;/&amp;quot;)-&amp;gt;children();&lt;br /&gt;
$children-&amp;gt;prepend($pages-&amp;gt;get(&amp;quot;/&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
listChildrenTree($children, $page, $wire);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bootstrap Navigation ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
// Markup to use wicht navigation_type field (normal=1, no-link=2,subpage=3)&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
// bundle up the first level pages and prepend the root home page&lt;br /&gt;
$homepage = $pages-&amp;gt;get(1);&lt;br /&gt;
$pa = $homepage-&amp;gt;children;&lt;br /&gt;
$pa = $pa-&amp;gt;prepend($homepage);&lt;br /&gt;
&lt;br /&gt;
// Set the ball rolling...&lt;br /&gt;
$myMenu = renderChildrenOf($pa);&lt;br /&gt;
$wrapper = &amp;#039;&lt;br /&gt;
&amp;lt;nav class=&amp;quot;navbar navbar-default&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div class=&amp;quot;container-fluid&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;navbar-header&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;navbar-toggle collapsed&amp;quot; data-toggle=&amp;quot;collapse&amp;quot; data-target=&amp;quot;#navbar-collapse-1&amp;quot; aria-expanded=&amp;quot;false&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;span class=&amp;quot;sr-only&amp;quot;&amp;gt;Menü&amp;lt;/span&amp;gt;&lt;br /&gt;
        &amp;lt;span class=&amp;quot;icon-bar&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
        &amp;lt;span class=&amp;quot;icon-bar&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
        &amp;lt;span class=&amp;quot;icon-bar&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
      &amp;lt;/button&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;collapse navbar-collapse&amp;quot; id=&amp;quot;navbar-collapse-1&amp;quot;&amp;gt;&lt;br /&gt;
      |&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;#039;;&lt;br /&gt;
$myMenu = wrap($myMenu,$wrapper);&lt;br /&gt;
echo $myMenu;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
Navigation for ProcessWire using the Bootstrap 2.2.2 markup&lt;br /&gt;
This menu was written by Soma based on work by NetCarver and a bit thrown in by Joss&lt;br /&gt;
Bootstrap 3 update by Damienov, with multi level dropdown support fix&lt;br /&gt;
*/&lt;br /&gt;
function renderChildrenOf($pa, $output = &amp;#039;&amp;#039;, $level = 0)&lt;br /&gt;
{&lt;br /&gt;
    $output = &amp;#039;&amp;#039;;&lt;br /&gt;
    $level++;&lt;br /&gt;
&lt;br /&gt;
    foreach ($pa as $child) {&lt;br /&gt;
        $atoggle = &amp;#039;&amp;#039;;&lt;br /&gt;
        $class = &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
        if ($child-&amp;gt;numChildren &amp;amp;&amp;amp; count($child-&amp;gt;parents) == 1) {&lt;br /&gt;
            $class .= &amp;#039;dropdown&amp;#039;;&lt;br /&gt;
            $atoggle .= &amp;#039; class=&amp;quot;dropdown-toggle&amp;quot; data-toggle=&amp;quot;dropdown&amp;quot;&amp;#039;;&lt;br /&gt;
        } else if ($child-&amp;gt;numChildren &amp;amp;&amp;amp; count($child-&amp;gt;parents) &amp;gt; 1 ) {&lt;br /&gt;
            $class .= &amp;#039;dropdown-submenu&amp;#039;;&lt;br /&gt;
            $atoggle .= &amp;#039; class=&amp;quot;dropdown-toggle&amp;quot;&amp;#039;;&lt;br /&gt;
        } else if ($child-&amp;gt;numChildren &amp;amp;&amp;amp; $child-&amp;gt;id != 1) {&lt;br /&gt;
            $class .= &amp;#039;dropdown-menu&amp;#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Makes the current page and it&amp;#039;s top level parent add an active class&lt;br /&gt;
        $class .= ($child === wire(&amp;quot;page&amp;quot;) || $child === wire(&amp;quot;page&amp;quot;)-&amp;gt;rootParent) ? &amp;quot; active&amp;quot; : &amp;#039;&amp;#039;;&lt;br /&gt;
        $class = strlen($class) ? &amp;quot; class=&amp;#039;&amp;quot; . trim($class) . &amp;quot;&amp;#039;&amp;quot; : &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
        if ($child-&amp;gt;numChildren &amp;amp;&amp;amp; count($child-&amp;gt;parents) == 1) {&lt;br /&gt;
            // Add Caret if have children&lt;br /&gt;
            $output .= &amp;quot;&amp;lt;li$class&amp;gt;&amp;lt;a href=&amp;#039;$child-&amp;gt;url&amp;#039;$atoggle&amp;gt;$child-&amp;gt;title &amp;lt;b class=&amp;#039;caret&amp;#039;&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;/a&amp;gt;&amp;quot;;&lt;br /&gt;
        } else if ($child-&amp;gt;numChildren &amp;amp;&amp;amp; count($child-&amp;gt;parents) &amp;gt; 1) {&lt;br /&gt;
            $output .= &amp;quot;&amp;lt;li$class&amp;gt;&amp;lt;a tabindex=&amp;#039;-1&amp;#039; href=&amp;#039;$child-&amp;gt;url&amp;#039;$atoggle&amp;gt;$child-&amp;gt;title&amp;lt;/a&amp;gt;&amp;quot;;&lt;br /&gt;
        } else {&lt;br /&gt;
            $output .= &amp;quot;&amp;lt;li$class&amp;gt;&amp;lt;a href=&amp;#039;$child-&amp;gt;url&amp;#039;$atoggle&amp;gt;$child-&amp;gt;title&amp;lt;/a&amp;gt;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // If this child is itself a parent and not the root page, then render it&amp;#039;s children in their own menu too...&lt;br /&gt;
        if ($child-&amp;gt;numChildren &amp;amp;&amp;amp; $child-&amp;gt;id != 1) {&lt;br /&gt;
            $output .= renderChildrenOf($child-&amp;gt;children, $output, $level);&lt;br /&gt;
        }&lt;br /&gt;
        $output .= &amp;#039;&amp;lt;/li&amp;gt;&amp;#039;;&lt;br /&gt;
    }&lt;br /&gt;
    $outerclass = ($level == 1) ? &amp;quot;nav navbar-nav&amp;quot; : &amp;#039;dropdown-menu&amp;#039;;&lt;br /&gt;
    return &amp;quot;&amp;lt;ul class=&amp;#039;$outerclass&amp;#039;&amp;gt;$output&amp;lt;/ul&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Modul: MarkupSimpleNavigation==&lt;br /&gt;
[[Processwire Modul - MarkupSimpleNavigation]]&lt;br /&gt;
&lt;br /&gt;
== Weitere Menübeispiele ==&lt;br /&gt;
=== Standard Tree Navigation ===&lt;br /&gt;
Für viele Zwecke ausreichend und leicht anpassbar, die klassische verschachtelte Liste.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Menüauswahl Hauptmenü / Metamenü / Footer-Navigation ===&lt;br /&gt;
Beispiel 1&lt;br /&gt;
Backend Feld menus anlegen Options: &lt;br /&gt;
&lt;br /&gt;
 1=Main Menu&lt;br /&gt;
 2=Meta Menu &lt;br /&gt;
&lt;br /&gt;
topnav.inc&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$pa = $homepage-&amp;gt;and($homepage-&amp;gt;children(&amp;quot;menus.id=1&amp;quot;));//only if main menu is checked&lt;br /&gt;
$options = array(&amp;#039;level&amp;#039; =&amp;gt; &amp;#039;1&amp;#039;, &amp;#039;ulClass&amp;#039; =&amp;gt; &amp;#039;sf-menu&amp;#039;, &amp;#039;liClass&amp;#039; =&amp;gt; &amp;#039;&amp;#039;);&lt;br /&gt;
echo &amp;quot;&amp;lt;div&amp;gt;&amp;quot;.renderNavTreeType($pa, $maxDepth = 1, $fieldNames = &amp;#039;&amp;#039;, $options).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel 2 (älter)&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Checkbox anlegen (footer_nav), und dann das Seitenarray etwa so modifizieren.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$footer_nav = $pages-&amp;gt;find(&amp;quot;parent=1, footer_checkbox=1&amp;quot;);&lt;br /&gt;
$main_nav = $pages-&amp;gt;find(&amp;quot;parent=1, footer_checkbox!=1&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zweispaltige Navigation aus Kindseiten ===&lt;br /&gt;
Verbesserungsvorschlag: Anstatt if lieber zwei for Schleifen -&amp;gt; bessere Performance&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Childrens&lt;br /&gt;
$n = count($page-&amp;gt;children);&lt;br /&gt;
$m = ceil($n/2);&lt;br /&gt;
$c = 0;&lt;br /&gt;
&lt;br /&gt;
// NAVIGATION &amp;amp; SLIDER Items&lt;br /&gt;
$listItem = &amp;#039;&amp;#039;;&lt;br /&gt;
$navList = &amp;#039;&amp;#039;;&lt;br /&gt;
$col1 = &amp;#039;&amp;lt;ul class=&amp;quot;nav-list col1&amp;quot;&amp;gt;&amp;#039;;&lt;br /&gt;
$col2 = &amp;#039;&amp;lt;ul class=&amp;quot;nav-list col2&amp;quot;&amp;gt;&amp;#039;;&lt;br /&gt;
foreach ($page-&amp;gt;children as $item) {&lt;br /&gt;
	if($item-&amp;gt;id == $page-&amp;gt;rootParent-&amp;gt;id) {&lt;br /&gt;
		$listItem = &amp;#039;&amp;lt;li class=&amp;quot;current&amp;quot;&amp;gt;&amp;#039;;&lt;br /&gt;
	} else {&lt;br /&gt;
		$listItem = &amp;#039;&amp;lt;li&amp;gt;&amp;#039;;&lt;br /&gt;
	}&lt;br /&gt;
	$listItem .= &amp;#039;&amp;lt;a class=&amp;quot;ajax-link&amp;quot; href=&amp;quot;&amp;#039;.$item-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;#039;;&lt;br /&gt;
	($c &amp;lt; $m) ? $col1 .= $listItem : $col2 .= $listItem;&lt;br /&gt;
	$c++;&lt;br /&gt;
}&lt;br /&gt;
$col1 .= &amp;#039;&amp;lt;/ul&amp;gt;&amp;#039;;&lt;br /&gt;
$col1 .= &amp;#039;&amp;lt;/ul&amp;gt;&amp;#039;;&lt;br /&gt;
$navList = $col1.$col2;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pushy Menu ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Given a group of pages, render a &amp;lt;ul&amp;gt; navigation tree&lt;br /&gt;
 *&lt;br /&gt;
 * This is here to demonstrate an example of a more intermediate level&lt;br /&gt;
 * shared function and usage is completely optional. This is very similar to&lt;br /&gt;
 * the renderNav() function above except that it can output more than one&lt;br /&gt;
 * level of navigation (recursively) and can include other fields in the output.&lt;br /&gt;
 * Assumes there is a field navigation_type to decide how a list item is&lt;br /&gt;
 * rendered&lt;br /&gt;
 *&lt;br /&gt;
 * @param array|PageArray $items&lt;br /&gt;
 * @param int $maxDepth How many levels of navigation below current should it go?&lt;br /&gt;
 * @param string $fieldNames Any extra field names to display (separate multiple fields with a space)&lt;br /&gt;
 * @param array $options extra options for classes configuration etc.&lt;br /&gt;
 * @return string&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
function renderPushyMenu($items, $maxDepth = 0, $fieldNames = &amp;#039;&amp;#039;, $options = array(&amp;#039;level&amp;#039; =&amp;gt; 0, &amp;#039;ulClass&amp;#039; =&amp;gt; &amp;#039;&amp;#039;, &amp;#039;liClass&amp;#039; =&amp;gt; &amp;#039;&amp;#039;, &amp;#039;aClass&amp;#039; =&amp;gt; &amp;#039;&amp;#039;) ) {&lt;br /&gt;
&lt;br /&gt;
	// if we were given a single Page rather than a group of them, we&amp;#039;ll pretend they&lt;br /&gt;
	// gave us a group of them (a group/array of 1)&lt;br /&gt;
	if($items instanceof Page) $items = array($items);&lt;br /&gt;
	$out = &amp;#039;&amp;#039;;&lt;br /&gt;
  $c = 0;&lt;br /&gt;
  $liClasses = array();&lt;br /&gt;
  $ulClasses = array();&lt;br /&gt;
	$level = 0;&lt;br /&gt;
	$liClass = &amp;#039;&amp;#039;;&lt;br /&gt;
	$ulClass = &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	if(!empty($options[&amp;#039;level&amp;#039;])) $level = $options[&amp;#039;level&amp;#039;];&lt;br /&gt;
	if(!empty($options[&amp;#039;ulClass&amp;#039;])) {&lt;br /&gt;
		$ulClasses[] = $options[&amp;#039;ulClass&amp;#039;];&lt;br /&gt;
		$ulClass = $options[&amp;#039;ulClass&amp;#039;];&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if(!empty($options[&amp;#039;liClass&amp;#039;])) {&lt;br /&gt;
		$liClasses[] = $options[&amp;#039;liClass&amp;#039;];&lt;br /&gt;
		$liClass = $options[&amp;#039;liClass&amp;#039;];&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// cycle through all the items&lt;br /&gt;
	foreach($items as $item) {&lt;br /&gt;
    //$level = count($page-&amp;gt;parents);&lt;br /&gt;
		// LI ITEM&lt;br /&gt;
		$classes = $liClasses;&lt;br /&gt;
    //if($item-&amp;gt;id == wire(&amp;#039;page&amp;#039;)-&amp;gt;id) $classes[] = &amp;#039;cur&amp;#039;;&lt;br /&gt;
		if($item-&amp;gt;hasChildren) {&lt;br /&gt;
      // BUTTON instead of Link&lt;br /&gt;
      $out .= &amp;#039;&amp;lt;li class=&amp;quot;pushy-submenu&amp;quot;&amp;gt;&amp;lt;button&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/button&amp;gt;&amp;#039;;&lt;br /&gt;
		}else{&lt;br /&gt;
      $classes[] = &amp;#039;level-&amp;#039;.$level;&lt;br /&gt;
  		$out .= &amp;#039;&amp;lt;li class=&amp;quot;&amp;#039;.implode($classes,&amp;#039; &amp;#039;).&amp;#039;&amp;quot;&amp;gt;&amp;#039;;&lt;br /&gt;
      unset($classes);&lt;br /&gt;
&lt;br /&gt;
  		// A ITEM&lt;br /&gt;
  		$navigation_type = $item-&amp;gt;navigation_type-&amp;gt;id;&lt;br /&gt;
  		$classes = $liClasses;&lt;br /&gt;
  		switch ( $navigation_type ) {&lt;br /&gt;
  			case 2: // do not link&lt;br /&gt;
  				$out .= &amp;#039;&amp;lt;span class=&amp;quot;spacer&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/span&amp;gt;&amp;#039;;&lt;br /&gt;
  				break;&lt;br /&gt;
  			case 3: // link to subpage&lt;br /&gt;
  				if( $item-&amp;gt;hasChildren() ){&lt;br /&gt;
  					$out .= &amp;#039;&amp;lt;a href=&amp;quot;&amp;#039;.$item-&amp;gt;child-&amp;gt;url.&amp;#039;&amp;quot; class=&amp;quot;ajax-link&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/a&amp;gt;&amp;#039;;&lt;br /&gt;
  				}else{&lt;br /&gt;
  					$out .= &amp;quot;&amp;lt;span class=&amp;#039;spacer&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
  				}&lt;br /&gt;
  				break;&lt;br /&gt;
  			default:&lt;br /&gt;
  				$out .= &amp;#039;&amp;lt;a href=&amp;quot;&amp;#039;.$item-&amp;gt;url.&amp;#039;&amp;quot; class=&amp;quot;ajax-link&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/a&amp;gt;&amp;#039;;&lt;br /&gt;
  				break;&lt;br /&gt;
  		}&lt;br /&gt;
  		unset($classes);&lt;br /&gt;
		}&lt;br /&gt;
		// if there are extra field names specified, render markup for each one in a &amp;lt;div&amp;gt;&lt;br /&gt;
		// having a class name the same as the field name&lt;br /&gt;
		if($fieldNames) foreach(explode(&amp;#039; &amp;#039;, $fieldNames) as $fieldName) {&lt;br /&gt;
			$value = $item-&amp;gt;get($fieldName);&lt;br /&gt;
			if($value) $out .= &amp;quot; &amp;lt;div class=&amp;#039;$fieldName&amp;#039;&amp;gt;$value&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if the item has children and we&amp;#039;re allowed to output tree navigation (maxDepth)&lt;br /&gt;
		// then call this same function again for the item&amp;#039;s children&lt;br /&gt;
		if($item-&amp;gt;hasChildren() &amp;amp;&amp;amp; $maxDepth) {&lt;br /&gt;
			//if($class == &amp;#039;nav&amp;#039;) $class = &amp;#039;nav nav-tree&amp;#039;;&lt;br /&gt;
			$nextLevelOptions = array(&amp;#039;level&amp;#039; =&amp;gt; $level+1, &amp;#039;ulClass&amp;#039; =&amp;gt; &amp;#039;&amp;#039;, &amp;#039;liClass&amp;#039; =&amp;gt; $liClass);&lt;br /&gt;
			$out .= renderNavTreeType($item-&amp;gt;children, $maxDepth-1, $fieldNames, $nextLevelOptions);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// close the list item&lt;br /&gt;
		$out .= &amp;quot;&amp;lt;/li&amp;gt;\n&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// if output was generated above, wrap it in a &amp;lt;ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	if($out) $out = &amp;quot;\n&amp;quot;.&amp;#039;&amp;lt;ul class=&amp;quot;&amp;#039;.implode($ulClasses,&amp;#039; &amp;#039;).&amp;#039;&amp;quot;&amp;gt;&amp;#039;.&amp;quot;\n&amp;quot;.$out.&amp;#039;&amp;lt;/ul&amp;gt;&amp;#039;.&amp;quot;\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	// return the markup we generated above&lt;br /&gt;
	return $out;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Do not link / link to subpage ==&lt;br /&gt;
=== MarkupSimpleNavigation XTemplate + Redirect Beispiel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
https://github.com/s...default-options&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Menü Platzhalter&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;xtemplate&amp;quot; =&amp;gt; &amp;quot;folder|placeholder&amp;quot;, // specify one or more templates&lt;br /&gt;
&amp;quot;xitem_tpl&amp;quot; =&amp;gt; &amp;quot;&amp;lt;span&amp;gt;{title}&amp;lt;/span&amp;gt;&amp;quot;, // default markup for page with this template&lt;br /&gt;
&amp;quot;xitem_current_tpl&amp;quot; =&amp;gt; &amp;quot;&amp;lt;span&amp;gt;{title}&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
echo $nav-&amp;gt;render(array(&lt;br /&gt;
   &amp;#039;max_levels&amp;#039;=&amp;gt;2,&lt;br /&gt;
   &amp;#039;selector&amp;#039;=&amp;gt;&amp;quot;limit=10&amp;quot;,&lt;br /&gt;
   &amp;#039;xtemplates&amp;#039; =&amp;gt; &amp;#039;placeholder|folder&amp;#039;&lt;br /&gt;
));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Redirect Template&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
You could also have a template &amp;quot;redirect&amp;quot; with only a title and a page field (single page) to select any page you want to go.&lt;br /&gt;
&lt;br /&gt;
Then in the code you should be able to write&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&amp;#039;item_tpl&amp;#039; =&amp;gt; &amp;#039;&amp;lt;a href=&amp;quot;{redirect_page|url}&amp;quot;&amp;gt;{title}&amp;lt;/a&amp;gt;&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So it would take the url of the referenced page in the page field if found, or if not it takes the url of the page itself. Assuming the page field is named &amp;quot;redirect_page&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== In der Navi ===&lt;br /&gt;
Zusätzliches Feld (Options) im Backend mit Namen navigation_type&lt;br /&gt;
&lt;br /&gt;
Beispiel&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Given a group of pages, render a &amp;lt;ul&amp;gt; navigation tree&lt;br /&gt;
 * If there is a field navigation_type the vals have following meaning&lt;br /&gt;
 * 1 = Normal&lt;br /&gt;
 * 2 = Do not link&lt;br /&gt;
 * 3 = Link to subpage&lt;br /&gt;
 *&lt;br /&gt;
 * @param array|PageArray $items&lt;br /&gt;
 * @param int $maxDepth How many levels of navigation below current should it go?&lt;br /&gt;
 * @param string $fieldNames Any extra field names to display (separate multiple fields with a space)&lt;br /&gt;
 * @param string $class CSS class name for containing &amp;lt;ul&amp;gt;&lt;br /&gt;
 * @return string&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
function renderNavTreeType($items, $maxDepth = 0, $fieldNames = &amp;#039;&amp;#039;, $options = array(&amp;#039;level&amp;#039; =&amp;gt; 0, &amp;#039;ulClass&amp;#039; =&amp;gt; &amp;#039;nav&amp;#039;, &amp;#039;liClass&amp;#039; =&amp;gt; &amp;#039;&amp;#039;, &amp;#039;aClass&amp;#039; =&amp;gt; &amp;#039;&amp;#039;) ) {&lt;br /&gt;
&lt;br /&gt;
	// if we were given a single Page rather than a group of them, we&amp;#039;ll pretend they&lt;br /&gt;
	// gave us a group of them (a group/array of 1)&lt;br /&gt;
	if($items instanceof Page) $items = array($items);&lt;br /&gt;
&lt;br /&gt;
	// $out is where we store the markup we are creating in this function&lt;br /&gt;
	$out = &amp;#039;&amp;#039;;&lt;br /&gt;
  $c = 0;&lt;br /&gt;
  $liClasses = array();&lt;br /&gt;
  $ulClasses = array();&lt;br /&gt;
	$level = 0;&lt;br /&gt;
	$liClass = &amp;#039;&amp;#039;;&lt;br /&gt;
	$ulClass = &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	if(!empty($options[&amp;#039;level&amp;#039;])) $level = $options[&amp;#039;level&amp;#039;];&lt;br /&gt;
	if(!empty($options[&amp;#039;ulClass&amp;#039;])) {&lt;br /&gt;
		$ulClasses[] = $options[&amp;#039;ulClass&amp;#039;];&lt;br /&gt;
		$ulClass = $options[&amp;#039;ulClass&amp;#039;];&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if(!empty($options[&amp;#039;liClass&amp;#039;])) {&lt;br /&gt;
		$liClasses[] = $options[&amp;#039;liClass&amp;#039;];&lt;br /&gt;
		$liClass = $options[&amp;#039;liClass&amp;#039;];&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// cycle through all the items&lt;br /&gt;
	foreach($items as $item) {&lt;br /&gt;
    //$level = count($page-&amp;gt;parents);&lt;br /&gt;
		// LI ITEM&lt;br /&gt;
		$classes = $liClasses;&lt;br /&gt;
    if($item-&amp;gt;id == wire(&amp;#039;page&amp;#039;)-&amp;gt;id) $classes[] = &amp;#039;cur&amp;#039;;&lt;br /&gt;
		if($item-&amp;gt;hasChildren) $classes[] = &amp;#039;has_children&amp;#039;;&lt;br /&gt;
    $classes[] = &amp;#039;level-&amp;#039;.$level;&lt;br /&gt;
		$out .= &amp;#039;&amp;lt;li class=&amp;quot;&amp;#039;.implode($classes,&amp;#039; &amp;#039;).&amp;#039;&amp;quot;&amp;gt;&amp;#039;;&lt;br /&gt;
    unset($classes);&lt;br /&gt;
&lt;br /&gt;
		// markup for the link&lt;br /&gt;
		$navigation_type = $item-&amp;gt;navigation_type-&amp;gt;id;&lt;br /&gt;
		$classes = $liClasses;&lt;br /&gt;
		switch ( $navigation_type ) {&lt;br /&gt;
			case 2: // do not link&lt;br /&gt;
				$out .= &amp;#039;&amp;lt;span class=&amp;quot;spacer&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/span&amp;gt;&amp;#039;;&lt;br /&gt;
				break;&lt;br /&gt;
			case 3: // link to subpage&lt;br /&gt;
				if( $item-&amp;gt;hasChildren() ){&lt;br /&gt;
					$out .= &amp;#039;&amp;lt;a href=&amp;quot;&amp;#039;.$item-&amp;gt;child-&amp;gt;url.&amp;#039;&amp;quot; class=&amp;quot;ajax-link&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/a&amp;gt;&amp;#039;;&lt;br /&gt;
				}else{&lt;br /&gt;
					$out .= &amp;quot;&amp;lt;span class=&amp;#039;spacer&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
				}&lt;br /&gt;
				break;&lt;br /&gt;
			default:&lt;br /&gt;
				$out .= &amp;#039;&amp;lt;a href=&amp;quot;&amp;#039;.$item-&amp;gt;url.&amp;#039;&amp;quot; class=&amp;quot;ajax-link&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/a&amp;gt;&amp;#039;;&lt;br /&gt;
				break;&lt;br /&gt;
		}&lt;br /&gt;
		unset($classes);&lt;br /&gt;
		// if there are extra field names specified, render markup for each one in a &amp;lt;div&amp;gt;&lt;br /&gt;
		// having a class name the same as the field name&lt;br /&gt;
		if($fieldNames) foreach(explode(&amp;#039; &amp;#039;, $fieldNames) as $fieldName) {&lt;br /&gt;
			$value = $item-&amp;gt;get($fieldName);&lt;br /&gt;
			if($value) $out .= &amp;quot; &amp;lt;div class=&amp;#039;$fieldName&amp;#039;&amp;gt;$value&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if the item has children and we&amp;#039;re allowed to output tree navigation (maxDepth)&lt;br /&gt;
		// then call this same function again for the item&amp;#039;s children&lt;br /&gt;
		if($item-&amp;gt;hasChildren() &amp;amp;&amp;amp; $maxDepth) {&lt;br /&gt;
			//if($class == &amp;#039;nav&amp;#039;) $class = &amp;#039;nav nav-tree&amp;#039;;&lt;br /&gt;
			$nextLevelOptions = array(&amp;#039;level&amp;#039; =&amp;gt; $level+1, &amp;#039;ulClass&amp;#039; =&amp;gt; &amp;#039;&amp;#039;, &amp;#039;liClass&amp;#039; =&amp;gt; $liClass);&lt;br /&gt;
			$out .= renderNavTreeType($item-&amp;gt;children, $maxDepth-1, $fieldNames, $nextLevelOptions);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// close the list item&lt;br /&gt;
		$out .= &amp;quot;&amp;lt;/li&amp;gt;\n&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// if output was generated above, wrap it in a &amp;lt;ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	if($out) $out = &amp;quot;\n&amp;quot;.&amp;#039;&amp;lt;ul class=&amp;quot;&amp;#039;.implode($ulClasses,&amp;#039; &amp;#039;).&amp;#039;&amp;quot;&amp;gt;&amp;#039;.&amp;quot;\n&amp;quot;.$out.&amp;#039;&amp;lt;/ul&amp;gt;&amp;#039;.&amp;quot;\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	// return the markup we generated above&lt;br /&gt;
	return $out;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Redirect über das Template ===&lt;br /&gt;
Sinnvoll wenn die URL direkt aufgerufen wird:&lt;br /&gt;
&lt;br /&gt;
 $session-&amp;gt;redirect($page-&amp;gt;redirect_page-&amp;gt;url);&lt;br /&gt;
or how about &amp;quot;redirect-to-firstchild&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
 $session-&amp;gt;redirect($page-&amp;gt;children-&amp;gt;first()-&amp;gt;url);&lt;br /&gt;
&lt;br /&gt;
== Beispiele für Funktionen (z.B. in _func.php)==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiele für Funktionen die Navigationen erzeugen. &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
=== One Level ===&lt;br /&gt;
==== Original ProcessWire Demo Beispiel ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Nested List ausgehend von einer Seite (meistens Homepage) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Given a group of pages, render a ONE LEVEL NAVBAR&lt;br /&gt;
  *&lt;br /&gt;
  * @param array|PageArray $items&lt;br /&gt;
  * @return string&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 function renderNavMain($pa,$pageId){&lt;br /&gt;
   if($pa instanceof Page) $pa = array($pa);&lt;br /&gt;
   $out = &amp;#039;&amp;lt;nav class=&amp;quot;menu menu--ferdinand&amp;quot;&amp;gt;&amp;lt;ul class=&amp;quot;nav navbar-nav menu__list&amp;quot;&amp;gt;&amp;#039;;&lt;br /&gt;
   foreach($pa as $item) {&lt;br /&gt;
     if($item-&amp;gt;id == $pageId) {&lt;br /&gt;
       $out .= &amp;quot;&amp;lt;li class=\&amp;quot;menu__item menu__item--current cur\&amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
     } else {&lt;br /&gt;
       $out .= &amp;quot;&amp;lt;li class=\&amp;quot;menu__item\&amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
     }&lt;br /&gt;
     // if template isotope-parent add first isotope-child name as hash&lt;br /&gt;
     if($item-&amp;gt;template-&amp;gt;name == &amp;#039;isotope-parent&amp;#039;){&lt;br /&gt;
       $out .= &amp;#039;&amp;lt;a class=&amp;quot;menu__link&amp;quot; href=&amp;quot;&amp;#039;.$item-&amp;gt;url.&amp;#039;#&amp;#039;.$item-&amp;gt;child-&amp;gt;name.&amp;#039;&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;#039;;&lt;br /&gt;
     }else $out .= &amp;#039;&amp;lt;a class=&amp;quot;menu__link&amp;quot; href=&amp;quot;&amp;#039;.$item-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;#039;;&lt;br /&gt;
   }&lt;br /&gt;
     $out .= &amp;quot;&amp;lt;/ul&amp;gt;&amp;lt;/nav&amp;gt;&amp;quot;;&lt;br /&gt;
     return $out;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Given a group of pages render a standard ISOTOP MARKUP&lt;br /&gt;
  *&lt;br /&gt;
  * @param array|PageArray $items&lt;br /&gt;
  * @return string&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 function renderNavIsotope($pa){&lt;br /&gt;
   if($pa instanceof Page) $pa = array($pa);&lt;br /&gt;
   $out = &amp;#039;&amp;lt;ul class=&amp;quot;submenu&amp;quot;&amp;gt;&amp;#039;;&lt;br /&gt;
   foreach($pa as $item){&lt;br /&gt;
     $out .= &amp;#039;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#&amp;#039;.$item-&amp;gt;name.&amp;#039;&amp;quot; class=&amp;quot;isotope-link&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;#039;;&lt;br /&gt;
   }&lt;br /&gt;
   $out .= &amp;quot;&amp;lt;/ul&amp;gt;&amp;quot;;&lt;br /&gt;
   return $out;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Given a group of pages, render a simple &amp;lt;ul&amp;gt; navigation&lt;br /&gt;
 *&lt;br /&gt;
 * This is here to demonstrate an example of a simple shared function.&lt;br /&gt;
 * Usage is completely optional.&lt;br /&gt;
 *&lt;br /&gt;
 * @param PageArray $items&lt;br /&gt;
 * @return string&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
function renderNav(PageArray $items) {&lt;br /&gt;
&lt;br /&gt;
	// $out is where we store the markup we are creating in this function&lt;br /&gt;
	$out = &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	// cycle through all the items&lt;br /&gt;
	foreach($items as $item) {&lt;br /&gt;
&lt;br /&gt;
		// render markup for each navigation item as an &amp;lt;li&amp;gt;&lt;br /&gt;
		if($item-&amp;gt;id == wire(&amp;#039;page&amp;#039;)-&amp;gt;id) {&lt;br /&gt;
			// if current item is the same as the page being viewed, add a &amp;quot;current&amp;quot; class to it&lt;br /&gt;
			$out .= &amp;quot;&amp;lt;li class=&amp;#039;current&amp;#039;&amp;gt;&amp;quot;;&lt;br /&gt;
		} else {&lt;br /&gt;
			// otherwise just a regular list item&lt;br /&gt;
			$out .= &amp;quot;&amp;lt;li&amp;gt;&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// markup for the link&lt;br /&gt;
		$out .= &amp;quot;&amp;lt;a href=&amp;#039;$item-&amp;gt;url&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/a&amp;gt; &amp;quot;;&lt;br /&gt;
&lt;br /&gt;
		// if the item has summary text, include that too&lt;br /&gt;
		if($item-&amp;gt;summary) $out .= &amp;quot;&amp;lt;div class=&amp;#039;summary&amp;#039;&amp;gt;$item-&amp;gt;summary&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
		// close the list item&lt;br /&gt;
		$out .= &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// if output was generated above, wrap it in a &amp;lt;ul&amp;gt;&lt;br /&gt;
	if($out) $out = &amp;quot;&amp;lt;ul class=&amp;#039;nav&amp;#039;&amp;gt;$out&amp;lt;/ul&amp;gt;\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	// return the markup we generated above&lt;br /&gt;
	return $out;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Given a group of pages, render a &amp;lt;ul&amp;gt; navigation tree&lt;br /&gt;
 *&lt;br /&gt;
 * This is here to demonstrate an example of a more intermediate level&lt;br /&gt;
 * shared function and usage is completely optional. This is very similar to&lt;br /&gt;
 * the renderNav() function above except that it can output more than one&lt;br /&gt;
 * level of navigation (recursively) and can include other fields in the output.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array|PageArray $items&lt;br /&gt;
 * @param int $maxDepth How many levels of navigation below current should it go?&lt;br /&gt;
 * @param string $fieldNames Any extra field names to display (separate multiple fields with a space)&lt;br /&gt;
 * @param string $class CSS class name for containing &amp;lt;ul&amp;gt;&lt;br /&gt;
 * @return string&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
function renderNavTree($items, $maxDepth = 0, $fieldNames = &amp;#039;&amp;#039;, $class = &amp;#039;nav&amp;#039;) {&lt;br /&gt;
&lt;br /&gt;
	// if we were given a single Page rather than a group of them, we&amp;#039;ll pretend they&lt;br /&gt;
	// gave us a group of them (a group/array of 1)&lt;br /&gt;
	if($items instanceof Page) $items = array($items);&lt;br /&gt;
&lt;br /&gt;
	// $out is where we store the markup we are creating in this function&lt;br /&gt;
	$out = &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	// cycle through all the items&lt;br /&gt;
	foreach($items as $item) {&lt;br /&gt;
&lt;br /&gt;
		// markup for the list item...&lt;br /&gt;
		// if current item is the same as the page being viewed, add a &amp;quot;current&amp;quot; class to it&lt;br /&gt;
		$out .= $item-&amp;gt;id == wire(&amp;#039;page&amp;#039;)-&amp;gt;id ? &amp;quot;&amp;lt;li class=&amp;#039;current&amp;#039;&amp;gt;&amp;quot; : &amp;quot;&amp;lt;li&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
		// markup for the link&lt;br /&gt;
		$out .= &amp;quot;&amp;lt;a href=&amp;#039;$item-&amp;gt;url&amp;#039;&amp;gt;$item-&amp;gt;title&amp;lt;/a&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
		// if there are extra field names specified, render markup for each one in a &amp;lt;div&amp;gt;&lt;br /&gt;
		// having a class name the same as the field name&lt;br /&gt;
		if($fieldNames) foreach(explode(&amp;#039; &amp;#039;, $fieldNames) as $fieldName) {&lt;br /&gt;
			$value = $item-&amp;gt;get($fieldName);&lt;br /&gt;
			if($value) $out .= &amp;quot; &amp;lt;div class=&amp;#039;$fieldName&amp;#039;&amp;gt;$value&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// if the item has children and we&amp;#039;re allowed to output tree navigation (maxDepth)&lt;br /&gt;
		// then call this same function again for the item&amp;#039;s children&lt;br /&gt;
		if($item-&amp;gt;hasChildren() &amp;amp;&amp;amp; $maxDepth) {&lt;br /&gt;
			if($class == &amp;#039;nav&amp;#039;) $class = &amp;#039;nav nav-tree&amp;#039;;&lt;br /&gt;
			$out .= renderNavTree($item-&amp;gt;children, $maxDepth-1, $fieldNames, $class);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// close the list item&lt;br /&gt;
		$out .= &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// if output was generated above, wrap it in a &amp;lt;ul&amp;gt;&lt;br /&gt;
	if($out) $out = &amp;quot;&amp;lt;ul class=&amp;#039;$class&amp;#039;&amp;gt;$out&amp;lt;/ul&amp;gt;\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	// return the markup we generated above&lt;br /&gt;
	return $out;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Komplette Beispiele ==&lt;br /&gt;
[[ProcessWire - Navigation Beispiele]]&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Navigation_Beispiele&amp;diff=24836</id>
		<title>ProcessWire - Navigation Beispiele</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Navigation_Beispiele&amp;diff=24836"/>
		<updated>2020-10-28T07:48:09Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Siehe auch ==&lt;br /&gt;
 [[ProcessWire - Navigation Snippets]]&lt;br /&gt;
 http://wiki.zone30.info/wikizone/index.php?title=Aligator_(ProcessWire)#Komplettes_Beispiel_1&lt;br /&gt;
&lt;br /&gt;
== MarkupSimpleNavigation Modul Navigation ==&lt;br /&gt;
Hinweis: Oft tun&amp;#039;s auch kleine Navigationssnippets anstatt der Module.&lt;br /&gt;
=== Multilevel Navigation mit diversen Klassen ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
$prependHomepage = 0;&lt;br /&gt;
foreach($homepage-&amp;gt;menus as $item) {&lt;br /&gt;
  if($item-&amp;gt;id == 1) $prependHomepage = 1;&lt;br /&gt;
}&lt;br /&gt;
if($prependHomepage) {&lt;br /&gt;
	$pa = $homepage-&amp;gt;and($homepage-&amp;gt;children(&amp;quot;menus.id=1&amp;quot;)); &lt;br /&gt;
}else $pa = $homepage-&amp;gt;children(&amp;quot;menus.id=1&amp;quot;);&lt;br /&gt;
// additional MarkupSimpleNavigation Filter&lt;br /&gt;
$selector = &amp;#039;menus.id=1&amp;#039;; // filter works only for first level because markup simple navigation renders children by itself. This is why we need extra selector&lt;br /&gt;
&lt;br /&gt;
$outer_tpl = &amp;#039;&amp;lt;ul class=&amp;quot; ul-nav&amp;quot;&amp;gt;||&amp;lt;/ul&amp;gt;&amp;#039;;&lt;br /&gt;
$inner_tpl = &amp;#039;&amp;lt;ul&amp;gt;||&amp;lt;/ul&amp;gt;&amp;#039;;&lt;br /&gt;
$list_tpl = &amp;#039;&amp;lt;li%s&amp;gt;||&amp;lt;/li&amp;gt;&amp;#039;;//%s is where classes form parent_class etc. goes&lt;br /&gt;
$item_tpl = &amp;#039;&amp;lt;a href=&amp;quot;{url}&amp;quot; class=&amp;quot;nav-link&amp;quot;&amp;gt;{headline|title}&amp;lt;/a&amp;gt;&amp;#039;;&lt;br /&gt;
$item_current_tpl =&amp;#039;&amp;lt;a href=&amp;quot;{url}&amp;quot; class=&amp;quot;current nav-link&amp;quot;&amp;gt;{headline|title}&amp;lt;/a&amp;gt;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
$myMenu = $modules-&amp;gt;get(&amp;quot;MarkupSimpleNavigation&amp;quot;); // load the module&lt;br /&gt;
$options = array(&lt;br /&gt;
    &amp;#039;parent_class&amp;#039; =&amp;gt; &amp;#039;parent&amp;#039;,	// goes in li classes&lt;br /&gt;
    &amp;#039;current_class&amp;#039; =&amp;gt; &amp;#039;current&amp;#039;, // goes in li classes&lt;br /&gt;
    &amp;#039;has_children_class&amp;#039; =&amp;gt; &amp;#039;has_children&amp;#039;, // goes in li classes&lt;br /&gt;
    &amp;#039;levels&amp;#039; =&amp;gt; true,&lt;br /&gt;
    &amp;#039;levels_prefix&amp;#039; =&amp;gt; &amp;#039;l-&amp;#039;,//goes in li classes&lt;br /&gt;
    &amp;#039;max_levels&amp;#039; =&amp;gt; 4,&lt;br /&gt;
    &amp;#039;firstlast&amp;#039; =&amp;gt; true,&lt;br /&gt;
    &amp;#039;collapsed&amp;#039; =&amp;gt; false,&lt;br /&gt;
    &amp;#039;show_root&amp;#039; =&amp;gt; false,&lt;br /&gt;
    &amp;#039;outer_tpl&amp;#039; =&amp;gt; $outer_tpl, // usually the ul part&lt;br /&gt;
    &amp;#039;inner_tpl&amp;#039; =&amp;gt; $inner_tpl, // usually inner ul tags&lt;br /&gt;
    &amp;#039;list_tpl&amp;#039; =&amp;gt; $list_tpl,&lt;br /&gt;
    &amp;#039;list_field_class&amp;#039; =&amp;gt; &amp;#039;&amp;#039;,&lt;br /&gt;
    &amp;#039;item_tpl&amp;#039; =&amp;gt; $item_tpl,&lt;br /&gt;
    &amp;#039;item_current_tpl&amp;#039; =&amp;gt; $item_current_tpl,&lt;br /&gt;
    &amp;#039;xtemplates&amp;#039; =&amp;gt; &amp;#039;&amp;#039;,&lt;br /&gt;
    &amp;#039;selector&amp;#039; =&amp;gt; $selector,&lt;br /&gt;
    &amp;#039;date_format&amp;#039; =&amp;gt; &amp;#039;d.m.Y&amp;#039;,&lt;br /&gt;
    &amp;#039;code_formatting&amp;#039; =&amp;gt; false,&lt;br /&gt;
    &amp;#039;debug&amp;#039; =&amp;gt; false&lt;br /&gt;
);&lt;br /&gt;
$out = &amp;#039;&lt;br /&gt;
&amp;lt;nav&amp;gt;&lt;br /&gt;
&amp;#039;.$myMenu-&amp;gt;render($options,null,$pa).&amp;#039;&lt;br /&gt;
&amp;lt;/nav&amp;gt;&lt;br /&gt;
&amp;#039;;&lt;br /&gt;
echo $out;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sidebar Navigation für MaterializeCSS ===&lt;br /&gt;
Beispiel orig. aus prantner.de. Nutzt ein Selectfeld um im Backen zu bestimmen ob eine Seite aufgeführt wird. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
$pages-&amp;gt;get(1001)-&amp;gt;my_selector = &amp;quot;template=projects&amp;quot;;&lt;br /&gt;
$pa = $homepage-&amp;gt;and($homepage-&amp;gt;children(&amp;quot;menus.id=1&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
$outer_tpl = &amp;#039;&amp;lt;ul id=&amp;quot;slide-out&amp;quot; class=&amp;quot;sidenav&amp;quot;&amp;gt;||&amp;lt;/ul&amp;gt;&amp;#039;;&lt;br /&gt;
//if($configpage-&amp;gt;nav_type-&amp;gt;value == 1) $outer_tpl = &amp;#039;&amp;lt;ul id=&amp;quot;slide-out&amp;quot; class=&amp;quot;sidenav sidenav-fixed&amp;quot;&amp;gt;||&amp;lt;/ul&amp;gt;&amp;#039;;&lt;br /&gt;
$sideMenu = $modules-&amp;gt;get(&amp;quot;MarkupSimpleNavigation&amp;quot;); // load the module&lt;br /&gt;
$options = array(&lt;br /&gt;
    &amp;#039;parent_class&amp;#039; =&amp;gt; &amp;#039;parent&amp;#039;,&lt;br /&gt;
    &amp;#039;current_class&amp;#039; =&amp;gt; &amp;#039;current&amp;#039;,&lt;br /&gt;
    &amp;#039;has_children_class&amp;#039; =&amp;gt; &amp;#039;has_children&amp;#039;,&lt;br /&gt;
    &amp;#039;levels&amp;#039; =&amp;gt; true,&lt;br /&gt;
    &amp;#039;levels_prefix&amp;#039; =&amp;gt; &amp;#039;l-&amp;#039;,&lt;br /&gt;
    &amp;#039;max_levels&amp;#039; =&amp;gt; 4,&lt;br /&gt;
    &amp;#039;firstlast&amp;#039; =&amp;gt; true,&lt;br /&gt;
    &amp;#039;collapsed&amp;#039; =&amp;gt; false,&lt;br /&gt;
    &amp;#039;show_root&amp;#039; =&amp;gt; false,&lt;br /&gt;
    &amp;#039;selector&amp;#039; =&amp;gt; &amp;#039;&amp;#039;,&lt;br /&gt;
    &amp;#039;selector_field&amp;#039; =&amp;gt; &amp;#039;nav_selector&amp;#039;,&lt;br /&gt;
    &amp;#039;outer_tpl&amp;#039; =&amp;gt; $outer_tpl,&lt;br /&gt;
    &amp;#039;inner_tpl&amp;#039; =&amp;gt; &amp;#039;&amp;lt;ul&amp;gt;||&amp;lt;/ul&amp;gt;&amp;#039;,&lt;br /&gt;
    &amp;#039;list_tpl&amp;#039; =&amp;gt; &amp;#039;&amp;lt;li%s&amp;gt;||&amp;lt;/li&amp;gt;&amp;#039;,&lt;br /&gt;
    &amp;#039;list_field_class&amp;#039; =&amp;gt; &amp;#039;&amp;#039;,&lt;br /&gt;
    &amp;#039;item_tpl&amp;#039; =&amp;gt; &amp;#039;&amp;lt;a href=&amp;quot;{url}&amp;quot;&amp;gt;{title}&amp;lt;/a&amp;gt;&amp;#039;,&lt;br /&gt;
    &amp;#039;item_current_tpl&amp;#039; =&amp;gt; &amp;#039;&amp;lt;a class=&amp;quot;cur&amp;quot; href=&amp;quot;{url}&amp;quot;&amp;gt;{title}&amp;lt;/a&amp;gt;&amp;#039;,&lt;br /&gt;
    &amp;#039;xtemplates&amp;#039; =&amp;gt; &amp;#039;&amp;#039;,&lt;br /&gt;
    &amp;#039;xitem_tpl&amp;#039; =&amp;gt; &amp;#039;&amp;lt;a href=&amp;quot;{url}&amp;quot;&amp;gt;{title}&amp;lt;/a&amp;gt;&amp;#039;,&lt;br /&gt;
    &amp;#039;xitem_current_tpl&amp;#039; =&amp;gt; &amp;#039;&amp;lt;span class=&amp;quot;cur&amp;quot;&amp;gt;{title}&amp;lt;/span&amp;gt;&amp;#039;,&lt;br /&gt;
    &amp;#039;date_format&amp;#039; =&amp;gt; &amp;#039;d.m.Y&amp;#039;,&lt;br /&gt;
    &amp;#039;code_formatting&amp;#039; =&amp;gt; false,&lt;br /&gt;
    &amp;#039;debug&amp;#039; =&amp;gt; false&lt;br /&gt;
);&lt;br /&gt;
$out = $sideMenu-&amp;gt;render($options,null,$pa);&lt;br /&gt;
&lt;br /&gt;
$out .= &amp;#039;&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; data-target=&amp;quot;slide-out&amp;quot; class=&amp;quot;sidenav-trigger&amp;quot; style=&amp;quot;margin-left:0;&amp;quot;&amp;gt;&amp;lt;i class=&amp;quot;material-icons&amp;quot;&amp;gt;menu&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&amp;#039;;&lt;br /&gt;
echo $out;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Previous Next Navigation mit Auswahlfeld im Backend ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Main Template&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;!-- footer --&amp;gt;&lt;br /&gt;
	&amp;lt;?php include(&amp;quot;partials/nav/nav-page.inc&amp;quot;); ?&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;nav-page.inc&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Page Prev Next Navigation&lt;br /&gt;
 */&lt;br /&gt;
$next = &amp;#039;&amp;#039;;&lt;br /&gt;
$prev = &amp;#039;&amp;#039;;&lt;br /&gt;
$navPageMarkup = &amp;#039;&amp;#039;;&lt;br /&gt;
if($page-&amp;gt;show_prev_next){&lt;br /&gt;
	if($page-&amp;gt;next-&amp;gt;id){&lt;br /&gt;
		$next = &amp;#039;&lt;br /&gt;
				&amp;lt;span class=&amp;quot;page-title next table-cell&amp;quot;&amp;gt;&lt;br /&gt;
					&amp;lt;a href=&amp;quot;&amp;#039;.$page-&amp;gt;next-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&lt;br /&gt;
						&amp;#039;.$page-&amp;gt;next-&amp;gt;title.&amp;#039;&lt;br /&gt;
					&amp;lt;/a&amp;gt;&lt;br /&gt;
				&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
				&amp;lt;span class=&amp;quot;nav-icon next table-cell&amp;quot;&amp;gt;&lt;br /&gt;
					&amp;amp;nbsp;&lt;br /&gt;
					&amp;lt;a href=&amp;quot;&amp;#039;.$page-&amp;gt;next-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&lt;br /&gt;
						&amp;lt;i class=&amp;quot;fa fa-chevron-right&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&lt;br /&gt;
					&amp;lt;/a&amp;gt;&lt;br /&gt;
				&amp;lt;/span&amp;gt;&lt;br /&gt;
			&amp;lt;/span&amp;gt;&lt;br /&gt;
		&amp;#039;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if($page-&amp;gt;prev-&amp;gt;id){&lt;br /&gt;
		$prev = &amp;#039;&lt;br /&gt;
				&amp;lt;span class=&amp;quot;nav-icon prev table-cell&amp;quot;&amp;gt;&lt;br /&gt;
					&amp;lt;a href=&amp;quot;&amp;#039;.$page-&amp;gt;prev-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&lt;br /&gt;
						&amp;lt;i class=&amp;quot;fa fa-chevron-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&lt;br /&gt;
					&amp;lt;/a&amp;gt;&lt;br /&gt;
					&amp;amp;nbsp;&lt;br /&gt;
				&amp;lt;/span&amp;gt;&lt;br /&gt;
				&amp;lt;span class=&amp;quot;page-title prev table-cell&amp;quot;&amp;gt;&lt;br /&gt;
					&amp;lt;a href=&amp;quot;&amp;#039;.$page-&amp;gt;prev-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&lt;br /&gt;
						&amp;#039;.$page-&amp;gt;prev-&amp;gt;title.&amp;#039;&lt;br /&gt;
					&amp;lt;/a&amp;gt;&lt;br /&gt;
				&amp;lt;/span&amp;gt;&lt;br /&gt;
		&amp;#039;;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	$navPageMarkup = &amp;#039;&lt;br /&gt;
	&amp;lt;div class=&amp;quot;section v2 nav-page hide-on-small-only&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;div class=&amp;quot;row container no-margin-bot&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;div class=&amp;quot;col s12 nav-page&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;div class=&amp;quot;page-nav-wrap table&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&lt;br /&gt;
					&amp;lt;div class=&amp;quot;table-row&amp;quot;&amp;gt;&lt;br /&gt;
						&amp;#039;.$prev.$next.&amp;#039;&lt;br /&gt;
					&amp;lt;/div&amp;gt;&lt;br /&gt;
					&amp;lt;!--&amp;lt;div class=&amp;quot;clearfix&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;--&amp;gt;&lt;br /&gt;
				&amp;lt;/div&amp;gt;&lt;br /&gt;
			&amp;lt;/div&amp;gt;&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
	&amp;lt;/div&amp;gt;&lt;br /&gt;
	&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
echo $navPageMarkup;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Megamenu ==&lt;br /&gt;
Ab 3.0.119 gibt es eine neue Funktion WireArray-&amp;gt;slice mit der man geschickt mehrspaltige Ausgaben realisieren kann.&lt;br /&gt;
 https://processwire.com/blog/posts/processwire-3.0.119-and-new-site-updates/#new-wirearray-slices-method&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$categories = $pages-&amp;gt;get(&amp;#039;/about/sites/categories/&amp;#039;)-&amp;gt;children();&lt;br /&gt;
foreach($categories-&amp;gt;slices(3) as $items) {&lt;br /&gt;
  echo &amp;quot;&amp;lt;div class=&amp;#039;uk-width-1-3&amp;#039;&amp;gt;&amp;lt;ul&amp;gt;&amp;quot;;&lt;br /&gt;
  echo $items-&amp;gt;each(&amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;{url}&amp;#039;&amp;gt;{title}&amp;lt;/a&amp;gt;&amp;quot;);&lt;br /&gt;
  echo &amp;quot;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Selectors&amp;diff=24824</id>
		<title>ProcessWire - Selectors</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Selectors&amp;diff=24824"/>
		<updated>2020-10-18T11:21:54Z</updated>

		<summary type="html">&lt;p&gt;84.155.186.35: /* Beispiele */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Operatoren ==&lt;br /&gt;
 http://cheatsheet.processwire.com/selectors/selector-operators/&lt;br /&gt;
Selector Operators&lt;br /&gt;
&lt;br /&gt;
    =&lt;br /&gt;
    Equal to (any_field=any_value)&lt;br /&gt;
&lt;br /&gt;
    !=&lt;br /&gt;
    Not equal to (any_field!=any_value)&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;&lt;br /&gt;
    Less than (any_field&lt;br /&gt;
&lt;br /&gt;
    &amp;gt;&lt;br /&gt;
    Greater than any_field&amp;gt;any_value&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;=&lt;br /&gt;
    Less than or equal to (any_field&amp;lt;=any_value)&lt;br /&gt;
&lt;br /&gt;
    &amp;gt;=&lt;br /&gt;
    Greater than or equal to (any_field&amp;gt;=any_value)&lt;br /&gt;
&lt;br /&gt;
    *=&lt;br /&gt;
    Contains the exact word or phrase (any_field*=any_value)&lt;br /&gt;
&lt;br /&gt;
    ~=&lt;br /&gt;
    Contains all the words (any_field~=any_value)&lt;br /&gt;
&lt;br /&gt;
    %=&lt;br /&gt;
    Contains the exact word or phrase (using slower SQL LIKE) [v2.1] (any_field%=any_value)&lt;br /&gt;
&lt;br /&gt;
    ^=&lt;br /&gt;
    Contains the exact word or phrase at the beginning of the field [v2.1] (any_field^=any_value)&lt;br /&gt;
&lt;br /&gt;
    $=&lt;br /&gt;
    Contains the exact word or phrase at the end of the field [v2.1] (any_field$=any_value)&lt;br /&gt;
&lt;br /&gt;
=== Neue Operatoren ab 3.0.160 ===&lt;br /&gt;
List of new operators available as of ProcessWire 3.0.160&lt;br /&gt;
&lt;br /&gt;
Here&amp;#039;s a list of new operators available as of 3.0.160, along with brief explanation of what each operator does and how it differs from other similar operators.&lt;br /&gt;
&lt;br /&gt;
    Contains words partial (~*=)&lt;br /&gt;
    Like existing match words (~=) operator, except that this one matches partial words as well.&lt;br /&gt;
&lt;br /&gt;
    Contains words live (~~=)&lt;br /&gt;
    Like match words, except that the last word in the query is treated as a partial match.&lt;br /&gt;
&lt;br /&gt;
    Contains words like (~%=)&lt;br /&gt;
    Matches all words in the query, in full or in part.&lt;br /&gt;
&lt;br /&gt;
    Contains words and expand (~+=)&lt;br /&gt;
    Like match words operator, but with the added power of the query expansion feature supported by MySQL fulltext indexes.&lt;br /&gt;
&lt;br /&gt;
    Contains any words (~|=)&lt;br /&gt;
    One or more of the words must match; this is similar to splitting the query with pipe (|) characters, but often easier to use, and better optimized.&lt;br /&gt;
&lt;br /&gt;
    Contains any partial words (~|*=)&lt;br /&gt;
    Similar to the previous operator, except that this one also provides partial matches.&lt;br /&gt;
&lt;br /&gt;
    Contains any words like (~|%=)&lt;br /&gt;
    Similar to the previous two operators, but uses LIKE query behind the scenes instead of the fulltext index.&lt;br /&gt;
&lt;br /&gt;
    Contains phrase and expand (*+=)&lt;br /&gt;
    Variation of the phrase match operator (*=) with added query expansion support.&lt;br /&gt;
&lt;br /&gt;
    Contains match (**=)&lt;br /&gt;
    This operator works much like the MATCH/AGAINST feature of MySQL fulltext indexes.&lt;br /&gt;
&lt;br /&gt;
    Contains match and expand (**+=)&lt;br /&gt;
    Otherwise identical to previous operator, except for the added query expansion.&lt;br /&gt;
&lt;br /&gt;
    Advanced text search (#=)&lt;br /&gt;
    This operator adds support for special characters, such as &amp;quot;+&amp;quot; for &amp;quot;must match&amp;quot;, &amp;quot;-&amp;quot; for &amp;quot;must not match&amp;quot;, and &amp;quot;*&amp;quot; for specifying partial matches.&lt;br /&gt;
&lt;br /&gt;
== Owner Attribut ==&lt;br /&gt;
Nützlich bei Pagereferences, wenn auf die Seite verweisende Seiten gefunden und gleichzeitig gefiltert werden sollen.&lt;br /&gt;
 https://processwire.com/blog/posts/processwire-3.0.95-core-updates/&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$members = $pages-&amp;gt;find(&amp;quot;template=member, age&amp;gt;50&amp;quot;);&lt;br /&gt;
foreach($members as $m) {&lt;br /&gt;
  $items = $m-&amp;gt;memberships-&amp;gt;find(&amp;quot;club=&amp;#039;Golf Club X&amp;#039;, mtype=GOLD&amp;quot;);&lt;br /&gt;
  foreach($items as $membership) {&lt;br /&gt;
     // add to excel or other export, etc.&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Ineffektiv bei vielen Datensätzen -&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$items = $pages-&amp;gt;find(&amp;quot;club=&amp;#039;Golf Club X&amp;#039;, mtype=GOLD, memberships.owner.age&amp;gt;50&amp;quot;);&lt;br /&gt;
foreach($items as $membership) {&lt;br /&gt;
  // add to excel or other export, etc.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Sortiere Seiten nach Reihenfolge im Seitenbaum ===&lt;br /&gt;
Das funktioniert mit der Sortierung &amp;quot;sort&amp;quot;.&lt;br /&gt;
 $categories = pages(&amp;#039;template=template_name,sort=sort&amp;#039;);&lt;br /&gt;
=== Große Datenmenge mit findMany() durchsuchen ===&lt;br /&gt;
 [[findMany() - ProcessWire API]]&lt;br /&gt;
&lt;br /&gt;
=== Suche nach Seiten die Verweise auf bestimmte andere Seiten enthalten ===&lt;br /&gt;
https://processwire.com/talk/topic/5414-selector-find-page-reference-help/&lt;br /&gt;
&lt;br /&gt;
Es sollen Seiten gefunden werden die mit einer Page Reference auf eine andere Seite verweisen. Am einfachsten geht das wenn man nicht wie man zuerst vermutet nach der Seiten ID sucht, sondern wenn man direkt nach der Seite sucht&lt;br /&gt;
 team_name=$page&lt;br /&gt;
&lt;br /&gt;
=== Suche nach Phrasen in Daten die in Seitenverweise enthalten sind ===&lt;br /&gt;
https://processwire.com/talk/topic/570-searching-page-reference-fields/&lt;br /&gt;
&lt;br /&gt;
Es sollen Seiten gefunden werden, die Verweise auf andere Seiten enthalten. Beispielsweise enthalten Personen (Eltern) Links zu Notfalladressen die separat angelegt sind. Nun soll Nach Eltern gesucht werden, die eine bestimmte Notfalladresse enthalten. Gesucht wird nach einer Phrase im Notfalladrdessen Namen).&lt;br /&gt;
&lt;br /&gt;
Lösung: Es wird in zwei Schritten gesucht. &lt;br /&gt;
&lt;br /&gt;
1. Suche nach Kontakten mit dem Search Term im body und die dem template emergency-contact entsprechen&lt;br /&gt;
 $contacts = $pages-&amp;gt;find(&amp;quot;body*=&amp;#039;search term&amp;#039;, template=emergency-contact&amp;quot;); &lt;br /&gt;
2. Seiten die diesen Kontakten entsprechen&lt;br /&gt;
 $parents = $pages-&amp;gt;find(&amp;quot;emergency-contacts=$contacts&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== Selektoren in Option Fieldtypes ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$optionsfield // return id (string)&lt;br /&gt;
$optionsfield-&amp;gt;id; // return id (int)&lt;br /&gt;
$optionsfield-&amp;gt;title; // return string USE THIS or&lt;br /&gt;
$optionsfield-&amp;gt;value; // return empty string or value (if your option settings like &amp;#039;1=value|title&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// dot syntax in selector string&lt;br /&gt;
$pages-&amp;gt;find(&amp;#039;optionsfield.id=2&amp;#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Seiten finden ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$skyscrapers = $pages-&amp;gt;find(&amp;quot;template=skyscraper, sort=-modified&amp;quot;);&lt;br /&gt;
foreach($skyscrapers as $skyscraper) {&lt;br /&gt;
    echo &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;$skyscraper-&amp;gt;url&amp;#039;&amp;gt;$skyscraper-&amp;gt;title&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Page Reference auf diese Seite ===&lt;br /&gt;
https://processwire.com/talk/topic/1071-page-fieldtype-two-way-relation/&lt;br /&gt;
 echo $pages-&amp;gt;find(&amp;quot;field1=$page&amp;quot;)-&amp;gt;render();&lt;br /&gt;
If the page isn&amp;#039;t part of the front-end site, then I&amp;#039;ll remove view access from its template. Or if it is part of the front-end, but I don&amp;#039;t want to show the relations, then this:&lt;br /&gt;
&lt;br /&gt;
 if($page-&amp;gt;editable()) echo $pages-&amp;gt;find(&amp;quot;field1=$page&amp;quot;)-&amp;gt;render();&lt;br /&gt;
 &lt;br /&gt;
Though I almost always integrate these relation-revealing pages into the site structure, as it&amp;#039;s rare that this information doesn&amp;#039;t have some value to the site&amp;#039;s users too. This is an example of one that locates all pages referencing it in a field called &amp;#039;country&amp;#039;:&lt;br /&gt;
 https://www.tripsite.com/countries/croatia/&lt;br /&gt;
&lt;br /&gt;
=== Suche in PageReference Feldern ===&lt;br /&gt;
 https://processwire.com/talk/topic/1224-selector-and-page-reference-field/&lt;br /&gt;
Finde Felder mit&lt;br /&gt;
* Template = POI&lt;br /&gt;
* poi_type.type = &amp;quot;zoo&amp;quot; (PageReference)&lt;br /&gt;
Der Filter&lt;br /&gt;
 $poi = $pages-&amp;gt;find(template=poi, poi_type.title=&amp;#039;Zoo&amp;#039;); &lt;br /&gt;
Funktioniert nicht.&lt;br /&gt;
&lt;br /&gt;
Stattdessen &lt;br /&gt;
- holt man zuerst alle Seiten mit dem Titel Zoo und&lt;br /&gt;
- nimmt diese Menge als Filter für eine Suche im PageReference Feld (poi_type)&lt;br /&gt;
&lt;br /&gt;
 $pr = $pages-&amp;gt;get(&amp;quot;title=Zoo&amp;quot;);&lt;br /&gt;
 $poi = $pages-&amp;gt;find(&amp;quot;template=poi, poi_type=$pr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== Punkt Syntax ===&lt;br /&gt;
 $architects = $pages-&amp;gt;find(&amp;quot;template=architect, city.title=Chicago&amp;quot;); &lt;br /&gt;
 $buildings = $pages-&amp;gt;find(&amp;quot;architect=$architects&amp;quot;); &lt;br /&gt;
That&amp;#039;s easy enough, but wouldn&amp;#039;t it be nicer if you could just do this?&lt;br /&gt;
 $buildings = $pages-&amp;gt;find(&amp;quot;architect.city.title=Chicago&amp;quot;); &lt;br /&gt;
&lt;br /&gt;
 $buildings = $pages-&amp;gt;find(&amp;quot;architect.city.state.abbr=IL&amp;quot;); &lt;br /&gt;
Broadening further, perhaps we want buildings from all architects in the USA:&lt;br /&gt;
&lt;br /&gt;
 $buildings = $pages-&amp;gt;find(&amp;quot;architect.city.state.country.abbr=USA&amp;quot;);&lt;br /&gt;
Or perhaps both USA and Canada:&lt;br /&gt;
&lt;br /&gt;
 $buildings = $pages-&amp;gt;find(&amp;quot;architect.city.state.country.abbr=USA|CA&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== User ===&lt;br /&gt;
 http://cheatsheet.processwire.com/users/users-methods/users-find-selector/&lt;br /&gt;
Find all users whose email address ENDS with processwire.com and create a link to email them&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$items = $users-&amp;gt;find(&amp;quot;email$=processwire.com&amp;quot;);&lt;br /&gt;
foreach($items as $item) {&lt;br /&gt;
    echo &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;mailto:{$item-&amp;gt;email}&amp;#039;&amp;gt;{$item-&amp;gt;name}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Find all users who have &amp;quot;fred&amp;quot; anywhere in their name&lt;br /&gt;
&lt;br /&gt;
 $items = $users-&amp;gt;find(&amp;quot;name*=fred&amp;quot;);&lt;br /&gt;
Find all users who have the &amp;quot;superuser&amp;quot; role&lt;br /&gt;
&lt;br /&gt;
 $items = $users-&amp;gt;find(&amp;quot;roles=superuser&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
== Array Selectors ==&lt;br /&gt;
https://processwire.com/blog/posts/processwire-3.0.13-selector-upgrades-and-new-form-builder-version/#building-a-selector-string-with-user-input-example&lt;br /&gt;
&lt;br /&gt;
=== Selektoren als assoziative Arrays ===&lt;br /&gt;
&lt;br /&gt;
Anstatt von Selector Strings kann man seit PW 3.0.13 auch Arrays nutzen.:d of a string:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$results = $pages-&amp;gt;find([&lt;br /&gt;
  &amp;#039;template&amp;#039; =&amp;gt; [&amp;#039;basic-page&amp;#039;, &amp;#039;product&amp;#039;],&lt;br /&gt;
  &amp;#039;title|body%=&amp;#039; =&amp;gt; $sanitizer-&amp;gt;text($input-&amp;gt;get(&amp;#039;q&amp;#039;)),&lt;br /&gt;
  &amp;#039;categories&amp;#039; =&amp;gt; $sanitizer-&amp;gt;intArray($input-&amp;gt;get(&amp;#039;categories&amp;#039;)),&lt;br /&gt;
  &amp;#039;sort&amp;#039; =&amp;gt; &amp;#039;-created&amp;#039;&lt;br /&gt;
]); &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Erläuterung:&lt;br /&gt;
&lt;br /&gt;
Die &amp;#039;&amp;#039;$sanitizer-&amp;gt;selectorValue()&amp;#039;&amp;#039; Methode um Text zu sanitizen der in Selektoren geht ist nicht mehr notwendig. Du solltest immer noch User Input sanitizen, aber man kann sich die sanierung für die Selektoren sparen.&lt;br /&gt;
Werte können Arrays sein. Im Beispiel werden Arrays für &amp;#039;template&amp;#039; and &amp;#039;categories&amp;#039; items genutzt. &lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;=&amp;quot; Operator wird für alle Selektoren Elemente angenommen, solange man nicht einen anderen Operator anhängt. Wie bei &amp;#039;&amp;#039;&amp;#039;title|body%=&amp;#039;&amp;#039;&amp;#039; zu sehen.&lt;br /&gt;
&lt;br /&gt;
=== Selektoren als reguläre Arrays ===&lt;br /&gt;
Man kann auch ein reguläres (nicht assoziatives Array nutzen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$results = $pages-&amp;gt;find([&lt;br /&gt;
  [&amp;#039;template&amp;#039;, [&amp;#039;basic-page&amp;#039;, &amp;#039;product&amp;#039;]],&lt;br /&gt;
  [&amp;#039;title|body&amp;#039;, &amp;#039;%=&amp;#039;, $input-&amp;gt;get(&amp;#039;q&amp;#039;), &amp;#039;text&amp;#039;],&lt;br /&gt;
  [&amp;#039;categories&amp;#039;, &amp;#039;=&amp;#039;, $input-&amp;gt;get(&amp;#039;categories&amp;#039;), &amp;#039;int&amp;#039;],&lt;br /&gt;
  [&amp;#039;sort&amp;#039;, &amp;#039;-created&amp;#039;]&lt;br /&gt;
]); &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hier werden die Selektorenteile als Array im Array übergeben. Das Format ist folgendes:f those arrays can use any of the following formats:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    [field, value]&lt;br /&gt;
    [field, operator, value]&lt;br /&gt;
    [field, operator, value, sanitizer]&lt;br /&gt;
    [field, operator, value, whitelist]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    The field element can be specified as a single field name, pipe &amp;quot;|&amp;quot; separated field names, or an array of field name(s).&lt;br /&gt;
&lt;br /&gt;
    The operator can be any operator. If none is specified, then equals &amp;quot;=&amp;quot; is assumed (which you can do if only specifying a field and value).&lt;br /&gt;
&lt;br /&gt;
    The value can be a string, number or array of either.&lt;br /&gt;
&lt;br /&gt;
    The sanitizer can be any $sanitizer method name that you want the value to pass through before being used in the selector.&lt;br /&gt;
&lt;br /&gt;
    When a whitelist (array) is specified for the sanitizer, the selector will throw an Exception if the given value (or values) are not present in the whitelist array.&lt;br /&gt;
&lt;br /&gt;
Beide Array Formate (assoziativ, regulär) kann man theoretisch sogar mischen.&lt;/div&gt;</summary>
		<author><name>84.155.186.35</name></author>
	</entry>
</feed>