Das ist ein voller Markt, und „baut Post-Types“ ist keine Neuigkeit. Seltener gestellt wird die Frage, was ein solches Plugin die Website bei jedem Request kostet — und die Antwort ergibt sich aus zwei Entscheidungen zur Speicherung, bei denen der übliche Reflex in beiden Fällen falsch liegt.
Die erste: Feldwerte gehen als gewöhnliche Meta nach postmeta, nicht in eine eigene Tabelle. Eine eigene Tabelle sieht im Benchmark besser aus und ist in der Praxis nutzlos — WP_Query sieht sie nicht, orderby => meta_value_num kann nicht danach sortieren, die REST-API zeigt sie nicht, und kein anderes Plugin weiß, dass es dort nachsehen müsste. Und die Form zählt so viel wie die Tabelle: Eine Galerie, die als ein serialisiertes Array in einer Zeile liegt, ist für jeden SQL-Vergleich für immer unsichtbar. Hier bekommt jeder Wert eine eigene Zeile unter einem Schlüssel — eine Zeile mehr je Eintrag, dafür überhaupt abfragbar.
Die zweite: Definitionen gehen in eine JSON-Datei, nicht in eine autoload-Option — und ausdrücklich nicht, weil „Dateien schneller sind als die Datenbank“, was die README selbst als falsch bezeichnet. Eine autoload-Option kostet keine zusätzliche Abfrage; sie kommt in derselben alloptions-Abfrage mit, die WordPress ohnehin macht, und bei einem kleinen Wert gewinnt die Option. Der Grund ist, was passiert, wenn der Wert nicht mehr klein ist: Eine Website mit dreißig Feldgruppen entpackt hundert Kilobyte bei jedem Request — Loginseite, admin-ajax, REST, Cron — auch bei der überwältigenden Mehrheit, die nie ein Feld ansieht. Eine Kopie bleibt mit abgeschaltetem autoload in der Datenbank, damit ein schreibgeschütztes Dateisystem etwas Geschwindigkeit kostet und nicht sämtliche Post-Types der Website.
Die stärkste Aussage hier ist die Folge genau dieser Entscheidung. Die Datei liegt im uploads-Verzeichnis, also kontrolliert sie alles, was dort schreiben kann — ein anderes Plugin, eine Upload-Lücke an anderer Stelle, ein geliehener FTP-Zugang. Ihr Inhalt gilt deshalb als genauso unvertrauenswürdig wie ein abgeschicktes Formular: gelesen mit json_decode und nie mit include oder unserialize, und jeder Wert läuft durch dieselbe Bereinigung wie ein abgeschickter. Ohne das könnte ein Label <img src=x onerror=…> lauten, und WordPress gibt name_admin_bar unescaped aus — Skriptausführung auf jeder Adminseite. Es gibt Obergrenzen für die Zahl der Einträge, für die Listen darin und für das Produkt aus Post-Types und Feldern, denn die Dateigröße zu begrenzen begrenzt nichts davon: Eine 14-KB-Datei kann zwanzigtausend register_post_meta-Aufrufe auf init erzeugen. Über der Grenze wird das Speichern verweigert statt stillschweigend gekürzt.
Die kostenlose Stufe verweigert außerdem Namen, die die Website beschädigen, und sagt, was passiert wäre: die Namen von WordPress selbst, Query-Variablen wie author und name, und alles über zwanzig Zeichen, weil die Spalte zwanzig Zeichen hat und ein längerer Name dort stillschweigend gekürzt wird, in PHP aber vollständig bleibt. Die Pro-Stufe baut aus denselben Werten JSON-LD und gibt bei einer unvollständigen Zuordnung nichts aus, sondern warnt; und sie exportiert eine eigenständige PHP-Datei für ein Child-Theme, nach der man das Plugin deaktivieren kann und Post-Types, Meta-Schlüssel und Inhalte genau dort bleiben, wo sie waren.
Für wen es gedacht ist
Websites, die wirklich eigene Post-Types brauchen · Kataloge und Listen, die nach einem Feld sortieren und filtern müssen · Content-Websites, die strukturierte Daten ohne SEO-Plugin wollen · Entwicklerinnen, die nicht bei jedem Request hundert Kilobyte autoloaden möchten · Designerinnen, die eine Website mit einem Plugin bauen und es danach entfernen wollen · Agenturen, die eine Website übergeben und die Datenstruktur nicht als Geisel zurücklassen möchten · alle, die einmal einen Post-Type namens author angelegt haben.