From 8ac7438b186d6157c429b5e58244c6b09e3d3b1e Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 22 Dec 2025 11:15:31 +0000 Subject: [PATCH] =?UTF-8?q?Dateien=20nach=20=E2=80=9Ed2s-discourse-map?= =?UTF-8?q?=E2=80=9C=20hochladen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- d2s-discourse-map/d2s-discourse-map.php | 275 ++++++++++++++++++++++++ d2s-discourse-map/d2s-discourse-map.zip | Bin 0 -> 3655 bytes 2 files changed, 275 insertions(+) create mode 100644 d2s-discourse-map/d2s-discourse-map.php create mode 100644 d2s-discourse-map/d2s-discourse-map.zip diff --git a/d2s-discourse-map/d2s-discourse-map.php b/d2s-discourse-map/d2s-discourse-map.php new file mode 100644 index 0000000..6c7c289 --- /dev/null +++ b/d2s-discourse-map/d2s-discourse-map.php @@ -0,0 +1,275 @@ + 'logbuch', + 'category_map' => ['privatlog' => 'privatlog'], + ], false); + } + } + + public function add_menu() { + add_options_page( + 'Discourse Tag Automapper', + 'Discourse Tag Automapper', + 'manage_options', + 'd2s-discourse-tag-automapper', + [$this, 'render_page'] + ); + } + + private function sanitize_tag($s) { + $s = is_string($s) ? trim($s) : ''; + $s = strtolower($s); + $s = str_replace([',',';'], '', $s); + $s = preg_replace('/\s+/', '-', $s); + $s = preg_replace('/[^a-z0-9\-_]/', '', $s); + return $s; + } + + private function handle_save() { + if (!current_user_can('manage_options')) return; + if (!isset($_POST['d2s_discourse_tag_nonce']) || !wp_verify_nonce($_POST['d2s_discourse_tag_nonce'], 'd2s_discourse_tag_save')) return; + + $fallback = isset($_POST['fallback_tag']) ? $this->sanitize_tag(wp_unslash($_POST['fallback_tag'])) : ''; + $raw_map = isset($_POST['category_map']) ? (array) $_POST['category_map'] : []; + + $map = []; + foreach ($raw_map as $cat_id => $tag) { + $tag = $this->sanitize_tag(wp_unslash($tag)); + $cat_id = intval($cat_id); + if ($cat_id > 0 && $tag !== '') { + $term = get_term($cat_id, 'category'); + if ($term && !is_wp_error($term)) $map[$term->slug] = $tag; + } + } + + update_option(self::OPTION, [ + 'fallback_tag' => $fallback !== '' ? $fallback : 'logbuch', + 'category_map' => $map, + ], false); + + add_settings_error('d2s_discourse_tag_automapper', 'saved', 'Einstellungen gespeichert.', 'updated'); + } + + public function render_page() { + if ($_SERVER['REQUEST_METHOD'] === 'POST') $this->handle_save(); + + $opt = get_option(self::OPTION); + $fallback = $opt['fallback_tag'] ?? 'logbuch'; + $map = (array)($opt['category_map'] ?? []); + + $cats = get_categories(['hide_empty' => false, 'orderby' => 'name', 'order' => 'ASC']); + + settings_errors('d2s_discourse_tag_automapper'); ?> +
+

Discourse Tag Automapper

+
+ + + + + + + + +

Kategorie → Discourse-Tag

+

Pro WP-Kategorie optional ein Discourse-Tag. Leer lassen = kein spezielles Tag → Fallback greift.

+ + + + + slug; + $current = $map[$slug] ?? ''; + ?> + + + + + + +
KategorieDiscourse-Tag
+ name); ?> +
Slug: (ID term_id); ?>)
+
+ +
+ + +
+
+ slug; + } + return $list; + } + + private function compute_tags_for_post($post) { + $opt = get_option(self::OPTION); + $fallback = $opt['fallback_tag'] ?? 'logbuch'; + $map = (array)($opt['category_map'] ?? []); + + $auto = $fallback; + $terms = get_the_terms($post, 'category'); + + if (!empty($terms) && !is_wp_error($terms)) { + usort($terms, fn($a,$b)=> strcmp($a->name, $b->name)); + foreach ($terms as $t) { + if (isset($map[$t->slug]) && $map[$t->slug] !== '') { $auto = $map[$t->slug]; break; } + } + } + + $tags = [$auto]; // kein Merge mit älteren Meta-Werten + $tags = array_map([$this, 'sanitize_tag'], $tags); + $tags = array_values(array_unique(array_filter($tags))); + + $this->log('[compute] post_id='.$post->ID.' cats='.wp_json_encode($this->get_post_categories_debug($post->ID)).' -> tags='.wp_json_encode($tags)); + return $tags; + } + + /* ===== ältere Filterpfade: falls deine Version sie nutzt ===== */ + + public function apply_mapping_to_params($params, $post) { + if (!$post instanceof WP_Post) return $params; + $tags = $this->compute_tags_for_post($post); + $params['tags'] = $tags; + $params['tag_names'] = $tags; + $this->log('[params] post_id='.$post->ID.' tags='.wp_json_encode($tags)); + return $params; + } + + /* ===== Späte/robuste Wege ===== */ + + public function apply_mapping_on_save($post_id, $post, $update) { + if (wp_is_post_revision($post_id)) return; + if ($post->post_type !== 'post') return; + + $tags = $this->compute_tags_for_post($post); + + update_post_meta($post_id, 'wpdc_discourse_tags', implode(',', $tags)); + update_post_meta($post_id, 'discourse_tags', implode(',', $tags)); + $this->log('[save_post] post_id='.$post_id.' tags='.wp_json_encode($tags)); + } + + public function apply_mapping_after_insert($post_id, $post, $update, $post_before) { + if ($post->post_type !== 'post') return; + $tags = $this->compute_tags_for_post($post); + update_post_meta($post_id, 'wpdc_discourse_tags', implode(',', $tags)); + update_post_meta($post_id, 'discourse_tags', implode(',', $tags)); + $this->log('[after_insert] post_id='.$post_id.' tags='.wp_json_encode($tags)); + } + + public function remember_post_on_publish($new_status, $old_status, $post) { + if (!$post instanceof WP_Post || $post->post_type !== 'post') return; + if ($new_status === 'publish' && $old_status !== 'publish') { + // ID 30s merken – reicht für den direkt anschließenden Publish-Request + set_transient(self::LAST_PUB_TX, intval($post->ID), 30); + $this->log('[remember] post_id='.$post->ID.' (publish transient gesetzt)'); + } + } + + public function apply_mapping_on_status_change($new_status, $old_status, $post) { + if (!$post instanceof WP_Post || $post->post_type !== 'post') return; + if ($new_status === 'publish' && $old_status !== 'publish') { + $this->apply_mapping_on_save($post->ID, $post, true); + $this->log('[status_change] post_id='.$post->ID.' '.$old_status.'→'.$new_status); + } + } + + /* ===== Final: Publish-Body patchen (garantiert im Request) ===== */ + + public function inject_tags_into_publish_body($body, $remote_post_type) { + // 1) Versuche $_REQUEST (falls die WP-Discourse-Version das setzt) + $post_id = isset($_REQUEST['post_id']) ? intval($_REQUEST['post_id']) : (isset($_REQUEST['post']) ? intval($_REQUEST['post']) : 0); + + // 2) Fallback: nimm die zuletzt veröffentlichte ID aus dem Transient + if (!$post_id) { + $post_id = intval(get_transient(self::LAST_PUB_TX)); + if ($post_id) { + $this->log('[publish_body] fallback via transient post_id='.$post_id); + } + } + + $post = $post_id ? get_post($post_id) : null; + + if ($post instanceof WP_Post && $post->post_type === 'post') { + $tags = $this->compute_tags_for_post($post); // frisch, aus den aktuellen Kategorien + if (!empty($tags)) { + $body['tags'] = $tags; + $body['tag_names'] = $tags; + $this->log('[publish_body] post_id='.$post->ID.' type='.$remote_post_type.' cats='.wp_json_encode($this->get_post_categories_debug($post->ID)).' tags='.wp_json_encode($tags)); + } else { + $this->log('[publish_body] post_id='.$post->ID.' type='.$remote_post_type.' tags=[] (leer)'); + } + } else { + $this->log('[publish_body] kein gültiger Post-Kontext'); + } + return $body; + } + +private function log($line) { + $file = trailingslashit(WP_CONTENT_DIR) . self::LOGFILE; + if (file_exists($file) && filesize($file) > 200 * 1024) { + @unlink($file); // rotate + } + $date = gmdate('Y-m-d H:i:s'); + @file_put_contents($file, '['.$date.' UTC] '.$line.PHP_EOL, FILE_APPEND); +} + + public static function on_uninstall() { + delete_option(self::OPTION); + // Log bleibt liegen + } +} + +new D2S_Discourse_Tag_Automapper(); +register_uninstall_hook(__FILE__, ['D2S_Discourse_Tag_Automapper', 'on_uninstall']); \ No newline at end of file diff --git a/d2s-discourse-map/d2s-discourse-map.zip b/d2s-discourse-map/d2s-discourse-map.zip new file mode 100644 index 0000000000000000000000000000000000000000..964323e87da37c6a74bf7fba970df29e1d3bb9dd GIT binary patch literal 3655 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 Na{TMVe{m5H?_az~=l}o! literal 0 HcmV?d00001