api_base = $base . '/api/v1'; $this->owner = $owner; $this->repo = $repo; $this->token = $token; } // ── API ─────────────────────────────────────────────────────────────────── private function api_get( $endpoint ) { $url = $this->api_base . $endpoint; $args = array( 'timeout' => 20, 'headers' => array( 'Accept' => 'application/json' ), ); if ( $this->token ) { $args['headers']['Authorization'] = 'token ' . $this->token; } $resp = wp_remote_get( $url, $args ); if ( is_wp_error( $resp ) ) { return $resp; } $code = wp_remote_retrieve_response_code( $resp ); if ( 200 !== $code ) { return new WP_Error( 'api_error', 'Gitea antwortet mit Status ' . $code . ' – URL: ' . $url ); } $body = json_decode( wp_remote_retrieve_body( $resp ), true ); if ( JSON_ERROR_NONE !== json_last_error() ) { return new WP_Error( 'json_error', 'Ungültige JSON-Antwort von: ' . $url ); } return $body; } // ── Öffentliche Methoden ────────────────────────────────────────────────── public function list_pages() { $endpoint = '/repos/' . rawurlencode( $this->owner ) . '/' . rawurlencode( $this->repo ) . '/wiki/pages?limit=50'; $result = $this->api_get( $endpoint ); if ( is_wp_error( $result ) ) { return $result; } if ( ! is_array( $result ) ) { return new WP_Error( 'invalid_response', 'Ungültige API-Antwort.' ); } $pages = array(); foreach ( $result as $page ) { if ( ! is_array( $page ) ) { continue; } $last = ''; if ( isset( $page['last_commit']['created'] ) ) { $last = $page['last_commit']['created']; } $pages[] = array( 'title' => isset( $page['title'] ) ? $page['title'] : '', 'last_updated' => $last, ); } return $pages; } public function get_page( $page_name ) { $endpoint = '/repos/' . rawurlencode( $this->owner ) . '/' . rawurlencode( $this->repo ) . '/wiki/page/' . rawurlencode( $page_name ); $result = $this->api_get( $endpoint ); if ( is_wp_error( $result ) ) { return $result; } if ( ! is_array( $result ) ) { return new WP_Error( 'invalid_response', 'Ungültige Seitenantwort für: ' . $page_name ); } $markdown = ''; if ( ! empty( $result['content_base64'] ) ) { $markdown = base64_decode( $result['content_base64'] ); // phpcs:ignore } if ( empty( $markdown ) && ! empty( $result['content'] ) ) { $markdown = $result['content']; } $title = isset( $result['title'] ) ? $result['title'] : $page_name; return array( 'title' => $title, 'content' => self::markdown_to_html( $markdown ), 'raw' => $markdown, ); } public function import_all( $wiki_id, $skip_pages = array( 'Home', '_Sidebar' ), $update_existing = false ) { $log = array( 'imported' => 0, 'updated' => 0, 'skipped' => 0, 'errors' => array() ); $pages = $this->list_pages(); if ( is_wp_error( $pages ) ) { $log['errors'][] = $pages->get_error_message(); return $log; } foreach ( $pages as $p ) { $title = $p['title']; if ( in_array( $title, $skip_pages, true ) ) { $log['skipped']++; continue; } $existing = get_posts( array( 'post_type' => 'wmw_article', 'post_status' => 'any', 'title' => $title, 'posts_per_page' => 1, 'meta_query' => array( array( 'key' => '_wmw_wiki_id', 'value' => $wiki_id ), ), ) ); if ( $existing && ! $update_existing ) { $log['skipped']++; continue; } $page_data = $this->get_page( $title ); if ( is_wp_error( $page_data ) ) { $log['errors'][] = 'Fehler bei "' . $title . '": ' . $page_data->get_error_message(); continue; } $post_data = array( 'post_type' => 'wmw_article', 'post_title' => $page_data['title'], 'post_content' => $page_data['content'], 'post_status' => 'publish', ); if ( $existing && $update_existing ) { $post_data['ID'] = $existing[0]->ID; $result = wp_update_post( $post_data, true ); if ( ! is_wp_error( $result ) ) { $log['updated']++; } } else { $result = wp_insert_post( $post_data, true ); if ( ! is_wp_error( $result ) ) { $log['imported']++; } } if ( is_wp_error( $result ) ) { $log['errors'][] = 'WP-Fehler bei "' . $title . '": ' . $result->get_error_message(); continue; } update_post_meta( $result, '_wmw_wiki_id', absint( $wiki_id ) ); update_post_meta( $result, '_wmw_gitea_source', $this->api_base . '/repos/' . rawurlencode( $this->owner ) . '/' . rawurlencode( $this->repo ) . '/wiki/page/' . rawurlencode( $title ) ); $auto_cat = self::guess_category( $title ); if ( $auto_cat ) { $term = term_exists( $auto_cat, 'wmw_category' ); if ( ! $term ) { $term = wp_insert_term( $auto_cat, 'wmw_category' ); } if ( ! is_wp_error( $term ) ) { $term_id = is_array( $term ) ? (int) $term['term_id'] : (int) $term; wp_set_object_terms( $result, $term_id, 'wmw_category', true ); } } } return $log; } // ── Markdown → HTML ─────────────────────────────────────────────────────── public static function markdown_to_html( $md ) { if ( empty( $md ) ) { return ''; } // Gitea [[Wiki-Links]] $md = preg_replace( '/\[\[([^\]|]+)\|([^\]]+)\]\]/', '[$2]($1)', $md ); $md = preg_replace( '/\[\[([^\]]+)\]\]/', '[$1]($1)', $md ); // Code-Blöcke sichern $code_blocks = array(); $md = preg_replace_callback( '/```(\w*)\n(.*?)```/s', function ( $m ) use ( &$code_blocks ) { $lang = ''; if ( ! empty( $m[1] ) ) { $lang = ' class="language-' . esc_attr( $m[1] ) . '"'; } $token = '%%CB_' . count( $code_blocks ) . '%%'; $code_blocks[ $token ] = '
' . esc_html( $m[2] ) . '';
return $token;
},
$md
);
// Inline Code
$md = preg_replace( '/`([^`\n]+)`/', '$1', $md );
// Überschriften
$md = preg_replace( '/^######\s+(.+)$/m', '$1', $md ); $md = preg_replace( '/^(\-{3,}|\*{3,}|_{3,})$/m', '
' . nl2br( $block ) . "
\n"; } } // Code-Blöcke zurücksetzen foreach ( $code_blocks as $token => $code_html ) { $html = str_replace( $token, $code_html, $html ); } return $html; } /** @param array $m */ private static function cb_table( $m ) { $rows = array_filter( explode( "\n", trim( $m[0] ) ) ); $html = '