Sprache

Kontakt aufnehmen

WordPress-Plugin · seit 2020

TableOn

Zeigt WordPress-Beiträge und Custom Post Types als sortier- und filterbare Tabellen, aufgebaut aus einem Spalten-Konstruktor.

Erstveröffentlichung
Aktive Installationen
200+
Bewertung
4.6 / 5 (15)Rezensionen lesen
  • PHP
  • WordPress
  • WP_Query
  • MySQL (custom tables, dbDelta)
  • JavaScript (ES6 classes)
  • Fetch API
  • AbortController
  • AlaSQL
  • WPML

Über mich

TableOn rendert Beiträge jedes Post Types als Tabelle. Der Admin baut Tabellen aus vordefinierten Spalten (Titel, Vorschaubild, Autor, Datumsangaben, Kommentaranzahl, Taxonomien, Galerie) und aus Post-Meta-Feldern, fügt ein Filterformular, vordefinierte Teilmengen und Skins hinzu und platziert das Ergebnis per Shortcode, in einem Popup oder per iframe innerhalb einer anderen Website.

Technisch besteht es aus zwei Teilen. Auf dem Server verwandelt ein öffentlicher Ajax-Endpunkt eine Tabellendefinition und einen Filterzustand in eine WP_Query und liefert Zeilen als JSON. Im Browser blättert, sortiert und durchsucht eine abhängigkeitsfreie Tabellenklasse, entweder über Ajax oder über bereits geladene Daten, und wechselt auf schmalen Bildschirmen in ein kompaktes Layout.

Die schwierigen Teile sind, eine konfigurierbare Tabellendefinition in eine WP_Query für jeden Post Type zu verwandeln, Meta-Felder zu typisieren, die WordPress als Strings speichert, und mehrere Tabellen mit unterschiedlichen Skins und Sprachen auf einer Seite unabhängig zu halten.

TableOn · Beitragstabelle

was gelöst wurde

LIVEseit 2020

Spaltenprofile und der Abfrage-Endpunkt

shipped · 2020

Was es bringtMitarbeiter entscheiden, welche Spalten eine Tabelle zeigt und welche Beiträge sie enthält, und jede Spalte lässt sich auf dieselbe Weise sortieren und filtern.

Problem
Ein Ajax-Endpunkt liefert die Zeilen für jede Tabelle: jeder Post Type, vom Admin definierte Meta-Spalten, Filter, vordefinierte Teilmengen und Sortierungen. Dasselbe Feld muss eine Zelle rendern, die Abfrage sortieren und als Filter dienen.
Lösung

Eine Tabelle wird durch ein Profil beschrieben: ein Array von Feldschlüsseln, jeweils mit Closures für den Zellwert, die Abfrageargumente und die Daten des Filter-Widgets. Angeforderte Spalten werden in diesem Profil über den Schlüssel nachgeschlagen.

Stack
  • PHP
  • closures
  • WP_Query
  • WordPress filters
Aufgaben · 5
Eine Felddefinition muss Zelle, Sortierung und Filter steuernAngeforderte Felder indizieren nur das Profil; jeder Schlüssel bringt seine eigenen Closures mit

TABLEON_Default::action() liefert das Profil: für jeden Schlüssel einen Titel, eine 'action'-Closure, die die Zelle rendert, und für filterbare Schlüssel get_filter_query_args und get_filter_draw_data. get_table_data() geht die angeforderten Felder durch und ruft $profile[$field]['action'] nur auf, wenn der Schlüssel existiert, sodass ein unbekannter Feldname ignoriert wird. Jede Zeile trägt außerdem pid, das die Zellaktionen im Frontend verwenden.

Vom Admin definierte Meta-Felder brauchen typisiertes AbfrageverhaltenMeta-Zeilen vom Typ Text, Zahl oder Kalender; jeder Typ baut seine eigene meta_query

assemble_meta_for_system() macht aus einer Zeile der Meta-Tabelle einen Profileintrag. Text verwendet LIKE und ein Textfeld. Zahl verwendet BETWEEN mit dem Typ numeric aus einem Wert 'min:max', einen Bereichsregler und die Sortierung meta_value_num. Kalender vergleicht entweder als Unix-Zeitstempel (numerisch) oder als DATETIME, je Feld gewählt, weil Plugins wie ACF Datumsstrings speichern, andere dagegen Zeitstempel.

Manche Sortierungen lassen sich nicht als WP_Query-Argumente ausdrückenTemporäre posts_orderby-Closure für post_status, direkt nach der Abfrage entfernt

Die Sortierung nach post_status geschieht mit einer an posts_orderby gehängten Closure für die Dauer einer WP_Query und wird danach entfernt, sodass sie nicht in andere Abfragen auf der Seite durchsickert. Werte des Sortier-Dropdowns wie title-desc oder <meta_key>-desc werden auf orderby/order abgebildet, mit meta_value_num für als Zahl typisierte Meta-Felder.

Tabellen, die auf eine gewählte Teilmenge von Beiträgen beschränkt sindVordefinierte Regeln werden zu post__in, post__not_in, author__in und tax_query

Jede Tabelle kann Regeln speichern: Beitrags-IDs, ausgeschlossene IDs, Autoren, ein- oder auszuschließende Begriffe. get_table_data() wendet sie vor den Filtern des Besuchers an, wobei IDs in Ganzzahlen umgewandelt werden. Ein Shortcode-Attribut author=N wird in dieselben Regeln eingefaltet (Code-Kommentar vom 16-09-2020).

Die Tabellenkonfiguration passt schlecht in Post-MetaVier eigene Tabellen über dbDelta: Tabellen, Spalten, Meta-Felder, Vokabular

Spalten sind Zeilen mit table_id, field_key, pos_num, is_active, show_on_mobile und JSON-Optionen, indiziert auf table_id und is_active, sodass die aktiven Spalten einer Tabelle eine einzige indizierte Abfrage sind. Die gesamte Konfiguration wird als ein JSON-Dokument exportiert; der Import leert jede Tabelle und fügt Zeilen neu ein, hinter einer Rollenprüfung.

Filterformular über Beiträge und Meta

shipped · 2020

Was es bringtBesucher grenzen Tabellen nach Text, Kategorien, Zahlenbereichen und Datumsangaben ein. Die Regler-Grenzen folgen den tatsächlichen Daten, sodass Mitarbeiter sie nicht eingeben müssen.

Problem
Das Filterformular wird für jeden Post Type aus demselben Profil erzeugt: Textsuche, Taxonomiebäume, Zahlenbereiche und Datumsbereiche. Das Plugin hat keinen eigenen Index, daher müssen Grenzen und Optionen aus Live-Daten kommen.
Lösung

Jeder Filterschlüssel liefert Darstellungsdaten (Grenzen, Optionen, Beschriftungen) und einen Query-Builder. Numerische Grenzen kommen aus MIN/MAX-Abfragen, sofern der Admin sie nicht gesetzt hat. Bedingungen, die WP_Query nicht ausdrücken kann, laufen über posts_where: Textwerte werden escapt und vorbereitet, Datumsangaben mit date() formatiert und Zahlen mit intval() umgewandelt.

Stack
  • PHP
  • WP_Query
  • posts_where
  • MySQL
Aufgaben · 6
Textsuche über gewählte Spalten, ohne Beachtung der Groß-/Kleinschreibung, sicherposts_where mit LOWER(field) LIKE; Felder per Whitelist, Werte vorbereitet und esc_like

Die durchsuchbaren Spalten kommen aus dem Shortcode-Attribut tableon_text_search_by, werden aber auf post_title, post_content und post_excerpt gefiltert, sodass ein Spaltenname nie von außerhalb der Liste in SQL gelangt. Der Suchbegriff wird mit einem Multibyte-fähigen Helfer in Kleinbuchstaben umgewandelt, mit esc_like() escapt und mit $wpdb->prepare() gebunden.

Bereichsregler brauchen Grenzen, die der Admin nicht eingegeben hatStandardgrenzen sind MIN/MAX von CAST(meta_value AS UNSIGNED) für den Meta-Key

get_field_drawing_data() verwendet das gespeicherte Min/Max der Tabelle, wenn gesetzt; andernfalls fragt es wp_postmeta für den Schlüssel mit einem numerischen Cast ab, sodass als Text gespeicherte Zahlen als Zahlen verglichen werden. Die Grenzen der Kommentaranzahl sind MIN/MAX über wp_posts des Post Types der Tabelle.

Ein Datumsfeld braucht zwei Eingaben, von und bisEinen Zwillingsschlüssel mit dem Suffix ---to zeichnen; der Provider leitet ihn mit einem Richtungs-Flag weiter

draw_filter_form_data() dupliziert ein Kalenderfeld als <key>---to mit den Beschriftungen 'From:' und 'To:'. Der Schlüssel existiert nicht im Profil, daher erkennt provider() das Suffix, entfernt es und ruft den Query-Builder des ursprünglichen Felds mit is_calendar_dir_to = true auf, was >= zu <= umkehrt.

Taxonomie-Mehrfachauswahl braucht pro Tabelle IN, NOT IN oder ANDOperator pro Tabelle gespeichert, vor tax_query gegen eine Whitelist geprüft

Die Option mselect-logic wird aus den Filteroptionen der Tabelle gelesen und durch IN ersetzt, wenn sie nicht IN, NOT IN oder AND ist. Begriffs-IDs gehen per term_id in tax_query.

Hierarchische Begriffslisten mit Include- und Exclude-MengenRekursiver Baum pro Parent mit Tiefenpräfix, nach ID-Listen gefiltert

build_taxonomy_tree() geht die Begriffe Parent für Parent durch, überspringt ausgeschlossene IDs, behält nur eingeschlossene IDs, wenn diese Liste gesetzt ist, und stellt den Titeln pro Ebene einen Bindestrich voran, sodass ein flaches Select die Hierarchie zeigt. Es führt pro Parent einen get_terms()-Aufruf mit hide_empty aus.

Andere Filter-Plugins müssen dieselbe Tabelle steuern könnenDer Provider-Hook tableon_filter_provider_{name} schreibt die WP_Query-Argumente um

Der Request nennt einen Filter-Provider; get_table_data() reicht die Query-Argumente, Filterdaten und Shortcode-Argumente durch den passenden Filter. Das eingebaute Formular ist der Provider 'default'. Taxonomy Chain Menu nutzt die Clientseite davon, schreibt filter_data in die Tabelle und fordert sie zum Neuzeichnen auf.

Clientseitige Tabellen-Engine

shipped · 2020

Was es bringtBlättern, Sortieren und Suchen fühlen sich schnell an, weil bereits geladene Daten wiederverwendet werden, und breite Tabellen wechseln auf Telefonen in ein kompaktes Layout.

Problem
Tabellen laufen in Seiten, Popups und iframes und müssen blättern, sortieren und suchen, ohne bei jedem Klick auf den Server zu warten. Schnelles Klicken lässt Antworten in falscher Reihenfolge eintreffen, und breite Tabellen passen nicht auf Telefone.
Lösung

Eine abhängigkeitsfreie JavaScript-Klasse mit drei Datenmodi, einer SQL-Engine im Browser für geladene Zeilen, einem Cache pro Anfrage, Anfrageabbruch und einem kompakten Layout unterhalb einer konfigurierbaren Breite.

Stack
  • JavaScript (ES6 classes)
  • Fetch API
  • AbortController
  • AlaSQL
Aufgaben · 5
Eine langsame frühere Antwort darf eine neuere Seite nicht überschreibenAbortController bricht den vorherigen Fetch ab, bevor eine neue Anfrage startet

Jede Ajax-Anfrage speichert ihren AbortController; eine neue Anfrage bricht zuerst die ausstehende ab, sodass nur der jeweils neueste Zustand von Seite, Sortierung oder Filter gezeichnet wird.

Daten sortieren und blättern, die bereits im Browser sindDer Modus json führt AlaSQL SELECT, ORDER BY und LIMIT über die geladenen Zeilen aus

Im Modus json sind die Zeilen in die Seite eingebettet. Titelsuche, Zählung, ORDER BY und LIMIT/OFFSET werden als SQL-Strings gebaut und von AlaSQL über das Array im Speicher ausgeführt, sodass Blättern und Sortieren keine Anfragen brauchen.

Einmal per Ajax laden und dann keine Roundtrips mehr machenModus to_json: Die erste Ajax-Antwort wird zu lokalen Daten und der Modus wechselt zu json

to_json startet als ajax mit einem Umschalt-Flag. Nach der ersten Antwort werden die Zeilen als table_data behalten und der Modus wird json. Auf dem Server fordern die json-Modi alle passenden Beiträge an (posts_per_page = -1), was der Code als Speicherrisiko markiert, sodass der Modus für kleine und mittlere Mengen geeignet ist.

Wiederholte Anfragen für bereits gesehene SeitenAntworten unter einem 32-Bit-Hash des JSON-Request-Objekts zwischenspeichern

set_cache() und get_cache() schlüsseln Antworten über __hash_object(request_data), einen String-Hash über JSON.stringify des gesamten Requests (Seite, Sortierung, Filter). Das Zurückgehen auf eine bereits gesehene Seite wird aus dem Speicher bedient. Der Cache ist in den Modi json, to_json und load-more aus, in denen die Daten ohnehin lokal sind.

Breite Tabellen auf TelefonenKompakte Ansicht unterhalb einer festgelegten Breite, Ausblenden pro Spalte auf Mobilgeräten, gedrosseltes Resize

Unterhalb von compact_view_width werden Zeilen als gestapelte Zellen gezeichnet und Kopfzeilen ausgeblendet. Der Resize-Handler zeichnet nur neu, wenn sich der kompakte Zustand tatsächlich ändert, und sperrt sich zwischen den Läufen für 999 ms. Spalten können auf Mobilgeräten entfallen (hide_on_mobile) oder unterhalb einer Pixelbreite durch erzeugte @media-Regeln ausgeblendet werden. Zeilen werden in einem DocumentFragment gebaut und einmal eingefügt.

Einbettung, Isolation und Admin-Zugriff

im Produkt

Was es bringtMehrere unterschiedlich gestaltete Tabellen können sich eine Seite teilen, Tabellen können auf anderen Websites angezeigt werden, Beschriftungen folgen der Sprache der Site, und ausgewählte Mitarbeiterrollen können sie verwalten.

Problem
Mehrere Tabellen mit unterschiedlichen Skins können sich eine Seite teilen, eine Tabelle kann in eine andere Website eingebettet werden, Beschriftungen müssen der Sprache der Site folgen, und die Tabellenverwaltung ist nicht auf Administratoren beschränkt.
Lösung

CSS wird beim Rendern auf die HTML-ID jeder Tabelle beschränkt, die Einbettung auf fremden Sites läuft über ein erzeugtes Loader-Skript, Beschriftungen laufen über eine Übersetzungstabelle, und Admin-Bildschirme werden über eine Rolleneinstellung gesteuert.

Stack
  • PHP
  • CSS
  • JavaScript
  • iframe
Aufgaben · 5
Mehrere Tabellen mit unterschiedlichen Skins auf einer SeiteSkin-CSS verwendet einen Platzhalter 'tid', der durch die HTML-ID der Tabelle ersetzt und dann minifiziert wird

get_theme_css() lädt den Skin zuerst aus dem Ordner tableon-skins des Themes, dann aus dem Plugin, ersetzt tid durch die HTML-ID der Tabelle und entfernt Kommentare und Leerraum. Spaltenstile und das eigene CSS der Tabelle werden ebenfalls mit #<table id> präfixiert, sodass die Regeln einer Tabelle eine andere nicht berühren.

Eine Tabelle auf einer Site zeigen, die nicht WordPress istEin Loader-Skript baut ein Lazy-iframe auf eine Seite, die das leere Template des Plugins verwendet

Ein Request mit tableon-remote-page und anchor liefert JavaScript statt einer Seite: Einstellungen als Variablen plus remote.js, das im angegebenen Container ein Lazy-Load-iframe erzeugt. Die Seite darin verwendet ein leeres Template, das das Plugin registriert, sodass die Oberfläche des Themes nicht angezeigt wird.

Inline-JSON-Konfiguration darf nicht aus ihrem HTML-Container ausbrechenjson_encode mit JSON_HEX_TAG, JSON_HEX_QUOT und JSON_HEX_AMP in einem verborgenen div

Tabelleneinstellungen und, im Modus json, alle Zeilen werden in die Seite ausgegeben. Weil <, >, Anführungszeichen und & als Unicode-Escapes kodiert werden, können Beitragstitel oder Meta-Werte das Element nicht schließen oder Markup einschleusen.

Oberflächentexte in mehreren Sprachen ohne .po-DateienEine Vokabeltabelle bildet einen String auf Werte pro Sprache ab, einmal pro Request geladen

TABLEON_Vocabulary liest die ganze Tabelle einmal in ein statisches Array; get() liefert den Wert für die aktuelle Locale oder den Originalstring. Die aktuelle Sprache läuft durch den Filter tableon_current_lang, der auch WPML umschaltet, sodass Ajax-Requests in der Sprache des Besuchers gerendert werden.

Andere Redakteure als Administratoren verwalten Tabellencan_manage_data(): Admin oder Rollen aus den Einstellungen, plus ein Nonce bei jedem Speichern

Admin-Bildschirme werden nur für Nutzer registriert, die can_manage_data() bestehen, was Administratoren und die in der Einstellung user_roles_can aufgeführten Rollen akzeptiert. Die Handler zum Speichern, Erstellen und Löschen prüfen jeweils den Nonce 'tableon'.

Zahlen

wordpress.org
  • Aktive Installationen 200+ Zähler von wordpress.org.
  • Rezensionen 15 Durchschnitt 4.6 von 5.
  • Jahre Support 6 Seit 2. November 2020, letztes Update 12. Juni 2026.