From 552458a98c04d5851ddbc4bc7d81edbdc8c6bef5 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 7 Aug 2026 14:29:05 +0000 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20Gutenberg-Block=20=E2=80=9EDatensat?= =?UTF-8?q?z-Karte"=20(v2.38.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alternative zum Shortcode [odw_dataset id="123"]: Im Editor über das Plus-Symbol einfügen und den Datensatz aus einer Liste wählen, statt eine ID abzutippen. Der Shortcode bleibt unverändert nutzbar. Umsetzung: - Dynamischer Block. Gespeichert wird nur die Datensatz-ID, das Markup entsteht beim Ausliefern über ODW_Shortcode::render(). Genau eine Quelle für die Karte, und ein später umbenannter Datensatz erscheint mit aktuellem Titel statt als eingefrorene Kopie im Beitrag. - Kein Build-Schritt: block.json plus Editor-Skript in schlichtem JS statt JSX. Eine JS-Build-Kette allein für einen Block wäre viel Apparat für wenig Ertrag. - Auswahlliste über wp_localize_script statt über den Core-Datenspeicher. Der CPT ist bewusst show_in_rest => false — dafür gibt es die eigenen Endpunkte. Die Abfrage läuft nur im Editor (enqueue_block_editor_assets), begrenzt auf 200 Einträge. - Platzhalter statt Live-Vorschau: Eine serverseitig gerenderte Vorschau bekäme das Frontend-Stylesheet im Editor-Rahmen nicht mit. Der Platzhalter nutzt die Placeholder-Komponente von WordPress und braucht deshalb kein eigenes CSS — assets/css/admin.css lädt im Beitragseditor ohnehin nicht. - bin/build-release.sh kopiert blocks/ mit. Ohne diese Ergänzung wäre der Block in der Installation schlicht nicht vorhanden gewesen. i18n: 7 neue Zeichenketten, .mo neu kompiliert (634 Einträge). Verifiziert: PHP-Syntax, JS-Syntax, block.json, Build-Skript-Syntax, check-i18n.py bei 0, Katalog-Abdeckung beidseitig leer. Das Verhalten im Editor lässt sich nur in einer laufenden Instanz prüfen. https://claude.ai/code/session_01JB1xUQM892bVZ4Yv3MZjvq --- CHANGELOG.md | 30 +++++++ CLAUDE.md | 10 ++- README.md | 22 ++++- bin/build-release.sh | 4 +- blocks/dataset-card/block.json | 25 ++++++ blocks/dataset-card/editor.js | 124 +++++++++++++++++++++++++ includes/class-block.php | 135 ++++++++++++++++++++++++++++ languages/open-data-wizard-en_US.mo | Bin 66549 -> 67334 bytes languages/open-data-wizard-en_US.po | 21 +++++ languages/open-data-wizard.pot | 21 +++++ open-data-wizard.php | 6 +- 11 files changed, 388 insertions(+), 10 deletions(-) create mode 100644 blocks/dataset-card/block.json create mode 100644 blocks/dataset-card/editor.js create mode 100644 includes/class-block.php diff --git a/CHANGELOG.md b/CHANGELOG.md index c2d34d7..39c6ad7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,36 @@ und dieses Projekt folgt [Semantic Versioning](https://semver.org/spec/v2.0.0.ht --- +## [2.38.0] — 2026-08-07 + +Gutenberg-Block „Datensatz-Karte" — keine IDs mehr abtippen. + +### ✨ Added +- **Block „Datensatz-Karte"** als Alternative zum Shortcode `[odw_dataset id="123"]`. Im Editor + über das Plus-Symbol einfügen und den Datensatz aus einer Liste wählen; zur Auswahl stehen nur + veröffentlichte Datensätze. Wer den Shortcode bevorzugt oder klassische Editoren nutzt, kann + ihn unverändert weiterverwenden. + +### ℹ️ Umsetzung +- **Dynamischer Block:** Gespeichert wird ausschließlich die Datensatz-ID, das Markup entsteht + beim Ausliefern über `ODW_Shortcode::render()`. Damit gibt es genau eine Quelle für die Karte — + Änderungen daran wirken auf Block und Shortcode gleichermaßen —, und ein später umbenannter + Datensatz erscheint mit seinem aktuellen Titel statt als eingefrorene Kopie im Beitrag. +- **Kein Build-Schritt.** `blocks/dataset-card/` enthält `block.json` und ein Editor-Skript in + schlichtem JavaScript statt JSX. Das Projekt hat keine JS-Build-Kette für den Admin-Bereich, + und eine allein für diesen Block einzuführen wäre viel Apparat für wenig Ertrag. +- **Auswahlliste über `wp_localize_script`,** nicht über den Core-Datenspeicher: Der Custom Post + Type ist bewusst nicht über die WP-REST-API exponiert (`show_in_rest => false`), dafür gibt es + die eigenen Endpunkte. Die Liste wird nur im Editor aufgebaut (`enqueue_block_editor_assets`) + und ist auf 200 Einträge begrenzt. +- **Platzhalter statt Live-Vorschau im Editor.** Eine serverseitig gerenderte Vorschau bekäme das + Frontend-Stylesheet im Editor-Rahmen nicht mit und sähe dort kaputt aus; die Platzhalterkarte + nutzt WordPress' eigene `Placeholder`-Komponente und braucht deshalb kein eigenes CSS. +- `bin/build-release.sh` kopiert `blocks/` mit ins Paket — ohne diese Ergänzung wäre der Block in + der Installation schlicht nicht vorhanden gewesen. + +--- + ## [2.37.0] — 2026-08-07 Alle 24 EU-Amtssprachen statt zwei. diff --git a/CLAUDE.md b/CLAUDE.md index b4e1e9b..4c81a6f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -147,6 +147,7 @@ Externe Harvester rufen /catalog, /datasets/, oder /delta ab | **ODW_Rdf** | JSON-LD → Turtle (dependency-frei) für RDF-Harvester | `to_turtle()` | | **ODW_Field_Reference** | Erzeugt `docs/FELD-REFERENZ.md` aus `config/field-catalog.php` | `build()`, `write()`, `js_map()` | | **ODW_Settings** | Plugin-Einstellungsseite | `get()`, `filter_catalog_title()` | +| **ODW_Block** | Gutenberg-Block „Datensatz-Karte“ (dynamisch, rendert über ODW_Shortcode) | `register()`, `localize()`, `render()` | | **ODW_Shortcode** | Frontend Download-Card: `[odw_dataset id="123"]` | `render()` | | **ODW_Batch_Import** | CSV/JSON Batch-Import: Parsing, Validierung, Bulk-Insert | `parse_file()`, `validate_row()`, `import_records()` | | **ODW_CLI** | WP-CLI Befehle (Qualitäts-Recalc, Cache-Clear) | `quality_recalculate()`, `cache_clear()` | @@ -730,7 +731,7 @@ Update **both** locations: - MINOR: New features (backward-compatible) - PATCH: Bug fixes only -Current: **v2.37.0** +Current: **v2.38.0** --- @@ -769,6 +770,10 @@ Neue technische Festlegungen gehören dorthin, nicht in README oder CLAUDE.md. - **Gebündelte Vokabulare vervollständigt (v2.37.0):** `access-right` (3 Stufen) und `language` (alle 24 EU-Amtssprachen) liegen unter `config/vocabularies/`. Die Sprachauswahl bot vorher nur Deutsch und Englisch, obwohl `odw_resolve_language_tag()` alle 24 Codes bereits umsetzen konnte. +- **Gutenberg-Block (v2.38.0):** „Datensatz-Karte“ als Alternative zum Shortcode. Dynamischer + Block ohne Build-Schritt — `blocks/dataset-card/` mit `block.json` und schlichtem JS; das + Rendern delegiert an `ODW_Shortcode::render()`. Die Auswahlliste kommt über + `wp_localize_script`, weil der CPT bewusst nicht über die WP-REST-API exponiert ist. - **Content Negotiation (v2.35.0):** Alle drei Endpunkte liefern `jsonld`/`json`/`turtle`; ohne `?format=` entscheidet der `Accept`-Header (q-Werte, `Vary: Accept`). Explizites `?format=` hat Vorrang. @@ -777,7 +782,6 @@ Neue technische Festlegungen gehören dorthin, nicht in README oder CLAUDE.md. - **Optional: RDF/XML** als weitere Serialisierung (Turtle und JSON-LD decken die gängigen Harvester bereits ab). -- **Gutenberg-Block** für die Download-Card (Alternative zum Shortcode). - **Mehrsprachigkeit der Oberfläche** (WPML/Polylang) — das Datenmodell unterstützt Mehrsprachigkeit bereits, die Integration fehlt. - **Optional/künftig:** Registry-getriebenes Formular-/JSON-LD-Rendering (Aufräumarbeit ohne @@ -872,6 +876,6 @@ Neue technische Festlegungen gehören dorthin, nicht in README oder CLAUDE.md. --- -**Zuletzt aktualisiert**: Version 2.37.0 (August 2026) +**Zuletzt aktualisiert**: Version 2.38.0 (August 2026) **Autor**: Open Data Wizard Team (nozilla) **License**: GPL-2.0-or-later diff --git a/README.md b/README.md index ad0231f..e32c832 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ![PHP Version](https://img.shields.io/badge/PHP-%3E%3D%208.1-8892BF?style=flat-square&logo=php&logoColor=white) ![WordPress](https://img.shields.io/badge/WordPress-compatible-21759B?style=flat-square&logo=wordpress&logoColor=white) ![DCAT-AP](https://img.shields.io/badge/DCAT--AP-3.0-brightgreen?style=flat-square) -![Version](https://img.shields.io/badge/Version-2.37.0-brightgreen?style=flat-square) +![Version](https://img.shields.io/badge/Version-2.38.0-brightgreen?style=flat-square) ![PRs Welcome](https://img.shields.io/badge/PRs-willkommen-brightgreen?style=flat-square) 📖 [Dokumentation](DOCUMENTATION.md) · 📋 [Feld-Referenz](docs/FELD-REFERENZ.md) · 📐 [Technische Spezifikation](TECHNICAL-SPEC.md) · 📝 [Changelog](CHANGELOG.md) · 🛡️ [Security](SECURITY.md) · ⚖️ [Lizenz](LICENSE) @@ -171,11 +171,27 @@ Automatische Metadaten-Qualitätsprüfung nach der [EU-MQA-Methodik](https://dat Berechnung nach jedem Speichern. Die **Listenspalte** zeigt Prozent + Stufe; die **Qualitäts-Meta-Box** ergänzt den MQA-Rohwert (z. B. „54 / 259 Punkte, von max. 405") als Detailzeile. -### 📥 Download-Card Shortcode +### 📥 Download-Card — Block oder Shortcode + +Zwei Wege zur selben Karte. **Empfohlen ist der Block:** + +Im Beitrags- oder Seiteneditor über das Plus-Symbol **„Datensatz-Karte"** einfügen und rechts in +der Seitenleiste den Datensatz aus einer Liste wählen — keine ID zum Abtippen. Zur Auswahl stehen +nur veröffentlichte Datensätze. + +Alternativ der Shortcode, etwa in klassischen Editoren oder Widgets: + ``` [odw_dataset id="123"] ``` -Rendert eine strukturierte Download-Card im Frontend: Titel, Thema-Badge, Lizenz, Schlagwörter als Tag-Pillen, Download-Button sowie einen **Metadaten-Download-Button (JSON-LD)**. CSS (`assets/css/frontend.css`) wird nur auf Seiten geladen, die den Shortcode enthalten. + +Beide rendern dieselbe strukturierte Download-Card im Frontend: Titel, Thema-Badge, Lizenz, +Schlagwörter als Tag-Pillen, Download-Button sowie einen **Metadaten-Download-Button (JSON-LD)**. +CSS (`assets/css/frontend.css`) wird nur auf Seiten geladen, die die Karte auch enthalten. + +Der Block speichert ausschließlich die Datensatz-ID und rendert beim Ausliefern — ein später +umbenannter Datensatz erscheint also mit seinem aktuellen Titel, statt eine eingefrorene Kopie im +Beitrag zu hinterlassen. ### 🔗 REST API Endpoints diff --git a/bin/build-release.sh b/bin/build-release.sh index 24dbc1f..bbacf94 100755 --- a/bin/build-release.sh +++ b/bin/build-release.sh @@ -3,7 +3,7 @@ # build-release.sh — erzeugt ein installationsfertiges WordPress-Plugin-ZIP. # # Enthält ausschließlich die zur Laufzeit benötigten Dateien: -# - Plugin-Bootstrap, Klassen, Assets, Sprachen, Beispiel-Dateien +# - Plugin-Bootstrap, Klassen, Assets, Blöcke, Sprachen, Beispiel-Dateien # - config/ (nur Datendateien; Dev-Configs und SHACL-Referenz entfallen) # - vendor/ mit ausschließlich der Produktionsabhängigkeit (Carbon Fields), # via `composer install --no-dev`, inkl. Bereinigung der Carbon-Fields-Dev-Dateien @@ -43,7 +43,7 @@ mkdir -p "$PLUG_DIR" # --- Runtime-Quelldateien kopieren (Allowlist) ----------------------------- cp "$ROOT_DIR/$SLUG.php" "$ROOT_DIR/uninstall.php" "$ROOT_DIR/README.md" "$ROOT_DIR/LICENSE" "$PLUG_DIR/" -cp -R "$ROOT_DIR/includes" "$ROOT_DIR/assets" "$ROOT_DIR/languages" "$ROOT_DIR/samples" "$PLUG_DIR/" +cp -R "$ROOT_DIR/includes" "$ROOT_DIR/assets" "$ROOT_DIR/blocks" "$ROOT_DIR/languages" "$ROOT_DIR/samples" "$PLUG_DIR/" # config/ vollständig kopieren, dann Dev-/Referenz-Anteile entfernen cp -R "$ROOT_DIR/config" "$PLUG_DIR/" diff --git a/blocks/dataset-card/block.json b/blocks/dataset-card/block.json new file mode 100644 index 0000000..5801f2a --- /dev/null +++ b/blocks/dataset-card/block.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "odw/dataset-card", + "title": "Datensatz-Karte", + "category": "widgets", + "icon": "database", + "description": "Zeigt einen veröffentlichten Datensatz als Download-Karte — die Alternative zum Shortcode [odw_dataset].", + "keywords": [ "Datensatz", "Open Data", "Download", "DCAT" ], + "textdomain": "open-data-wizard", + "supports": { + "html": false, + "align": [ "wide" ], + "spacing": { + "margin": true + } + }, + "attributes": { + "datasetId": { + "type": "number", + "default": 0 + } + }, + "editorScript": "odw-dataset-card-editor" +} diff --git a/blocks/dataset-card/editor.js b/blocks/dataset-card/editor.js new file mode 100644 index 0000000..9a096cf --- /dev/null +++ b/blocks/dataset-card/editor.js @@ -0,0 +1,124 @@ +/* global wp */ +/** + * Editor-Skript für den Block „Datensatz-Karte". + * + * Bewusst in schlichtem JavaScript statt JSX: Das Projekt hat keine + * JS-Build-Kette für den Admin-Bereich, und eine allein für diesen Block + * einzuführen wäre viel Apparat für wenig Ertrag. Der Preis ist das + * ausgeschriebene createElement() statt der gewohnten JSX-Schreibweise. + * + * Die Auswahlliste kommt aus window.odwDatasetBlock (siehe ODW_Block): Der + * Custom Post Type ist absichtlich nicht über die WP-REST-API exponiert — + * dafür gibt es die eigenen Endpunkte —, also lässt er sich im Editor nicht + * über den Core-Datenspeicher abfragen. + * + * Im Editor steht eine Platzhalterkarte statt einer Live-Vorschau. Eine + * serverseitig gerenderte Vorschau bekäme das Frontend-Stylesheet im + * Editor-Rahmen nicht mit und sähe dort kaputt aus — eine ehrliche + * Platzhalterkarte ist verlässlicher als eine halbe Vorschau. + */ +( function ( blocks, element, blockEditor, components ) { + 'use strict'; + + var el = element.createElement; + var cfg = window.odwDatasetBlock || { datasets: [], labels: {} }; + var datasets = cfg.datasets || []; + var labels = cfg.labels || {}; + + function findDataset( id ) { + for ( var i = 0; i < datasets.length; i++ ) { + if ( datasets[ i ].id === id ) { + return datasets[ i ]; + } + } + return null; + } + + function selectOptions() { + var options = [ { label: labels.choose || '', value: 0 } ]; + for ( var i = 0; i < datasets.length; i++ ) { + options.push( { label: datasets[ i ].title, value: datasets[ i ].id } ); + } + return options; + } + + /** + * Die Karte im Editor — kein Abbild des Frontends, sondern eine ruhige + * Zusammenfassung dessen, was veröffentlicht wird. + * + * @param {Object} dataset Ausgewählter Datensatz oder null. + * @return {Object} Element. + */ + function preview( dataset, onChange ) { + // Durchgehend die Placeholder-Komponente von WordPress: Sie bringt ihr + // Aussehen selbst mit. Eigenes CSS wäre im Beitragseditor wirkungslos — + // assets/css/admin.css lädt nur auf den Datensatz-Bildschirmen. + if ( ! datasets.length ) { + return el( + components.Placeholder, + { icon: 'database', label: labels.title }, + el( 'p', null, labels.none ) + ); + } + + if ( ! dataset ) { + return el( + components.Placeholder, + { icon: 'database', label: labels.title, instructions: labels.pick }, + el( components.SelectControl, { + value: 0, + options: selectOptions(), + onChange: onChange, + __nextHasNoMarginBottom: true, + } ) + ); + } + + return el( + components.Placeholder, + { icon: 'database', label: labels.title }, + el( 'p', null, el( 'strong', null, dataset.title ) ), + el( 'p', null, labels.rendered ) + ); + } + + blocks.registerBlockType( 'odw/dataset-card', { + edit: function ( props ) { + var blockProps = blockEditor.useBlockProps(); + var id = props.attributes.datasetId || 0; + var dataset = findDataset( id ); + + function choose( value ) { + props.setAttributes( { datasetId: parseInt( value, 10 ) || 0 } ); + } + + return el( + 'div', + blockProps, + el( + blockEditor.InspectorControls, + null, + el( + components.PanelBody, + { title: labels.panel, initialOpen: true }, + el( components.SelectControl, { + label: labels.field, + value: id, + options: selectOptions(), + help: datasets.length ? labels.help : labels.none, + onChange: choose, + __nextHasNoMarginBottom: true, + } ) + ) + ), + preview( dataset, choose ) + ); + }, + + // Dynamischer Block: Das Markup entsteht beim Ausliefern in PHP über + // dieselbe Funktion wie beim Shortcode, damit es nur eine Quelle gibt. + save: function () { + return null; + }, + } ); +}( window.wp.blocks, window.wp.element, window.wp.blockEditor, window.wp.components ) ); diff --git a/includes/class-block.php b/includes/class-block.php new file mode 100644 index 0000000..153c3c5 --- /dev/null +++ b/includes/class-block.php @@ -0,0 +1,135 @@ + array( self::class, 'render' ) ) + ); + } + + /** + * Passes the list of published datasets and the editor labels to the script. + */ + public static function localize(): void { + $posts = get_posts( + array( + 'post_type' => 'odw_dataset', + 'post_status' => 'publish', + 'numberposts' => self::MAX_CHOICES, + 'orderby' => 'title', + 'order' => 'ASC', + 'suppress_filters' => false, + ) + ); + + $datasets = array(); + foreach ( $posts as $post ) { + $datasets[] = array( + 'id' => (int) $post->ID, + 'title' => $post->post_title !== '' ? $post->post_title : sprintf( + /* translators: %d: post ID of an untitled dataset */ + __( '(ohne Titel, ID %d)', 'open-data-wizard' ), + (int) $post->ID + ), + ); + } + + wp_localize_script( + 'odw-dataset-card-editor', + 'odwDatasetBlock', + array( + 'datasets' => $datasets, + 'labels' => array( + 'title' => __( 'Datensatz-Karte', 'open-data-wizard' ), + 'panel' => __( 'Datensatz', 'open-data-wizard' ), + 'field' => __( 'Welcher Datensatz soll angezeigt werden?', 'open-data-wizard' ), + 'choose' => __( '— Bitte wählen —', 'open-data-wizard' ), + 'help' => __( 'Nur veröffentlichte Datensätze stehen zur Auswahl. Entwürfe erscheinen erst nach dem Veröffentlichen.', 'open-data-wizard' ), + 'none' => __( 'Es gibt noch keinen veröffentlichten Datensatz. Legen Sie zuerst einen an und veröffentlichen Sie ihn.', 'open-data-wizard' ), + 'pick' => __( 'Wählen Sie rechts in der Seitenleiste einen Datensatz aus.', 'open-data-wizard' ), + 'rendered' => __( 'wird als Download-Karte ausgegeben', 'open-data-wizard' ), + ), + ) + ); + } + + /** + * Renders the block on the front end. + * + * @param array $attributes Block attributes. + * @return string + */ + public static function render( array $attributes ): string { + $dataset_id = isset( $attributes['datasetId'] ) ? absint( $attributes['datasetId'] ) : 0; + + if ( $dataset_id <= 0 ) { + return ''; + } + + if ( ! class_exists( 'ODW_Shortcode' ) ) { + return ''; + } + + // Dieselbe Ausgabe wie beim Shortcode, inklusive dessen Prüfungen auf + // Beitragstyp und Veröffentlichungsstatus und dem Einbinden des + // Frontend-Stylesheets. + return ODW_Shortcode::render( array( 'id' => (string) $dataset_id ) ); + } +} diff --git a/languages/open-data-wizard-en_US.mo b/languages/open-data-wizard-en_US.mo index 4318bf49d21ea591dba047e56c28e755eda034bb..bc2ed773e8c5e02fc5d6bad242f51959173934cc 100644 GIT binary patch delta 10942 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 CS3?;9 delta 10228 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 F{{T_=SYZGF diff --git a/languages/open-data-wizard-en_US.po b/languages/open-data-wizard-en_US.po index 088409a..594da9a 100644 --- a/languages/open-data-wizard-en_US.po +++ b/languages/open-data-wizard-en_US.po @@ -1894,3 +1894,24 @@ msgstr "(automatic)" msgid "Davon steuert der Wizard %d Punkte selbst bei: Das Änderungsdatum wird bei jedem Speichern automatisch gesetzt. Deshalb steht auch ein noch leerer Datensatz nicht bei 0 %%." msgstr "Of these, the wizard contributes %d points itself: the modification date is set automatically every time you save. That is why even an empty dataset does not start at 0 %%." + +msgid "(ohne Titel, ID %d)" +msgstr "(untitled, ID %d)" + +msgid "Datensatz-Karte" +msgstr "Dataset card" + +msgid "Es gibt noch keinen veröffentlichten Datensatz. Legen Sie zuerst einen an und veröffentlichen Sie ihn." +msgstr "There is no published dataset yet. Create one first and publish it." + +msgid "Nur veröffentlichte Datensätze stehen zur Auswahl. Entwürfe erscheinen erst nach dem Veröffentlichen." +msgstr "Only published datasets can be selected. Drafts appear once they are published." + +msgid "Welcher Datensatz soll angezeigt werden?" +msgstr "Which dataset should be shown?" + +msgid "Wählen Sie rechts in der Seitenleiste einen Datensatz aus." +msgstr "Choose a dataset in the sidebar on the right." + +msgid "wird als Download-Karte ausgegeben" +msgstr "will be output as a download card" diff --git a/languages/open-data-wizard.pot b/languages/open-data-wizard.pot index ed9f4b4..b1514fb 100644 --- a/languages/open-data-wizard.pot +++ b/languages/open-data-wizard.pot @@ -1521,3 +1521,24 @@ msgstr "" msgid "Welchem Engagementfeld ist dieser Datensatz zuzuordnen?" msgstr "" + +msgid "(ohne Titel, ID %d)" +msgstr "" + +msgid "Datensatz-Karte" +msgstr "" + +msgid "Es gibt noch keinen veröffentlichten Datensatz. Legen Sie zuerst einen an und veröffentlichen Sie ihn." +msgstr "" + +msgid "Nur veröffentlichte Datensätze stehen zur Auswahl. Entwürfe erscheinen erst nach dem Veröffentlichen." +msgstr "" + +msgid "Welcher Datensatz soll angezeigt werden?" +msgstr "" + +msgid "Wählen Sie rechts in der Seitenleiste einen Datensatz aus." +msgstr "" + +msgid "wird als Download-Karte ausgegeben" +msgstr "" diff --git a/open-data-wizard.php b/open-data-wizard.php index 9b5bf38..5d50e7e 100644 --- a/open-data-wizard.php +++ b/open-data-wizard.php @@ -3,7 +3,7 @@ * Plugin Name: Open Data Wizard * Plugin URI: https://github.com/daimpad/OpenDataWizard * Description: DCAT-AP 3.0 konforme Open Data Metadatenverwaltung für WordPress. Bereitstellung als maschinenlesbarer JSON-LD-Endpoint für offene Daten. - * Version: 2.37.0 + * Version: 2.38.0 * Requires at least: 6.4 * Requires PHP: 8.1 * Author: nozilla @@ -26,7 +26,7 @@ exit; } -define( 'ODW_VERSION', '2.37.0' ); +define( 'ODW_VERSION', '2.38.0' ); define( 'ODW_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); define( 'ODW_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); define( 'ODW_PLUGIN_FILE', __FILE__ ); @@ -147,6 +147,7 @@ function () use ( $e ): void { require_once ODW_PLUGIN_DIR . 'includes/class-admin.php'; require_once ODW_PLUGIN_DIR . 'includes/class-batch-import.php'; require_once ODW_PLUGIN_DIR . 'includes/class-shortcode.php'; + require_once ODW_PLUGIN_DIR . 'includes/class-block.php'; require_once ODW_PLUGIN_DIR . 'includes/class-cli.php'; ODW_Settings::init(); @@ -157,6 +158,7 @@ function () use ( $e ): void { ODW_Quality::init(); ODW_Admin::init(); ODW_Shortcode::init(); + ODW_Block::init(); ODW_Setup::init(); ODW_CLI::init(); } From ac308476446a349ca76871b0a6f00a131d0bc3eb Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 7 Aug 2026 14:30:23 +0000 Subject: [PATCH 2/2] style: Yoda-Bedingung in ODW_Block::localize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WPCS verlangt das Literal links. Die Stelle dabei auseinandergezogen — der Ternär über einen mehrzeiligen sprintf war schwer zu lesen — und den Grund für den Ersatztitel als Kommentar festgehalten. https://claude.ai/code/session_01JB1xUQM892bVZ4Yv3MZjvq --- includes/class-block.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/includes/class-block.php b/includes/class-block.php index 153c3c5..8950ebf 100644 --- a/includes/class-block.php +++ b/includes/class-block.php @@ -81,13 +81,21 @@ public static function localize(): void { $datasets = array(); foreach ( $posts as $post ) { - $datasets[] = array( - 'id' => (int) $post->ID, - 'title' => $post->post_title !== '' ? $post->post_title : sprintf( + $title = (string) $post->post_title; + + // Ein Datensatz ohne Titel wäre in der Auswahlliste unsichtbar — + // die ID macht ihn wenigstens auffindbar. + if ( '' === trim( $title ) ) { + $title = sprintf( /* translators: %d: post ID of an untitled dataset */ __( '(ohne Titel, ID %d)', 'open-data-wizard' ), (int) $post->ID - ), + ); + } + + $datasets[] = array( + 'id' => (int) $post->ID, + 'title' => $title, ); }