From fddaf8e8d00e2b9813b22796dabb4e67db5450c5 Mon Sep 17 00:00:00 2001 From: Remi Peyronnet Date: Sun, 6 Nov 2022 18:25:18 +0100 Subject: [PATCH 1/2] Various improvements (see PR) --- jekyll-export-cli.php | 44 +++- jekyll-exporter.php | 465 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 466 insertions(+), 43 deletions(-) diff --git a/jekyll-export-cli.php b/jekyll-export-cli.php index 33fb36d7..7c12b6dd 100644 --- a/jekyll-export-cli.php +++ b/jekyll-export-cli.php @@ -16,12 +16,54 @@ * * Must be run in the wordpress-to-jekyll-exporter/ directory. */ -require '../../../wp-load.php'; + +// Uncomment for extra replace options + +$wordpress_path = "../../../"; +//$wordpress_path = "/home/wordpress/"; + +require $wordpress_path . 'wp-load.php'; require_once 'jekyll-exporter.php'; // Ensure plugin is "activated". +$config["site_url"] = "https://www.mywebsite.fr/"; + +$config["extra_remove_site_url"] = $config["site_url"]; // Will remove site url to get relative URLs +$config['extra_code'] = true; // Will retrieve lang and protect pre/code +$config['extra_img_style'] = true; // Will retrieve style from image +$config['extra_tag_spoiler'] = true; // Will convert spoiler tags + +//$config['force_dest_dir'] = "/dest-path/"; // "_export/"; // Force destination directory to relative one (without temp folder, will deactivate zip) + + if ( php_sapi_name() !== 'cli' ) { wp_die( 'Jekyll export must be run via the command line or administrative dashboard.' ); } +add_filter( 'the_content', function($contents) { + + if ($config["extra_remove_site_url"]) $contents = preg_replace("!${$config['extra_remove_site_url']}!",'', $contents); + + if ($config['extra_code']) { + $contents = preg_replace('!]*crayon-inline[^>]*>([^<]*)!','\1', $contents); + $contents = preg_replace('!class="lang:default!','class="', $contents); + $contents = preg_replace('!class="lang:!','class="language-', $contents); + $contents = preg_replace('!]*)>!','', $contents); + $contents = preg_replace('!!','', $contents); + $contents = preg_replace('!]*)>!','
', $contents);
+		$contents = preg_replace('!]*>!','
', $contents); + } + if ($config['extra_img_style']) { + $contents = preg_replace('!(]*alignright[^>]*/>)!','\1{: .img-right}', $contents); + $contents = preg_replace('!(]*aligncenter[^>]*/>)!','\1{: .img-center}', $contents); + $contents = preg_replace('!(]*aligncenter[^>]*/>)!','\1{: .img-center}', $contents); + } + if ($config['extra_tag_spoiler']) { + $contents = preg_replace('!\[su_spoiler title="([^"]*)" [^\]]*\]!',"
\\1", $contents); + $contents = preg_replace('!\[/su_spoiler\]!',"
", $contents); + } + + return $contents; +}); + $jekyll_export = new Jekyll_Export(); $jekyll_export->export(); diff --git a/jekyll-exporter.php b/jekyll-exporter.php index bcd6de6f..8ece9ea1 100644 --- a/jekyll-exporter.php +++ b/jekyll-exporter.php @@ -35,6 +35,32 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +// Extra options + +$config = array(); + +// $config["site_url"] = "https://mywebsite.fr/"; // Destination site URL +// $config['force_dest_dir'] = "_export/"; // Force destination directory to relative one (without temp folder, will deactivate zip) + +$config['forceHtml'] = false; // true; // Force export to HTML + +// Skip some parts of the script that you do not need +// $config['skip_options'] = true; +// $config['skip_posts'] = true; +// $config['skip_uploads'] = true; +// $config['skip_comments'] = true; + +$config['comment_target_data'] = true; // Export comments as data files +// $config['comment_target_pages'] = true; // Export comments as jekyll pages +// $config['comment_target_github'] = true; // Export comments to GitHub discussions (for use with Giscus) + +// To export comments to GitHub for Giscus (https://giscus.app) +// $config['gh_token'] = "gho_xxxx"; // Get token from command line: gh auth token +// $config['gh_repo'] = "R_kgDOIVZ3BQ"; // Get values from giscus config page +// $config['category_id'] = "DIC_kwDOIVZ3Bc4CSRMx"; // Get values from giscus config page + + + if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) { wp_die( 'Jekyll Export requires PHP 5.3 or later' ); } @@ -46,6 +72,102 @@ use League\HTMLToMarkdown\Converter\TableConverter; use Symfony\Component\Yaml\Yaml; + +// https://gist.github.com/dunglas/05d901cb7560d2667d999875322e690a +function graphql_query(string $endpoint, string $query, array $variables = [], ?string $token = null): array +{ + $headers = ['Content-Type: application/json', 'User-Agent: Dunglas\'s minimal GraphQL client']; + if (null !== $token) { + $headers[] = "Authorization: bearer $token"; + } + + if (false === $data = @file_get_contents($endpoint, false, stream_context_create([ + 'http' => [ + 'method' => 'POST', + 'header' => $headers, + 'content' => json_encode(['query' => $query, 'variables' => $variables]), + ] + ]))) { + $error = error_get_last(); + throw new \ErrorException($error['message'], $error['type']); + } + + return json_decode($data, true); +} + + +function github_query(string $query, array $variables = []) { + global $config; + $ret = null; + if ($config['gh_token']) { + $ret = graphql_query('https://api.github.com/graphql', $query, $variables, $config['gh_token']); + sleep(5); // Delay because Github does not like mutations too quick + } + return $ret; +} + + +function gh_create_discussion($title, $content) { + global $config; + + $query = <<<'GRAPHQL' + mutation MyMutation($repositoryId: ID!, $title: String!, $body: String!, $categoryId: ID!) { + createDiscussion(input: { + repositoryId: $repositoryId, + title: $title, + body: $body, + categoryId: $categoryId + }) + { discussion { id } } } + GRAPHQL; + + $vars = [ + 'repositoryId' => $config['gh_repo'], + 'title' => $title, + 'body' => $content, + 'categoryId' => $config['category_id'] + ]; + + $r = github_query($query, $vars); + + $discussion_id = $r['data']['createDiscussion']['discussion']['id'] ?? null; + + if ($discussion_id == null) { var_dump(">>> Discussion", $query, $vars, $r, $discussion_id); } + + return $discussion_id; +} + + +function gh_create_discussion_comment($discussionId, $content, $parent_comment = null) { + global $config; + + $query = <<<'GRAPHQL' + mutation MyMutation($discussionId: ID!, $body: String!, $replyToId: ID ) { + addDiscussionComment( + input: { + discussionId: $discussionId, + body: $body, + replyToId: $replyToId + }) + { comment { id }} + } + GRAPHQL; + + $vars = [ + 'discussionId' => $discussionId, + 'body' => $content, + 'replyToId' => $parent_comment + ]; + + $r = github_query($query, $vars); + + $comment_id = $r['data']['addDiscussionComment']['comment']['id'] ?? null; + + //if (!$comment_id) { var_dump(">> Comment", $query, $vars, $r); } + + return $comment_id; +} + /** * Class Jekyll_Export * @@ -57,6 +179,9 @@ */ class Jekyll_Export { + public $gh_discussions = array(); // wordpress id => github id + public $gh_comments = array(); // wordpress id => github id + /** * Strings to strip from option keys on export * @@ -125,7 +250,7 @@ function get_posts() { } $posts = array(); - $post_types = apply_filters( 'jekyll_export_post_types', array( 'post', 'page', 'revision' ) ); + $post_types = apply_filters( 'jekyll_export_post_types', array( 'post', 'page' /*, 'revision'*/ ) ); /** * WordPress style rules don't let us interpolate a string before passing it to @@ -149,28 +274,43 @@ function get_posts() { function convert_meta( $post ) { $output = array( - 'id' => $post->ID, + 'post_id' => $post->ID, 'title' => get_the_title( $post ), 'date' => get_the_date( 'c', $post ), + 'last_modified_at' => get_the_modified_date( 'c', $post ), 'author' => get_userdata( $post->post_author )->display_name, 'excerpt' => $post->post_excerpt, 'layout' => get_post_type( $post ), 'guid' => $post->guid, + 'slug' => $post->post_name, ); // Preserve exact permalink, since Jekyll doesn't support redirection. - if ( 'page' !== $post->post_type ) { + $ignore_permalink = array(); // array('page') + if ( !in_array($post->post_type, $ignore_permalink) ) { $output['permalink'] = str_replace( home_url(), '', get_permalink( $post ) ); } // Convert traditional post_meta values, hide hidden values. + $ignore_list = array( + '_*', + 'ocean_*', + 'classic-editor-remember', + 'osh_disable_topbar_sticky', + 'osh_disable_header_sticky', + 'osh_sticky_header_style', + 'ampforwp-amp-on-off', + ); + foreach ( get_post_custom( $post->ID ) as $key => $value ) { - if ( substr( $key, 0, 1 ) === '_' ) { - continue; + $ignore = false; + foreach ($ignore_list as $ignore_item) { + if (fnmatch($ignore_item, $key)) { $ignore = true; } } - $output[ $key ] = $value; + if (is_array($value) && (count($value) == 1)) { $value = $value[0]; } + if (!$ignore) $output[ $key ] = $value; } $post_thumbnail_id = get_post_thumbnail_id( $post ); @@ -198,27 +338,66 @@ function convert_terms( $post ) { $output = array(); foreach ( get_taxonomies( - array( + /*array( 'object_type' => array( get_post_type( $post ) ), - ) + )*/ ) as $tax ) { $terms = get_the_terms( $post, $tax ); - // Convert tax name for Jekyll. - switch ( $tax ) { - case 'post_tag': - $tax = 'tags'; - break; - case 'category': - $tax = 'categories'; - break; - } + if ($terms != false) { + // Convert tax name for Jekyll. + switch ( $tax ) { + case 'post_tag': + $tax = 'tags'; + break; + case 'category': + $tax = 'categories'; + foreach ($terms as $key => $value) { + $tr_tax = wp_get_object_terms($value->term_id, 'term_translations'); + $translations = unserialize($tr_tax[0]->description); + $cat_fr_id = $translations['fr']; + if ($cat_fr_id > 0) { + $cat_fr = get_term($cat_fr_id + 0); + $terms[$key] = $cat_fr; + } + } + break; + + // Extract Polylang + case 'language': + $tax = 'lang'; + if (count($terms) == 1) { + $terms = str_replace('pll_','', $terms[0]->slug); + } + break; + case 'post_language': + $tax = 'lang'; + if (count($terms) == 1) { + $terms = str_replace('pll_','', $terms[0]->slug); + } + break; + case 'post_translations': + $tax = 'lang-translations'; + if (count($terms) == 1) { + $output['lang-ref'] = $terms[0]->name; + $translations = unserialize($terms[0]->description); + foreach ($translations as $key => $value) { + $tr_post = get_post($value + 0); + $translations[$key] = $tr_post->post_name; + } + $terms = $translations; + } + break; + } - if ( 'post_format' === $tax ) { - $output['format'] = get_post_format( $post ); - } elseif ( is_array( $terms ) ) { - $output[ $tax ] = wp_list_pluck( $terms, 'name' ); + if ( 'post_format' === $tax ) { + $output['format'] = get_post_format( $post ); + } elseif ( is_array( $terms ) && ($tax != 'lang-translations')) { + $output[ $tax ] = wp_list_pluck( $terms, 'name' ); + } else { + $output[ $tax ] = $terms; + } } } @@ -232,8 +411,8 @@ function convert_terms( $post ) { * @param Post $post the post to Convert. * @return String the converted post content */ - function convert_content( $post ) { - + function convert_content( $post_content ) { + /* // check if jetpack markdown is available. if ( class_exists( 'WPCom_Markdown' ) ) { $wpcom_markdown_instance = WPCom_Markdown::get_instance(); @@ -245,15 +424,18 @@ function convert_content( $post ) { return $content; } } + */ - $content = apply_filters( 'the_content', $post->post_content ); + global $config; + + $content = apply_filters( 'the_content', $post_content ); $converter_options = apply_filters( 'jekyll_export_markdown_converter_options', array( 'header_style' => 'atx' ) ); $converter = new HtmlConverter( $converter_options ); $converter->getEnvironment()->addConverter( new TableConverter() ); $markdown = $converter->convert( $content ); - if ( strpos( $markdown, '[]: ' ) !== false ) { + if ( ( strpos( $markdown, '[]: ' ) !== false) || ($config['forceHtml']) ) { // faulty links; return plain HTML. $content = apply_filters( 'jekyll_export_html', $content ); $content = apply_filters( 'jekyll_export_content', $content ); @@ -269,12 +451,15 @@ function convert_content( $post ) { * Loop through and convert all posts to MD files with YAML headers */ function convert_posts() { - global $post; - - foreach ( $this->get_posts() as $post_id ) { + //global $post; // was causing the issue, php was mixing posts + + foreach ( $this->get_posts() as $post_id ) { $post = get_post( $post_id ); + setup_postdata( $post ); + //if ($post->ID != $post_id) var_dump($post); + $meta = array_merge( $this->convert_meta( $post ), $this->convert_terms( $post_id ) ); // remove falsy values, which just add clutter. @@ -284,14 +469,179 @@ function convert_posts() { } } + $content = $post->post_content; + $output = "---\n"; $output .= Yaml::dump( $meta ); $output .= "---\n\n"; - $output .= $this->convert_content( $post ); + $output .= $this->convert_content( $content ); $this->write( $output, $post ); } } + function convert_comment_github($header, $content, $post, $comment) { + global $config; + + $post_id = $post->ID; + + // Need to get meta of post + $meta = array_merge( $this->convert_meta( $post ), $this->convert_terms( $post_id ) ); + + // Create discussion if not already created (TODO: search github instead of cache) + if (!array_key_exists($post_id, $this->gh_discussions)) { + $discussion_id = gh_create_discussion($meta['permalink'], + get_the_excerpt($post) . "\n\n" . + $config["site_url"] . $meta['permalink']); + $this->gh_discussions[$post_id] = $discussion_id; + } + + // Get parent comment id (TODO: search github instead of cache) + $comment_parent_id = null; + if ($comment->comment_parent != '0') { + if (array_key_exists($comment->comment_parent, $this->gh_comments)) { + $comment_parent_id = $this->gh_comments[$comment->comment_parent]; + } else { + // parent comment should have been created before, not normal + printf("Parent comment not found:" . $comment->comment_parent); + } + } + + + $migrated_text = "_From **{$comment->comment_author}** on **{$comment->comment_date}** (Migrated from Wordpress):_\n\n"; + // Basic multilang comment support (fr only) + if ($meta['lang'] == 'fr') $migrated_text = "_De **{$comment->comment_author}** le **{$comment->comment_date}** (Migré depuis Wordpress):_\n\n"; + + $comment_id = gh_create_discussion_comment( + $this->gh_discussions[$post_id], + "\n" . $migrated_text . $content, + $comment_parent_id + ); + $this->gh_comments[$comment->comment_ID] = $comment_id; + } + + /** + * Loop through and convert all comments to MD files with YAML headers + */ + + function convert_comment($post, $comment) { + global $config; + + $comment_meta = array( + 'comment_ID' => $comment->comment_ID, + 'comment_author' => $comment->comment_author, + 'comment_author_url' => $comment->comment_author_url, + 'comment_date' => $comment->comment_date, // = '0000-00-00 00:00:00'; + 'comment_date_gmt' => $comment->comment_date_gmt, // = '0000-00-00 00:00:00'; + 'comment_type' => $comment->comment_type, + 'comment_parent' => $comment->comment_parent, + 'post_id' => $post->ID, + // Other comments metadata available (warning you may expose personal data) + // 'comment_author_email' => $comment->comment_author_email, + // 'comment_author_IP' => $comment->comment_author_IP, + // 'comment_karma' => $comment->comment_karma, + // 'comment_approved' => $comment->comment_approved, + // 'comment_agent' => $comment->comment_agent, + // 'user_id' => $user_id, + ); + + $header = "---\n"; + $header .= Yaml::dump( $comment_meta ); + $header .= "---\n\n"; + + $content = $this->convert_content( $comment->comment_content ); + + if ($config['comment_target_github']) { + $this->convert_comment_github($header, $content, $post, $comment); + } + + if ($config['comment_target_pages']) { + $this->write($header . $content, $post, $comment); + } + + $this->convert_comment_children($post, $comment->comment_ID); + } + + function convert_comment_children($post, $comment_parent) { + + $comments = get_comments(array( + 'post_id' => $post->ID, + 'type' => 'comment', + 'parent' => $comment_parent, + 'orderby'=>'comment_date', + 'order'=>'ASC' + )); + + foreach( $comments as $comment ) { + $this->convert_comment($post, $comment); + } + + } + + function convert_comment_data($post) { + + global $wp_filesystem; + + $comments = get_comments(array( + 'post_id' => $post->ID, + 'type' => 'comment', + 'orderby'=>'comment_date', + 'order'=>'ASC' + )); + + $comments_list = []; + + foreach( $comments as $comment ) { + $comment_data = [ + 'ID' => $comment->comment_ID, + 'post_id' => $post->ID, + 'author' => $comment->comment_author, + 'date' => $comment->comment_date, // = '0000-00-00 00:00:00'; + ]; + $comment_data['comment'] = $comment->comment_content; + if ($comment->comment_parent) $comment_data['parent'] = $comment->comment_parent; + if ($comment->comment_author_url) $comment_data['author_url'] = $comment->comment_author_url; + + $comments_list[] = $comment_data; + } + + if (count($comments_list) > 0) { + + $filename = '_data/comments/' . $post->post_name . '.yml'; + + $output = Yaml::dump( $comments_list ); + + $wp_filesystem->put_contents( $this->dir . $filename, $output); + } + + } + + + function convert_comments() { + global $wp_filesystem; + global $config; + + //global $post; // was causing the issue, php was mixing posts + + $ext = ($config['forceHtml']) ? '.html' : '.md'; + + $gql = ''; + + foreach ( $this->get_posts() as $post_id ) { + $post = get_post( $post_id ); + setup_postdata( $post ); + + // Convert to pages & github + if ($config['comment_target_pages'] || $config['comment_target_github']) { + $this->convert_comment_children($post, '0'); + } + + // Convert to data + if ($config['comment_target_data']) { + $this->convert_comment_data($post); + } + } + } + /** * Callback to modify the filesystem filter */ @@ -304,6 +654,7 @@ function filesystem_method_filter() { */ function init_temp_dir() { global $wp_filesystem; + global $config; add_filter( 'filesystem_method', array( &$this, 'filesystem_method_filter' ) ); @@ -311,33 +662,50 @@ function init_temp_dir() { // When on Azure Web App use %HOME%\temp\ to avoid weird default temp folder behavior. // For more information see https://github.com/projectkudu/kudu/wiki/Understanding-the-Azure-App-Service-file-system. + $temp_dir = ( getenv( 'WEBSITE_SITE_NAME' ) !== false ) ? ( getenv( 'HOME' ) . DIRECTORY_SEPARATOR . 'temp' ) : get_temp_dir(); $wp_filesystem->mkdir( $temp_dir ); $temp_dir = realpath( $temp_dir ) . DIRECTORY_SEPARATOR; $this->dir = $temp_dir . 'wp-jekyll-' . md5( time() ) . DIRECTORY_SEPARATOR; + if ($config['force_dest_dir']) $this->dir = $config['force_dest_dir']; $this->zip = $temp_dir . 'wp-jekyll.zip'; $wp_filesystem->mkdir( $this->dir ); $wp_filesystem->mkdir( $this->dir . '_posts/' ); + $wp_filesystem->mkdir( $this->dir . '_pages/' ); $wp_filesystem->mkdir( $this->dir . '_drafts/' ); - $wp_filesystem->mkdir( $this->dir . 'wp-content/' ); + //$wp_filesystem->mkdir( $this->dir . 'wp-content/' ); + if ($config['comment_target_pages']) { + $wp_filesystem->mkdir( $this->dir . '_comments/' ); + $wp_filesystem->mkdir( $this->dir . '_comments/_posts/' ); + $wp_filesystem->mkdir( $this->dir . '_comments/_pages/' ); + } + if ($config['comment_target_data']) { + $wp_filesystem->mkdir( $this->dir . '_data/' ); + $wp_filesystem->mkdir( $this->dir . '_data/comments/' ); + } } /** * Main function, bootstraps, converts, and cleans up */ function export() { + global $config; + do_action( 'jekyll_export' ); ob_start(); $this->init_temp_dir(); - $this->convert_options(); - $this->convert_posts(); - $this->convert_uploads(); - $this->zip(); + if (!$config['skip_options']) $this->convert_options(); + if (!$config['skip_posts']) $this->convert_posts(); + if (!$config['skip_uploads']) $this->convert_uploads(); + if (!$config['skip_comments']) $this->convert_comments(); ob_end_clean(); - $this->send(); - $this->cleanup(); + if (!$config['force_dest_dir']) { + $this->zip(); + $this->send(); + $this->cleanup(); + } } @@ -387,20 +755,33 @@ function convert_options() { * @param String $output the post content. * @param Post $post the Post object. */ - function write( $output, $post ) { + function write( $output, $post, $comment = null ) { global $wp_filesystem; + global $config; + + $ext = ($config['forceHtml']) ? '.html' : '.md'; - if ( ! in_array( get_post_status( $post ), array( 'publish', 'future' ), true ) ) { - $filename = '_drafts/' . sanitize_file_name( get_page_uri( $post->id ) . '-' . ( get_the_title( $post->id ) ) . '.md' ); + if ( get_post_type( $post ) === 'revision' ) { + $filename = '_revisions/' . sanitize_file_name( get_page_uri( $post ) . '-' . ( get_the_title( $post ) ) ); + } elseif ( ! in_array( get_post_status( $post ), array( 'publish', 'future' ), true ) ) { + $filename = '_drafts/' . sanitize_file_name( get_page_uri( $post ) . '-' . ( get_the_title( $post ) ) ); } elseif ( get_post_type( $post ) === 'page' ) { - $filename = get_page_uri( $post->id ) . '.md'; + $filename = '_pages/' . get_page_uri( $post ); } else { - $filename = '_' . get_post_type( $post ) . 's/' . gmdate( 'Y-m-d', strtotime( $post->post_date ) ) . '-' . sanitize_file_name( $post->post_name ) . '.md'; + $filename = '_' . get_post_type( $post ) . 's/' . gmdate( 'Y-m-d', strtotime( $post->post_date ) ) . '-' . sanitize_file_name( $post->post_name ); } $wp_filesystem->mkdir( $this->dir . dirname( $filename ) ); - $wp_filesystem->put_contents( $this->dir . $filename, $output ); + + if ($comment) { + $filename = "_comments/" . $filename; + $wp_filesystem->mkdir( $this->dir . dirname( $filename ) ); + $filename = $filename . '/' . gmdate( 'Y-m-d', strtotime( $comment->comment_date ) ) . '-' . sanitize_file_name( $comment->comment_type ) . '-' . $comment->comment_ID . '-' . sanitize_file_name( $comment->comment_author ); + $wp_filesystem->mkdir( $this->dir . dirname( $filename ) ); + } + + $wp_filesystem->put_contents( $this->dir . $filename . $ext, $output ); } /** From 9d14f0ad639478c52e5a8f80bab3c5b6966a1e91 Mon Sep 17 00:00:00 2001 From: Remi Peyronnet Date: Fri, 11 Nov 2022 12:44:53 +0100 Subject: [PATCH 2/2] First step in integrating PR comments --- .gitignore | 3 +- jekyll-export-cli.php | 44 ++++--------------------- jekyll-exporter.php | 76 +++++++++++++++++++++++++++++++++++-------- 3 files changed, 70 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index 80630e94..cc0e214b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ vendor/**/*.js vendor/**/*.css bin/* coverage.xml -composer.lock \ No newline at end of file +composer.lock +jekyll-export-local-conf.php \ No newline at end of file diff --git a/jekyll-export-cli.php b/jekyll-export-cli.php index 7c12b6dd..88aec54e 100644 --- a/jekyll-export-cli.php +++ b/jekyll-export-cli.php @@ -19,51 +19,19 @@ // Uncomment for extra replace options +// Customize here the path to wordpress installation if not in the wordpress plugin dir (ex: "/home/wordpress/") $wordpress_path = "../../../"; -//$wordpress_path = "/home/wordpress/"; + +$user_config = array(); +// You may customize user_config outside the source files with adding a jekyll-export-local-conf.php +if (file_exists('jekyll-export-local-conf.php')) { include 'jekyll-export-local-conf.php'; } require $wordpress_path . 'wp-load.php'; require_once 'jekyll-exporter.php'; // Ensure plugin is "activated". -$config["site_url"] = "https://www.mywebsite.fr/"; - -$config["extra_remove_site_url"] = $config["site_url"]; // Will remove site url to get relative URLs -$config['extra_code'] = true; // Will retrieve lang and protect pre/code -$config['extra_img_style'] = true; // Will retrieve style from image -$config['extra_tag_spoiler'] = true; // Will convert spoiler tags - -//$config['force_dest_dir'] = "/dest-path/"; // "_export/"; // Force destination directory to relative one (without temp folder, will deactivate zip) - - if ( php_sapi_name() !== 'cli' ) { wp_die( 'Jekyll export must be run via the command line or administrative dashboard.' ); } -add_filter( 'the_content', function($contents) { - - if ($config["extra_remove_site_url"]) $contents = preg_replace("!${$config['extra_remove_site_url']}!",'', $contents); - - if ($config['extra_code']) { - $contents = preg_replace('!]*crayon-inline[^>]*>([^<]*)!','\1', $contents); - $contents = preg_replace('!class="lang:default!','class="', $contents); - $contents = preg_replace('!class="lang:!','class="language-', $contents); - $contents = preg_replace('!]*)>!','', $contents); - $contents = preg_replace('!!','', $contents); - $contents = preg_replace('!]*)>!','
', $contents);
-		$contents = preg_replace('!]*>!','
', $contents); - } - if ($config['extra_img_style']) { - $contents = preg_replace('!(]*alignright[^>]*/>)!','\1{: .img-right}', $contents); - $contents = preg_replace('!(]*aligncenter[^>]*/>)!','\1{: .img-center}', $contents); - $contents = preg_replace('!(]*aligncenter[^>]*/>)!','\1{: .img-center}', $contents); - } - if ($config['extra_tag_spoiler']) { - $contents = preg_replace('!\[su_spoiler title="([^"]*)" [^\]]*\]!',"
\\1", $contents); - $contents = preg_replace('!\[/su_spoiler\]!',"
", $contents); - } - - return $contents; -}); - $jekyll_export = new Jekyll_Export(); -$jekyll_export->export(); +$jekyll_export->export($user_config); diff --git a/jekyll-exporter.php b/jekyll-exporter.php index 8ece9ea1..cf47d0f7 100644 --- a/jekyll-exporter.php +++ b/jekyll-exporter.php @@ -60,6 +60,32 @@ // $config['category_id'] = "DIC_kwDOIVZ3Bc4CSRMx"; // Get values from giscus config page +// The site URL should be correctly detected from Wordpress, if not force here (ex: "https://www.mywebsite.fr/") +$config["site_url"] = get_site_url() . '/'; // Trailing slash is important to get relative URLs + +$config["extra_remove_site_url"] = $config["site_url"]; // Will remove site url to get relative URLs +$config['extra_code'] = true; // Will retrieve lang and protect pre/code +$config['extra_img_style'] = true; // Will retrieve style from image +$config['extra_tag_spoiler'] = true; // Will convert spoiler tags + +// Configure types exported (revision can cause some article mismatch, try remove it in case of problems) +$config['export_types'] = ['post', 'page', 'revision']; + +// Configure name of key where WordPress post id is exported to +$config["post_id_key"] = "id"; + +$config["meta_ignore_list"] = array( + '_*', + 'ocean_*', + 'classic-editor-remember', + 'osh_disable_topbar_sticky', + 'osh_disable_header_sticky', + 'osh_sticky_header_style', + 'ampforwp-amp-on-off', +); + +//$config['force_dest_dir'] = "/dest-path/"; // "_export/"; // Force destination directory to relative one (without temp folder, will deactivate zip) + if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) { wp_die( 'Jekyll Export requires PHP 5.3 or later' ); @@ -73,6 +99,33 @@ use Symfony\Component\Yaml\Yaml; +function jekyll_exporter_patch_contents($contents) { + + if ($config["extra_remove_site_url"]) $contents = preg_replace("!${$config['extra_remove_site_url']}!",'', $contents); + + if ($config['extra_code']) { + $contents = preg_replace('!]*crayon-inline[^>]*>([^<]*)!','\1', $contents); + $contents = preg_replace('!class="lang:default!','class="', $contents); + $contents = preg_replace('!class="lang:!','class="language-', $contents); + $contents = preg_replace('!]*)>!','', $contents); + $contents = preg_replace('!!','', $contents); + $contents = preg_replace('!]*)>!','
', $contents);
+		$contents = preg_replace('!]*>!','
', $contents); + } + if ($config['extra_img_style']) { + $contents = preg_replace('!(]*alignright[^>]*/>)!','\1{: .img-right}', $contents); + $contents = preg_replace('!(]*aligncenter[^>]*/>)!','\1{: .img-center}', $contents); + $contents = preg_replace('!(]*aligncenter[^>]*/>)!','\1{: .img-center}', $contents); + } + if ($config['extra_tag_spoiler']) { + $contents = preg_replace('!\[su_spoiler title="([^"]*)" [^\]]*\]!',"
\\1", $contents); + $contents = preg_replace('!\[/su_spoiler\]!',"
", $contents); + } + + return $contents; +} +add_filter( 'the_content', 'jekyll_exporter_patch_contents'); + // https://gist.github.com/dunglas/05d901cb7560d2667d999875322e690a function graphql_query(string $endpoint, string $query, array $variables = [], ?string $token = null): array { @@ -243,6 +296,7 @@ function register_menu() { */ function get_posts() { global $wpdb; + global $config; $posts = wp_cache_get( 'jekyll_export_posts' ); if ( $posts ) { @@ -250,7 +304,7 @@ function get_posts() { } $posts = array(); - $post_types = apply_filters( 'jekyll_export_post_types', array( 'post', 'page' /*, 'revision'*/ ) ); + $post_types = apply_filters( 'jekyll_export_post_types', $config['export_types'] ); /** * WordPress style rules don't let us interpolate a string before passing it to @@ -273,8 +327,10 @@ function get_posts() { */ function convert_meta( $post ) { + global $config; + $output = array( - 'post_id' => $post->ID, + $config["post_id_key"] => $post->ID, 'title' => get_the_title( $post ), 'date' => get_the_date( 'c', $post ), 'last_modified_at' => get_the_modified_date( 'c', $post ), @@ -292,15 +348,7 @@ function convert_meta( $post ) { } // Convert traditional post_meta values, hide hidden values. - $ignore_list = array( - '_*', - 'ocean_*', - 'classic-editor-remember', - 'osh_disable_topbar_sticky', - 'osh_disable_header_sticky', - 'osh_sticky_header_style', - 'ampforwp-amp-on-off', - ); + $ignore_list = $config['meta_ignore_list']; foreach ( get_post_custom( $post->ID ) as $key => $value ) { @@ -458,8 +506,6 @@ function convert_posts() { setup_postdata( $post ); - //if ($post->ID != $post_id) var_dump($post); - $meta = array_merge( $this->convert_meta( $post ), $this->convert_terms( $post_id ) ); // remove falsy values, which just add clutter. @@ -690,9 +736,11 @@ function init_temp_dir() { /** * Main function, bootstraps, converts, and cleans up */ - function export() { + function export($user_config = null) { global $config; + if ($user_config) $config = array_merge($config, $user_config); + do_action( 'jekyll_export' ); ob_start(); $this->init_temp_dir();