Mu-Plugin 1.5.0: Reihenfolge-Feld und Loop-Grid-Sortierung

This commit is contained in:
2026-09-22 13:54:28 +02:00
parent 39163f43bb
commit 257a414649
4 changed files with 154 additions and 84 deletions

View File

@@ -443,6 +443,7 @@ const meta = {
faq_ueberschrift: a.faq_ueberschrift || '', faq_ueberschrift: a.faq_ueberschrift || '',
cta_ziel: a.cta_ziel || '', cta_ziel: a.cta_ziel || '',
stand_datum: a.stand_datum || heute, stand_datum: a.stand_datum || heute,
ratgeber_reihenfolge: Number.isFinite(Number(a.reihenfolge)) && a.reihenfolge !== null && a.reihenfolge !== '' ? Number(a.reihenfolge) : 999,
faq: Array.isArray(a.faq) faq: Array.isArray(a.faq)
? a.faq.filter(f => f && f.frage).map(f => ({ frage: String(f.frage), antwort: String(f.antwort || '') })) ? a.faq.filter(f => f && f.frage).map(f => ({ frage: String(f.frage), antwort: String(f.antwort || '') }))
: [], : [],

View File

@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
"""Schreibt ratgeber_reihenfolge aus artikel/*.json in die bestehenden WP-Beitraege (braucht Mu-Plugin ab 1.5.0)."""
import base64, glob, json, urllib.request
E = {}
for z in open('.env', encoding='utf-8'):
z = z.strip()
if z and not z.startswith('#') and '=' in z:
k, v = z.split('=', 1); E[k] = v.strip().strip('"')
AUTH = 'Basic ' + base64.b64encode(f"{E['WP_USER']}:{E['WP_APP_PASSWORD']}".encode()).decode()
WP = E['WP_BASE_URL'].rstrip('/') + '/wp-json/wp/v2/posts'
def ruf(url, daten=None):
r = urllib.request.Request(url, data=json.dumps(daten).encode() if daten else None, method='POST' if daten else 'GET',
headers={'Authorization': AUTH, 'Content-Type': 'application/json'})
return json.load(urllib.request.urlopen(r, timeout=60))
for f in sorted(glob.glob('artikel/artikel-*.json')):
a = json.load(open(f, encoding='utf-8'))
treffer = ruf(f"{WP}?slug={a['slug']}&status=draft,publish,pending,future,private&context=edit&_fields=id,meta")
if not treffer:
print('kein Beitrag', a['slug']); continue
pid = treffer[0]['id']
neu = ruf(f"{WP}/{pid}?_fields=id,meta", {'meta': {'ratgeber_reihenfolge': a.get('reihenfolge', 999)}})
print(pid, a['slug'], neu['meta'].get('ratgeber_reihenfolge', 'Feld unbekannt, Plugin 1.5.0 fehlt'))

View File

@@ -1,8 +1,8 @@
<?php <?php
/** /**
* Plugin Name: Skrift Ratgeber Felder * Plugin Name: Skrift Ratgeber Felder
* Description: Meta-Felder fuer Ratgeberartikel (kurzantwort, faq, faq_ueberschrift, cta_ziel, stand_datum) mit Eingabebox im Editor, Shortcodes, Elementor-Widgets fuer FAQ und Kurzantwort sowie Dynamic Tags fuer Lesezeit, FAQ-Ueberschrift und Stand. * Description: Meta-Felder fuer Ratgeberartikel (kurzantwort, faq, faq_ueberschrift, cta_ziel, stand_datum, ratgeber_reihenfolge) mit Eingabebox im Editor, Shortcodes, Elementor-Widgets fuer FAQ und Kurzantwort sowie Dynamic Tags fuer Lesezeit, FAQ-Ueberschrift und Stand.
* Version: 1.4.0 * Version: 1.5.0
* Author: Lucas Orth * Author: Lucas Orth
* *
* Ablage: wp-content/mu-plugins/skrift-ratgeber-felder.php * Ablage: wp-content/mu-plugins/skrift-ratgeber-felder.php
@@ -54,6 +54,16 @@ add_action( 'init', function () {
'auth_callback' => 'skrift_ratgeber_meta_auth', 'auth_callback' => 'skrift_ratgeber_meta_auth',
) ); ) );
// Feste Reihenfolge im Loop Grid, klein = weiter vorn. Schritte von 10 lassen Platz zum Einschieben.
register_post_meta( 'post', 'ratgeber_reihenfolge', array(
'type' => 'integer',
'single' => true,
'default' => 999,
'show_in_rest' => true,
'sanitize_callback' => 'absint',
'auth_callback' => 'skrift_ratgeber_meta_auth',
) );
register_post_meta( 'post', 'faq', array( register_post_meta( 'post', 'faq', array(
'type' => 'array', 'type' => 'array',
'single' => true, 'single' => true,
@@ -101,6 +111,8 @@ function skrift_ratgeber_metabox( $post ) {
$cta = (string) get_post_meta( $post->ID, 'cta_ziel', true ); $cta = (string) get_post_meta( $post->ID, 'cta_ziel', true );
$stand = (string) get_post_meta( $post->ID, 'stand_datum', true ); $stand = (string) get_post_meta( $post->ID, 'stand_datum', true );
$faq_u = (string) get_post_meta( $post->ID, 'faq_ueberschrift', true ); $faq_u = (string) get_post_meta( $post->ID, 'faq_ueberschrift', true );
$rf = get_post_meta( $post->ID, 'ratgeber_reihenfolge', true );
$rf = ( '' === $rf ) ? 999 : (int) $rf;
$faq = get_post_meta( $post->ID, 'faq', true ); $faq = get_post_meta( $post->ID, 'faq', true );
if ( ! is_array( $faq ) ) { if ( ! is_array( $faq ) ) {
$faq = array(); $faq = array();
@@ -132,6 +144,11 @@ function skrift_ratgeber_metabox( $post ) {
<label for="skrift_stand_datum">Stand</label> <label for="skrift_stand_datum">Stand</label>
<input type="date" id="skrift_stand_datum" name="skrift_stand_datum" value="<?php echo esc_attr( $stand ); ?>"> <input type="date" id="skrift_stand_datum" name="skrift_stand_datum" value="<?php echo esc_attr( $stand ); ?>">
</p> </p>
<p>
<label for="skrift_reihenfolge">Reihenfolge</label>
<input type="number" min="0" step="1" id="skrift_reihenfolge" name="skrift_reihenfolge" value="<?php echo esc_attr( $rf ); ?>">
<span class="description">Klein = weiter vorn im Loop Grid.</span>
</p>
</div> </div>
<p> <p>
@@ -199,6 +216,7 @@ add_action( 'save_post_post', function ( $post_id ) {
update_post_meta( $post_id, 'kurzantwort', wp_kses_post( wp_unslash( $_POST['skrift_kurzantwort'] ?? '' ) ) ); update_post_meta( $post_id, 'kurzantwort', wp_kses_post( wp_unslash( $_POST['skrift_kurzantwort'] ?? '' ) ) );
update_post_meta( $post_id, 'faq_ueberschrift', sanitize_text_field( wp_unslash( $_POST['skrift_faq_ueberschrift'] ?? '' ) ) ); update_post_meta( $post_id, 'faq_ueberschrift', sanitize_text_field( wp_unslash( $_POST['skrift_faq_ueberschrift'] ?? '' ) ) );
update_post_meta( $post_id, 'cta_ziel', esc_url_raw( wp_unslash( $_POST['skrift_cta_ziel'] ?? '' ) ) ); update_post_meta( $post_id, 'cta_ziel', esc_url_raw( wp_unslash( $_POST['skrift_cta_ziel'] ?? '' ) ) );
update_post_meta( $post_id, 'ratgeber_reihenfolge', isset( $_POST['skrift_reihenfolge'] ) && '' !== $_POST['skrift_reihenfolge'] ? absint( $_POST['skrift_reihenfolge'] ) : 999 );
update_post_meta( $post_id, 'stand_datum', skrift_ratgeber_datum( sanitize_text_field( wp_unslash( $_POST['skrift_stand_datum'] ?? '' ) ) ) ); update_post_meta( $post_id, 'stand_datum', skrift_ratgeber_datum( sanitize_text_field( wp_unslash( $_POST['skrift_stand_datum'] ?? '' ) ) ) );
$faq = array(); $faq = array();
@@ -753,3 +771,32 @@ add_action( 'elementor/dynamic_tags/register', function ( $dynamic_tags ) {
$dynamic_tags->register( new Skrift_Tag_FAQ_Ueberschrift() ); $dynamic_tags->register( new Skrift_Tag_FAQ_Ueberschrift() );
$dynamic_tags->register( new Skrift_Tag_Stand() ); $dynamic_tags->register( new Skrift_Tag_Stand() );
} ); } );
/* ------------------------------------------------------------------------
* Loop Grid: Sortierung ueber ratgeber_reihenfolge
* In Elementor im Loop Grid unter Abfrage > Abfrage-ID "skrift_ratgeber" eintragen.
* Kategorie-Filter aus dem Widget (Einschliessen nach Begriff) bleibt erhalten.
* Beitraege ohne Wert landen hinten, bei gleichem Wert entscheidet das Datum.
* --------------------------------------------------------------------- */
add_action( 'elementor/query/skrift_ratgeber', function ( $query ) {
$meta_query = (array) $query->get( 'meta_query' );
$meta_query[] = array(
'relation' => 'OR',
'rf_vorhanden' => array( 'key' => 'ratgeber_reihenfolge', 'type' => 'NUMERIC', 'compare' => 'EXISTS' ),
'rf_fehlt' => array( 'key' => 'ratgeber_reihenfolge', 'compare' => 'NOT EXISTS' ),
);
$query->set( 'meta_query', $meta_query );
$query->set( 'orderby', array( 'rf_vorhanden' => 'ASC', 'date' => 'DESC' ) );
} );
// Beitraege ohne Wert bekommen beim Speichern 999, damit sie in der Sortierung hinten stehen.
add_action( 'save_post_post', function ( $post_id ) {
if ( wp_is_post_revision( $post_id ) ) {
return;
}
if ( ! metadata_exists( 'post', $post_id, 'ratgeber_reihenfolge' ) ) {
update_post_meta( $post_id, 'ratgeber_reihenfolge', 999 );
}
}, 20 );

View File

@@ -9,7 +9,7 @@
-460, -460,
100 100
], ],
"id": "77876018-7154-4c9d-b1dd-5dd786cf8aae", "id": "e645bc35-12a4-4aed-9c7a-ecc74d00f453",
"name": "Manuell starten" "name": "Manuell starten"
}, },
{ {
@@ -25,9 +25,9 @@
-460, -460,
280 280
], ],
"id": "57a30ac3-70e9-4cd3-b898-2f2b4ac669ac", "id": "1d24eaed-3b4f-41e8-9016-4cc6923ab622",
"name": "Webhook Start", "name": "Webhook Start",
"webhookId": "7a157b66-1824-459c-9dfb-0b52145d33a5" "webhookId": "a54ca6b3-e645-465e-8969-fd2e242055ae"
}, },
{ {
"parameters": { "parameters": {
@@ -35,115 +35,115 @@
"assignments": { "assignments": {
"assignments": [ "assignments": [
{ {
"id": "30e392d0-59d5-4ede-bd7a-2e007e477c0a", "id": "81fec9aa-b2e1-42a2-8eb3-87106e596bde",
"name": "nw_base", "name": "nw_base",
"value": "https://app.neuronwriter.com/neuron-api/0.5/writer", "value": "https://app.neuronwriter.com/neuron-api/0.5/writer",
"type": "string" "type": "string"
}, },
{ {
"id": "68bbc028-b18a-49ad-9032-5c0b0b3de53a", "id": "ee7027dd-2ebd-4570-aaf5-85057bf01135",
"name": "gitea_base", "name": "gitea_base",
"value": "http://gitea:3000", "value": "http://gitea:3000",
"type": "string" "type": "string"
}, },
{ {
"id": "61a631f8-1840-45ab-ad22-3090d5de8e84", "id": "03aee034-b048-4065-97c7-cf79f3983faa",
"name": "gitea_owner", "name": "gitea_owner",
"value": "lucas.orth", "value": "lucas.orth",
"type": "string" "type": "string"
}, },
{ {
"id": "0efb15dc-4dbf-4e51-b7d6-7e0fd1535ee6", "id": "4f52fda8-7009-45c4-a639-47f2781745a9",
"name": "gitea_repo", "name": "gitea_repo",
"value": "Skrift-Auto-Article", "value": "Skrift-Auto-Article",
"type": "string" "type": "string"
}, },
{ {
"id": "6f442b85-68aa-4723-8f20-0c4804863d94", "id": "c90e3261-c81c-4793-bc2f-dd8161939f08",
"name": "branch", "name": "branch",
"value": "main", "value": "main",
"type": "string" "type": "string"
}, },
{ {
"id": "f26f278d-f9ce-4b2e-a9b4-17a528823163", "id": "6a4e762a-a262-4aae-b4a9-a746e1e163e6",
"name": "artikel_ordner", "name": "artikel_ordner",
"value": "artikel", "value": "artikel",
"type": "string" "type": "string"
}, },
{ {
"id": "0a60485f-7117-4736-a8e9-a180d5f66ea3", "id": "f724b9be-2c72-4e94-a9b9-62a9f22baf50",
"name": "brief_ordner", "name": "brief_ordner",
"value": "briefe", "value": "briefe",
"type": "string" "type": "string"
}, },
{ {
"id": "fb4029bc-aaa5-4a2b-ac39-74e0a6b18ef6", "id": "742cbf71-76b2-4c86-ab81-8ddf644d4422",
"name": "nachbessern_ordner", "name": "nachbessern_ordner",
"value": "nachbessern", "value": "nachbessern",
"type": "string" "type": "string"
}, },
{ {
"id": "e255b391-5f12-4bde-84b4-c508bab8dac5", "id": "4c5b9314-bc21-4474-8e48-056deecd14d8",
"name": "status_pfad", "name": "status_pfad",
"value": "status-importe.json", "value": "status-importe.json",
"type": "string" "type": "string"
}, },
{ {
"id": "5785c32f-ef1c-45c3-bde1-61eccb439105", "id": "95d6f83b-aa71-4ebf-861e-ad6d2e9fa79b",
"name": "wp_base", "name": "wp_base",
"value": "https://skrift.de", "value": "https://skrift.de",
"type": "string" "type": "string"
}, },
{ {
"id": "b973a4ea-3b85-4c2f-abbd-8cf6d26025bc", "id": "105b0778-3d05-4b5f-9fed-99409c2aa44f",
"name": "score_ziel", "name": "score_ziel",
"value": "={{ $json.body && $json.body.score_ziel ? Number($json.body.score_ziel) : 65 }}", "value": "={{ $json.body && $json.body.score_ziel ? Number($json.body.score_ziel) : 65 }}",
"type": "number" "type": "number"
}, },
{ {
"id": "ff314c6a-5748-4de2-8e2a-7c05ba864085", "id": "7f9d5e34-8319-407f-8c06-4acd2aab10f2",
"name": "pause_zwischen_artikeln", "name": "pause_zwischen_artikeln",
"value": 5, "value": 5,
"type": "number" "type": "number"
}, },
{ {
"id": "66d24a08-85e1-4f85-b365-e34283f3b3a8", "id": "0562defc-78e5-4bf5-a3be-caccff62640c",
"name": "elementor_ausgabe", "name": "elementor_ausgabe",
"value": false, "value": false,
"type": "boolean" "type": "boolean"
}, },
{ {
"id": "afc4788f-4558-489f-8b3c-7df902791200", "id": "d16d9864-9d93-438c-a7cf-ae9c9cdcaff0",
"name": "bild_aktiv", "name": "bild_aktiv",
"value": true, "value": true,
"type": "boolean" "type": "boolean"
}, },
{ {
"id": "fde4d84a-6f31-40a4-88c3-863e796aa45d", "id": "2c439140-a3ad-4f7d-8565-0810b3c27467",
"name": "bild_modell", "name": "bild_modell",
"value": "gpt-image-2", "value": "gpt-image-2",
"type": "string" "type": "string"
}, },
{ {
"id": "ef031954-d296-4068-872a-6fbe54e1ccc3", "id": "1ae43107-262a-4257-a89d-132f8dabfdd9",
"name": "bild_groesse", "name": "bild_groesse",
"value": "1200x1200", "value": "1200x1200",
"type": "string" "type": "string"
}, },
{ {
"id": "94990856-3ac7-47df-9636-b51dfe6d5e1e", "id": "886ab8cf-1e76-4775-ba4f-727fe2389d81",
"name": "bild_qualitaet", "name": "bild_qualitaet",
"value": "medium", "value": "medium",
"type": "string" "type": "string"
}, },
{ {
"id": "d51af1a1-fc5a-4a60-ac9a-9ce2df113dd1", "id": "e255dc56-5585-4c5d-831f-41913892e9f9",
"name": "faq_ueberschrift", "name": "faq_ueberschrift",
"value": "Häufige Fragen", "value": "Häufige Fragen",
"type": "string" "type": "string"
}, },
{ {
"id": "b8366f1f-fe40-4ca7-b052-1bee24d543be", "id": "482a9f25-1180-422a-a03e-04e8d555b672",
"name": "benachrichtigung_an", "name": "benachrichtigung_an",
"value": "privat@lucas-orth.de", "value": "privat@lucas-orth.de",
"type": "string" "type": "string"
@@ -158,7 +158,7 @@
-240, -240,
190 190
], ],
"id": "01d2991f-f38d-485d-8871-af8267952501", "id": "6ad49d4e-b542-499f-907a-2eb4a82e0cad",
"name": "Konfiguration" "name": "Konfiguration"
}, },
{ {
@@ -183,7 +183,7 @@
-20, -20,
190 190
], ],
"id": "b9f2b463-32ec-4250-bfbc-ad262f3901d3", "id": "d049d98d-d7c6-4b65-a981-2b783050d08f",
"name": "Artikelordner lesen", "name": "Artikelordner lesen",
"credentials": { "credentials": {
"httpHeaderAuth": { "httpHeaderAuth": {
@@ -206,7 +206,7 @@
200, 200,
190 190
], ],
"id": "c89a4237-836d-44c3-8572-2bf939a873af", "id": "fe3a6d0a-982d-41f1-86a1-74363a3fd16b",
"name": "Artikeldateien filtern" "name": "Artikeldateien filtern"
}, },
{ {
@@ -220,7 +220,7 @@
}, },
"conditions": [ "conditions": [
{ {
"id": "c7bbd13f-b4c6-48f9-8b79-4efcb95ab7a2", "id": "875e5b9f-9c14-432f-abc9-ac4ede4f53b2",
"leftValue": "={{ $json.leer === true }}", "leftValue": "={{ $json.leer === true }}",
"rightValue": "", "rightValue": "",
"operator": { "operator": {
@@ -241,7 +241,7 @@
420, 420,
190 190
], ],
"id": "946944dc-a368-46f7-9af0-dd93cf2972a1", "id": "c83e34b8-5538-4aa2-893a-ab75c67d7bbf",
"name": "Artikel vorhanden?" "name": "Artikel vorhanden?"
}, },
{ {
@@ -252,7 +252,7 @@
640, 640,
40 40
], ],
"id": "6171f836-f34c-4528-b8df-2fe872055632", "id": "b971a2aa-7412-44b1-9ea7-192727cd8552",
"name": "Nichts zu tun" "name": "Nichts zu tun"
}, },
{ {
@@ -268,7 +268,7 @@
640, 640,
320 320
], ],
"id": "9c1acd2c-c3ec-4dc9-8359-011552d42f61", "id": "17dad5b6-7d29-4200-9895-d9cfa89e3e65",
"name": "Artikel nacheinander" "name": "Artikel nacheinander"
}, },
{ {
@@ -292,7 +292,7 @@
900, 900,
420 420
], ],
"id": "baf3e0c2-38c8-45c4-834e-db4d09a570a9", "id": "70cf0ad6-149c-4930-8e32-6b469ef96dc4",
"name": "Artikeldatei laden", "name": "Artikeldatei laden",
"credentials": { "credentials": {
"httpHeaderAuth": { "httpHeaderAuth": {
@@ -316,7 +316,7 @@
900, 900,
640 640
], ],
"id": "c0751d4b-193c-4942-86c3-f588b7cca5c6", "id": "15e29181-177a-496e-aedc-1861f3ca021a",
"name": "Fehler Artikeldatei", "name": "Fehler Artikeldatei",
"onError": "continueRegularOutput" "onError": "continueRegularOutput"
}, },
@@ -342,7 +342,7 @@
1120, 1120,
420 420
], ],
"id": "998ea097-3d46-4bd5-9afb-9727c58b119d", "id": "e0493f24-d401-47fc-917b-d1091ab17f1e",
"name": "Brief laden", "name": "Brief laden",
"credentials": { "credentials": {
"httpHeaderAuth": { "httpHeaderAuth": {
@@ -362,7 +362,7 @@
1340, 1340,
420 420
], ],
"id": "abfc66c7-c1ef-4640-9e5e-1f7268173605", "id": "2a7b4374-a366-44f3-96b1-d33dc7378b2c",
"name": "Artikel pruefen" "name": "Artikel pruefen"
}, },
{ {
@@ -392,7 +392,7 @@
1560, 1560,
420 420
], ],
"id": "9158e17f-118f-4e28-b4bd-27c2f38ab958", "id": "f163c0a3-181e-40c0-88a2-f2157042d415",
"name": "Score ermitteln", "name": "Score ermitteln",
"credentials": { "credentials": {
"httpHeaderAuth": { "httpHeaderAuth": {
@@ -416,7 +416,7 @@
1560, 1560,
640 640
], ],
"id": "e5155865-6106-494e-b238-de63ec2fcf23", "id": "4455414d-1ed4-48a3-921b-d10cafe23afd",
"name": "Fehler Score", "name": "Fehler Score",
"onError": "continueRegularOutput" "onError": "continueRegularOutput"
}, },
@@ -431,7 +431,7 @@
1780, 1780,
420 420
], ],
"id": "c670cfc5-5c64-46c4-b9d9-da2f9f7d998a", "id": "0fe1ca56-4b69-4504-aa55-87766e82d1e6",
"name": "Score auswerten" "name": "Score auswerten"
}, },
{ {
@@ -445,7 +445,7 @@
}, },
"conditions": [ "conditions": [
{ {
"id": "da564c6f-a42b-4cf5-82bf-da3d41877da7", "id": "62fbfd27-c661-454c-b433-b5977f969e52",
"leftValue": "={{ $json.bestanden }}", "leftValue": "={{ $json.bestanden }}",
"rightValue": "", "rightValue": "",
"operator": { "operator": {
@@ -466,7 +466,7 @@
2000, 2000,
420 420
], ],
"id": "3dfb6f30-0274-49c2-84c0-a010d862298c", "id": "ca4f34e1-f915-4fcf-91bd-6cbcc71abe77",
"name": "Score erreicht?" "name": "Score erreicht?"
}, },
{ {
@@ -480,7 +480,7 @@
2220, 2220,
640 640
], ],
"id": "bac5edd8-d56a-4533-b56c-f3b24bab3263", "id": "f598e1f9-a15a-4b34-a59d-5bdf15513402",
"name": "Fehlende Begriffe ermitteln" "name": "Fehlende Begriffe ermitteln"
}, },
{ {
@@ -505,7 +505,7 @@
2440, 2440,
640 640
], ],
"id": "3d514218-62c0-439e-8594-7ccc5ebebdae", "id": "2a20625a-a1b4-470a-a558-edf71e3985b8",
"name": "Nachbesserung vorhanden?", "name": "Nachbesserung vorhanden?",
"credentials": { "credentials": {
"httpHeaderAuth": { "httpHeaderAuth": {
@@ -525,7 +525,7 @@
2660, 2660,
640 640
], ],
"id": "a6b0f5d9-361d-4b09-bba3-e169b33b85ca", "id": "4413cca3-3996-40ff-88bc-90deceac60c9",
"name": "Nachbesserung vorbereiten" "name": "Nachbesserung vorbereiten"
}, },
{ {
@@ -555,7 +555,7 @@
2880, 2880,
640 640
], ],
"id": "4a9a76dc-68fa-4c8e-93a6-6c01f1ede8ce", "id": "7c6e53c5-fb96-4c18-811b-c6764804b3f9",
"name": "Nachbesserung committen", "name": "Nachbesserung committen",
"credentials": { "credentials": {
"httpHeaderAuth": { "httpHeaderAuth": {
@@ -579,7 +579,7 @@
2880, 2880,
860 860
], ],
"id": "b675c23e-1826-4d4c-ace8-a339efef67bf", "id": "24d265f2-7379-4dcc-af74-bd275c293ac1",
"name": "Fehler Nachbesserung", "name": "Fehler Nachbesserung",
"onError": "continueRegularOutput" "onError": "continueRegularOutput"
}, },
@@ -594,7 +594,7 @@
3100, 3100,
640 640
], ],
"id": "48d2bbc1-5cc0-496e-80ba-d002ee7ea687", "id": "1bb8c4d3-91f7-4aa1-b0f3-ae176e5e4e3a",
"name": "Nachbesserung gemerkt" "name": "Nachbesserung gemerkt"
}, },
{ {
@@ -624,7 +624,7 @@
2220, 2220,
240 240
], ],
"id": "b84af3b2-4638-4713-81c1-c8d8747c0363", "id": "b1dd3437-1339-47a8-acf2-ac50a07e2fba",
"name": "Revision zu NeuronWriter", "name": "Revision zu NeuronWriter",
"credentials": { "credentials": {
"httpHeaderAuth": { "httpHeaderAuth": {
@@ -648,7 +648,7 @@
2220, 2220,
60 60
], ],
"id": "c881c38e-ecdc-4a9c-a25f-e05e40c3e5ef", "id": "41308b76-0798-4d3b-892f-bfa9a0c2331b",
"name": "Fehler Revision", "name": "Fehler Revision",
"onError": "continueRegularOutput" "onError": "continueRegularOutput"
}, },
@@ -674,7 +674,7 @@
2440, 2440,
240 240
], ],
"id": "3fd00ae7-8bf9-4027-9119-bb8ba00d6e11", "id": "92090059-6fd5-492b-b3d4-0f381ff24aa6",
"name": "Beitrag vorhanden?", "name": "Beitrag vorhanden?",
"credentials": { "credentials": {
"httpBasicAuth": { "httpBasicAuth": {
@@ -708,7 +708,7 @@
2660, 2660,
240 240
], ],
"id": "78586dc9-923d-49be-b5df-11f27a0cfbea", "id": "db39d451-3fae-476d-ac3f-e8a7a754c3af",
"name": "Kategorie suchen", "name": "Kategorie suchen",
"credentials": { "credentials": {
"httpBasicAuth": { "httpBasicAuth": {
@@ -731,7 +731,7 @@
2880, 2880,
240 240
], ],
"id": "e198abd7-2f0b-49f5-adc5-3c4a9ee3ab3a", "id": "4574946a-3f6c-4616-9b39-ecc412802a93",
"name": "Kategorie pruefen" "name": "Kategorie pruefen"
}, },
{ {
@@ -745,7 +745,7 @@
}, },
"conditions": [ "conditions": [
{ {
"id": "b0e30459-6b54-4b74-8470-9520c5f3a9bb", "id": "2cc73f4f-f7a9-4639-8e76-8a36e28e55ec",
"leftValue": "={{ $json.kategorie_fehlt }}", "leftValue": "={{ $json.kategorie_fehlt }}",
"rightValue": "", "rightValue": "",
"operator": { "operator": {
@@ -766,7 +766,7 @@
3100, 3100,
240 240
], ],
"id": "bcbe3d18-9ecc-497e-886b-32cdab8263e7", "id": "54eda814-f0fa-4289-b85c-7d6bf1552894",
"name": "Kategorie anlegen?" "name": "Kategorie anlegen?"
}, },
{ {
@@ -796,7 +796,7 @@
3320, 3320,
140 140
], ],
"id": "5a6a0165-5d7b-42f6-9818-2b76ebc1376b", "id": "97c45331-c51c-4500-9559-1531e5dd69fe",
"name": "Kategorie anlegen", "name": "Kategorie anlegen",
"credentials": { "credentials": {
"httpBasicAuth": { "httpBasicAuth": {
@@ -819,13 +819,13 @@
3540, 3540,
240 240
], ],
"id": "c0e0e90e-e0d2-4a9d-8f9e-74fabf3a0561", "id": "8cca486f-9191-4afb-9022-69a95657cf25",
"name": "Kategorie festlegen" "name": "Kategorie festlegen"
}, },
{ {
"parameters": { "parameters": {
"mode": "runOnceForAllItems", "mode": "runOnceForAllItems",
"jsCode": "\nconst s = $input.first().json;\nconst dup = $('Beitrag vorhanden?').first().json;\nconst a = s.artikel;\n\n// Duplikatspruefung: exakter Slug-Treffer entscheidet ueber anlegen oder aktualisieren.\n// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.\nconst K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);\nconst kd = K(dup);\nconst treffer = (dup.statusCode === 200 && Array.isArray(kd))\n ? kd.find(p => p.slug === s.slug) : null;\n\nconst heute = new Date().toISOString().slice(0, 10);\n\nconst meta = {\n kurzantwort: a.kurzantwort || '',\n faq_ueberschrift: a.faq_ueberschrift || '',\n cta_ziel: a.cta_ziel || '',\n stand_datum: a.stand_datum || heute,\n faq: Array.isArray(a.faq)\n ? a.faq.filter(f => f && f.frage).map(f => ({ frage: String(f.frage), antwort: String(f.antwort || '') }))\n : [],\n _seopress_titles_title: a.seo_titel || a.titel,\n _seopress_titles_desc: a.seo_beschreibung || '',\n _seopress_analysis_target_kw: a.keyword || '',\n};\n\n// --- Elementor-Struktur aus Artikel und FAQ ---\n// Zerlegt den Text an den H2-Grenzen in Text-Editor-Widgets und haengt das FAQ\n// als nested-accordion an, dasselbe Widget wie auf den Leistungsseiten.\nconst konf = $('Konfiguration').first().json;\nconst eid = () => Math.random().toString(16).slice(2, 9);\nconst textWidget = (h) => ({ id: eid(), elType: 'widget', settings: { editor: h },\n elements: [], widgetType: 'text-editor' });\nconst behaelter = (kinder, innen) => {\n const s = { content_width: 'full' };\n if (innen) Object.assign(s, {\n _title: 'Element',\n padding: { unit: 'px', top: '8', right: '8', bottom: '8', left: '8', isLinked: true },\n flex_gap: { column: '20', row: '20', isLinked: true, unit: 'px', size: 20 },\n });\n const c = { id: eid(), elType: 'container', settings: s, elements: kinder };\n if (innen) { c.isInner = true; c.isLocked = true; }\n return c;\n};\n\nfunction elementorBauen() {\n const wurzel = [];\n if (a.kurzantwort) {\n wurzel.push(behaelter([textWidget(\n `<div class=\"skrift-kurzantwort\"><p>${a.kurzantwort}</p></div>`)]));\n }\n const html = String(a.content_html || '');\n const stellen = [];\n const re2 = /<h2[ >]/g;\n let mm;\n while ((mm = re2.exec(html)) !== null) stellen.push(mm.index);\n const bloecke = [];\n if (!stellen.length) {\n if (html.trim()) bloecke.push(html.trim());\n } else {\n if (stellen[0] > 0 && html.slice(0, stellen[0]).trim()) bloecke.push(html.slice(0, stellen[0]).trim());\n stellen.forEach((s, i) => {\n const ende = i + 1 < stellen.length ? stellen[i + 1] : html.length;\n const b = html.slice(s, ende).trim();\n if (b) bloecke.push(b);\n });\n }\n bloecke.forEach(b => wurzel.push(behaelter([textWidget(b)])));\n\n if (meta.faq.length) {\n const items = [], kinder = [];\n meta.faq.forEach(f => {\n items.push({ item_title: f.frage, _id: eid() });\n kinder.push(behaelter([textWidget(`<p>${f.antwort || ''}</p>`)], true));\n });\n wurzel.push(behaelter([\n textWidget(`<h2>${konf.faq_ueberschrift || 'Häufige Fragen'}</h2>`),\n { id: eid(), elType: 'widget', widgetType: 'nested-accordion',\n settings: { items, faq_schema: 'yes', default_state: 'all_collapsed' },\n elements: kinder },\n ]));\n }\n return wurzel;\n}\n\nif (konf.elementor_ausgabe) {\n meta._elementor_data = JSON.stringify(elementorBauen());\n meta._elementor_edit_mode = 'builder';\n meta._elementor_template_type = 'wp-post';\n}\n\nconst body = {\n title: a.titel,\n slug: s.slug,\n content: a.content_html,\n status: 'draft', // harte Vorgabe: nie automatisch veroeffentlichen\n categories: [s.kategorie_id],\n meta,\n};\nif (a.auszug) body.excerpt = a.auszug;\n\nreturn [{ json: {\n ...s,\n vorhanden: !!treffer,\n post_id: treffer ? treffer.id : null,\n alter_status: treffer ? treffer.status : null,\n wp_url: treffer\n ? `${$('Konfiguration').first().json.wp_base}/wp-json/wp/v2/posts/${treffer.id}`\n : `${$('Konfiguration').first().json.wp_base}/wp-json/wp/v2/posts`,\n wp_body: JSON.stringify(body),\n}}];\n" "jsCode": "\nconst s = $input.first().json;\nconst dup = $('Beitrag vorhanden?').first().json;\nconst a = s.artikel;\n\n// Duplikatspruefung: exakter Slug-Treffer entscheidet ueber anlegen oder aktualisieren.\n// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.\nconst K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);\nconst kd = K(dup);\nconst treffer = (dup.statusCode === 200 && Array.isArray(kd))\n ? kd.find(p => p.slug === s.slug) : null;\n\nconst heute = new Date().toISOString().slice(0, 10);\n\nconst meta = {\n kurzantwort: a.kurzantwort || '',\n faq_ueberschrift: a.faq_ueberschrift || '',\n cta_ziel: a.cta_ziel || '',\n stand_datum: a.stand_datum || heute,\n ratgeber_reihenfolge: Number.isFinite(Number(a.reihenfolge)) && a.reihenfolge !== null && a.reihenfolge !== '' ? Number(a.reihenfolge) : 999,\n faq: Array.isArray(a.faq)\n ? a.faq.filter(f => f && f.frage).map(f => ({ frage: String(f.frage), antwort: String(f.antwort || '') }))\n : [],\n _seopress_titles_title: a.seo_titel || a.titel,\n _seopress_titles_desc: a.seo_beschreibung || '',\n _seopress_analysis_target_kw: a.keyword || '',\n};\n\n// --- Elementor-Struktur aus Artikel und FAQ ---\n// Zerlegt den Text an den H2-Grenzen in Text-Editor-Widgets und haengt das FAQ\n// als nested-accordion an, dasselbe Widget wie auf den Leistungsseiten.\nconst konf = $('Konfiguration').first().json;\nconst eid = () => Math.random().toString(16).slice(2, 9);\nconst textWidget = (h) => ({ id: eid(), elType: 'widget', settings: { editor: h },\n elements: [], widgetType: 'text-editor' });\nconst behaelter = (kinder, innen) => {\n const s = { content_width: 'full' };\n if (innen) Object.assign(s, {\n _title: 'Element',\n padding: { unit: 'px', top: '8', right: '8', bottom: '8', left: '8', isLinked: true },\n flex_gap: { column: '20', row: '20', isLinked: true, unit: 'px', size: 20 },\n });\n const c = { id: eid(), elType: 'container', settings: s, elements: kinder };\n if (innen) { c.isInner = true; c.isLocked = true; }\n return c;\n};\n\nfunction elementorBauen() {\n const wurzel = [];\n if (a.kurzantwort) {\n wurzel.push(behaelter([textWidget(\n `<div class=\"skrift-kurzantwort\"><p>${a.kurzantwort}</p></div>`)]));\n }\n const html = String(a.content_html || '');\n const stellen = [];\n const re2 = /<h2[ >]/g;\n let mm;\n while ((mm = re2.exec(html)) !== null) stellen.push(mm.index);\n const bloecke = [];\n if (!stellen.length) {\n if (html.trim()) bloecke.push(html.trim());\n } else {\n if (stellen[0] > 0 && html.slice(0, stellen[0]).trim()) bloecke.push(html.slice(0, stellen[0]).trim());\n stellen.forEach((s, i) => {\n const ende = i + 1 < stellen.length ? stellen[i + 1] : html.length;\n const b = html.slice(s, ende).trim();\n if (b) bloecke.push(b);\n });\n }\n bloecke.forEach(b => wurzel.push(behaelter([textWidget(b)])));\n\n if (meta.faq.length) {\n const items = [], kinder = [];\n meta.faq.forEach(f => {\n items.push({ item_title: f.frage, _id: eid() });\n kinder.push(behaelter([textWidget(`<p>${f.antwort || ''}</p>`)], true));\n });\n wurzel.push(behaelter([\n textWidget(`<h2>${konf.faq_ueberschrift || 'Häufige Fragen'}</h2>`),\n { id: eid(), elType: 'widget', widgetType: 'nested-accordion',\n settings: { items, faq_schema: 'yes', default_state: 'all_collapsed' },\n elements: kinder },\n ]));\n }\n return wurzel;\n}\n\nif (konf.elementor_ausgabe) {\n meta._elementor_data = JSON.stringify(elementorBauen());\n meta._elementor_edit_mode = 'builder';\n meta._elementor_template_type = 'wp-post';\n}\n\nconst body = {\n title: a.titel,\n slug: s.slug,\n content: a.content_html,\n status: 'draft', // harte Vorgabe: nie automatisch veroeffentlichen\n categories: [s.kategorie_id],\n meta,\n};\nif (a.auszug) body.excerpt = a.auszug;\n\nreturn [{ json: {\n ...s,\n vorhanden: !!treffer,\n post_id: treffer ? treffer.id : null,\n alter_status: treffer ? treffer.status : null,\n wp_url: treffer\n ? `${$('Konfiguration').first().json.wp_base}/wp-json/wp/v2/posts/${treffer.id}`\n : `${$('Konfiguration').first().json.wp_base}/wp-json/wp/v2/posts`,\n wp_body: JSON.stringify(body),\n}}];\n"
}, },
"type": "n8n-nodes-base.code", "type": "n8n-nodes-base.code",
"typeVersion": 2, "typeVersion": 2,
@@ -833,7 +833,7 @@
3760, 3760,
240 240
], ],
"id": "5712410d-e1ce-4147-a575-df8147fcdf86", "id": "64401c03-a0e6-493d-be07-7054964fa3d7",
"name": "WordPress-Body bauen" "name": "WordPress-Body bauen"
}, },
{ {
@@ -863,7 +863,7 @@
3980, 3980,
240 240
], ],
"id": "7d1c919c-bb1e-4aff-b10b-ba9703dd66d7", "id": "652a752f-aaf2-4169-bf1f-5e5c246b0575",
"name": "Beitrag anlegen oder aktualisieren", "name": "Beitrag anlegen oder aktualisieren",
"credentials": { "credentials": {
"httpBasicAuth": { "httpBasicAuth": {
@@ -886,7 +886,7 @@
4200, 4200,
240 240
], ],
"id": "553a5836-dd1b-44c5-9146-453e2fbf6bb6", "id": "5c89708b-21a3-466b-a142-90ca5776cabb",
"name": "Ergebnis pruefen" "name": "Ergebnis pruefen"
}, },
{ {
@@ -917,7 +917,7 @@
4420, 4420,
240 240
], ],
"id": "ec545d25-2c80-4b3b-9b7b-dd30b61990d8", "id": "617d82a6-7c93-42df-8aa3-5345ea5e5a11",
"name": "Cache leeren", "name": "Cache leeren",
"credentials": { "credentials": {
"httpBasicAuth": { "httpBasicAuth": {
@@ -937,7 +937,7 @@
4640, 4640,
240 240
], ],
"id": "db87877c-313a-434a-a1ee-fe0f0644ad86", "id": "e930894f-0a23-4b6f-8672-539fddded17a",
"name": "Importergebnis merken" "name": "Importergebnis merken"
}, },
{ {
@@ -951,9 +951,9 @@
4860, 4860,
420 420
], ],
"id": "06918dbc-a5cc-4598-ab4f-12963601622a", "id": "b52ef44c-0a99-428f-ac87-6f23ad851dcc",
"name": "Pause Rate Limit", "name": "Pause Rate Limit",
"webhookId": "5be31916-7738-453d-b4a8-c3f58380d328" "webhookId": "601a717a-a791-4885-9ae4-6211c4042840"
}, },
{ {
"parameters": { "parameters": {
@@ -966,7 +966,7 @@
}, },
"conditions": [ "conditions": [
{ {
"id": "38a37fb2-cd95-46ec-bdde-60a18b572c1c", "id": "3479c179-c254-4e07-bbe3-139c2232cb41",
"leftValue": "={{ $('Konfiguration').first().json.bild_aktiv === true && !Number($json.featured_media) }}", "leftValue": "={{ $('Konfiguration').first().json.bild_aktiv === true && !Number($json.featured_media) }}",
"rightValue": "", "rightValue": "",
"operator": { "operator": {
@@ -987,7 +987,7 @@
4860, 4860,
240 240
], ],
"id": "04b068e9-ed31-4dcc-8970-04daebd61b7f", "id": "ac9b1b62-9967-4bbf-b437-5b6d9d9c4f03",
"name": "Beitragsbild fehlt?" "name": "Beitragsbild fehlt?"
}, },
{ {
@@ -1012,7 +1012,7 @@
5080, 5080,
120 120
], ],
"id": "e11b4f49-0c55-4392-861c-d66a9762a623", "id": "fe7baabb-0017-4539-b367-78b55a7b59a4",
"name": "Bilddaten laden", "name": "Bilddaten laden",
"credentials": { "credentials": {
"httpHeaderAuth": { "httpHeaderAuth": {
@@ -1035,7 +1035,7 @@
5300, 5300,
120 120
], ],
"id": "ebe17d0b-3139-4aca-85cd-b5345c550c1b", "id": "7b14c694-e412-4a82-ac54-3dc038492daa",
"name": "Bildprompt bauen" "name": "Bildprompt bauen"
}, },
{ {
@@ -1049,7 +1049,7 @@
}, },
"conditions": [ "conditions": [
{ {
"id": "6d7b129e-23c1-40b4-949d-0b8b628a4984", "id": "9cc14322-cbf9-4d63-8032-75f3a326e208",
"leftValue": "={{ !!$json.bild_prompt }}", "leftValue": "={{ !!$json.bild_prompt }}",
"rightValue": "", "rightValue": "",
"operator": { "operator": {
@@ -1070,7 +1070,7 @@
5520, 5520,
120 120
], ],
"id": "583dad0b-2fec-4bfb-8c50-32edd965c782", "id": "ac5412be-fd49-4ae6-b727-54bb8a5e7b5b",
"name": "Bildprompt vorhanden?" "name": "Bildprompt vorhanden?"
}, },
{ {
@@ -1100,7 +1100,7 @@
5740, 5740,
40 40
], ],
"id": "3d2143cc-e937-4dca-bff4-1705102f41a2", "id": "f4a67217-eac5-4292-b48f-97dd852db890",
"name": "Bild erzeugen", "name": "Bild erzeugen",
"credentials": { "credentials": {
"httpHeaderAuth": { "httpHeaderAuth": {
@@ -1124,7 +1124,7 @@
5740, 5740,
260 260
], ],
"id": "bff3ef3d-9be6-4b71-ad55-7de2a9244440", "id": "d0507f71-febb-4770-8879-289cd5db8bde",
"name": "Fehler Bild", "name": "Fehler Bild",
"onError": "continueRegularOutput" "onError": "continueRegularOutput"
}, },
@@ -1139,7 +1139,7 @@
5960, 5960,
40 40
], ],
"id": "d44f9381-0b68-4872-bd92-cb14cab24dfb", "id": "0a26c40e-f669-447c-9873-b4658a0caa75",
"name": "Bild als Datei" "name": "Bild als Datei"
}, },
{ {
@@ -1174,7 +1174,7 @@
6180, 6180,
40 40
], ],
"id": "47c9c7e9-1f65-4434-b4b0-05ce2577a98b", "id": "1f93892d-ca03-480f-80d4-d3e9136ba6be",
"name": "Bild in Mediathek", "name": "Bild in Mediathek",
"credentials": { "credentials": {
"httpBasicAuth": { "httpBasicAuth": {
@@ -1208,7 +1208,7 @@
6400, 6400,
40 40
], ],
"id": "85b0be75-4b66-4af7-83a0-a00d5b9fcbd9", "id": "df178293-f772-47db-bd70-5ebbbfecc99b",
"name": "Beitragsbild setzen", "name": "Beitragsbild setzen",
"credentials": { "credentials": {
"httpBasicAuth": { "httpBasicAuth": {
@@ -1231,7 +1231,7 @@
6620, 6620,
40 40
], ],
"id": "0de4b676-fd3c-4438-aeb5-d279effc2bc8", "id": "7acb87e1-6d08-4068-86e1-148e66e30a15",
"name": "Bild gemerkt" "name": "Bild gemerkt"
}, },
{ {
@@ -1245,7 +1245,7 @@
900, 900,
80 80
], ],
"id": "6e3219cb-c2be-44d0-b2d0-6b182329ccc9", "id": "de688426-8e55-4f3e-8fa0-6b6c536a645e",
"name": "Ergebnisse sammeln" "name": "Ergebnisse sammeln"
}, },
{ {
@@ -1270,7 +1270,7 @@
1120, 1120,
80 80
], ],
"id": "b368e64d-9aac-4cde-be95-4d061e76bd37", "id": "c4d40ae3-0c2a-4c85-afb2-8e35e3b7a910",
"name": "Statustabelle lesen", "name": "Statustabelle lesen",
"credentials": { "credentials": {
"httpHeaderAuth": { "httpHeaderAuth": {
@@ -1290,7 +1290,7 @@
1340, 1340,
80 80
], ],
"id": "6fb9c69b-f398-4cc3-a1e5-633f91c24923", "id": "ef884157-2d8f-4108-8413-f8a44d30377c",
"name": "Statustabelle fortschreiben" "name": "Statustabelle fortschreiben"
}, },
{ {
@@ -1304,7 +1304,7 @@
}, },
"conditions": [ "conditions": [
{ {
"id": "04e69285-96fe-4313-9a53-22c17b0a1923", "id": "88098264-cf81-4b80-8dd6-24e2b69ac9f6",
"leftValue": "={{ $json.ueberspringen }}", "leftValue": "={{ $json.ueberspringen }}",
"rightValue": "", "rightValue": "",
"operator": { "operator": {
@@ -1325,7 +1325,7 @@
1560, 1560,
80 80
], ],
"id": "5049ff31-926b-4c6c-a728-ba463fdd565b", "id": "680f0cda-2253-4542-a268-b5789d36e3ba",
"name": "Gab es Importe?" "name": "Gab es Importe?"
}, },
{ {
@@ -1355,7 +1355,7 @@
1780, 1780,
160 160
], ],
"id": "73f50d9b-9334-4f6c-a702-ced32babc406", "id": "e3c52d54-c52c-4afb-ba79-4de6fcbe6668",
"name": "Statustabelle schreiben", "name": "Statustabelle schreiben",
"credentials": { "credentials": {
"httpHeaderAuth": { "httpHeaderAuth": {
@@ -1379,7 +1379,7 @@
1780, 1780,
340 340
], ],
"id": "652ccbd8-38df-40b6-8cf9-43bd9ff9ba7c", "id": "fe8b8aca-18cb-4111-858f-61863c8b411f",
"name": "Fehler Statustabelle", "name": "Fehler Statustabelle",
"onError": "continueRegularOutput" "onError": "continueRegularOutput"
}, },
@@ -1394,7 +1394,7 @@
2000, 2000,
80 80
], ],
"id": "80192868-178f-4eca-a313-073f06bf3ce3", "id": "557665ff-7190-485b-bbba-b001c50d04bf",
"name": "Meldung formulieren" "name": "Meldung formulieren"
}, },
{ {
@@ -1412,7 +1412,7 @@
2220, 2220,
80 80
], ],
"id": "c81c485d-8ac3-4c5c-bf3e-e2934a349f32", "id": "0d7c548b-73ac-49a6-a2cd-0c4791507058",
"name": "Benachrichtigung", "name": "Benachrichtigung",
"disabled": true, "disabled": true,
"notes": "SMTP-Credential zuweisen, Absender eintragen, dann aktivieren." "notes": "SMTP-Credential zuweisen, Absender eintragen, dann aktivieren."