summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.editorconfig3
-rw-r--r--.phpcs.xml25
-rw-r--r--import-posts.php186
3 files changed, 214 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..22fcb8a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,3 @@
+[*.php]
+indent_style = tab
+indent_size = 4
diff --git a/.phpcs.xml b/.phpcs.xml
new file mode 100644
index 0000000..f8bb5f3
--- /dev/null
+++ b/.phpcs.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="PHP_CodeSniffer" xsi:noNamespaceSchemaLocation="phpcs.xsd">
+ <description>PHPCS configuration for hmno.migrate</description>
+
+ <exclude-pattern>*/src/Standards/*/Tests/*\.(inc|css|js)$</exclude-pattern>
+ <exclude-pattern>*/tests/Core/*/*\.(inc|css|js)$</exclude-pattern>
+
+ <arg name="basepath" value="."/>
+ <arg name="colors"/>
+ <arg name="parallel" value="75"/>
+ <arg value="np"/>
+
+ <!-- Don't hide tokenizer exceptions -->
+ <rule ref="Internal.Tokenizer.Exception">
+ <type>error</type>
+ </rule>
+
+ <!-- Include the whole PEAR standard -->
+ <rule ref="WordPress">
+ <exclude name="Generic.WhiteSpace.DisallowSpaceIndent" />
+ <exclude name="Squiz.Commenting.InlineComment.InvalidEndChar" />
+ <exclude name="WordPress.Security.EscapeOutput.OutputNotEscaped" />
+ <exclude name="Squiz.Commenting.FunctionComment.Missing" />
+ </rule>
+</ruleset>
diff --git a/import-posts.php b/import-posts.php
new file mode 100644
index 0000000..6697289
--- /dev/null
+++ b/import-posts.php
@@ -0,0 +1,186 @@
+<?php
+/**
+ * Script to import posts from RefineryCMS to WordPress for Heavymetal.no
+ *
+ * We expect the posts to be in a zip-archive containing files as exported
+ * by the export-articles script in the old install. That is html files
+ * with a prepended frontmatter block containing the relevant metadata.
+ *
+ * We don't care about any subdirectories in the archive, or indeed file
+ * names, as we only iterate through the archive linearly by index.
+ *
+ * @package hmno.migrate
+ */
+
+if ( $argc < 2 ) {
+ echo "Usage: {$argv[0]} <filename.zip>" . PHP_EOL;
+ exit( -1 );
+}
+
+$filename = $argv[1];
+
+
+// Load WordPress
+require_once getcwd() . '/wp-load.php';
+
+// Required for the taxonomy functions (categories/tags)
+require_once getcwd() . '/wp-admin/includes/taxonomy.php';
+
+// Required for kses functionality
+require_once getcwd() . '/wp-includes/kses.php';
+
+
+$archive = new ZipArchive();
+if ( true === $archive->open( $filename, ZipArchive::RDONLY ) ) {
+ $files = $archive->count();
+ echo "Opened archive with {$files} files." . PHP_EOL;
+
+ for ( $i = 0; $i < $files; $i++ ) {
+ echo " => {$archive->getNameIndex( $i )}..." . PHP_EOL;
+ $meta = parse_old_post( $archive->getFromIndex( $i ) );
+ migrate_post( $meta );
+ }
+
+ $archive->close();
+}
+
+function parse_old_post( $input ) : array {
+ $parts = explode( '---', $input );
+
+ // $parts[0] is empty
+ $meta = parse_post_frontmatter( $parts[1] );
+ $meta['body'] = trim( $parts[2] );
+
+ return $meta;
+}
+
+function parse_post_frontmatter( $input ) : array {
+ $lines = array_filter( explode( "\n", $input ) );
+ return array_reduce(
+ $lines,
+ function( $acc, $line ) {
+ $kv = explode( ': ', $line, 2 );
+ if ( isset( $kv[0], $kv[1] ) ) {
+ $acc[ $kv[0] ] = $kv[1];
+ }
+ return $acc;
+ },
+ array()
+ );
+}
+
+function get_wp_category( $name, $parent = 0 ) : int {
+ $cat = category_exists( $name );
+
+ if ( ! $cat ) {
+ $cat = wp_create_category( $name, $parent );
+ }
+
+ return $cat;
+}
+
+function migrate_post( $meta ) {
+ global $wpdb;
+
+ $categories = array_map(
+ fn( $cat ) => get_wp_category( $cat ),
+ explode( ',', $meta['categories'] )
+ );
+
+ $images = migrate_images( $meta );
+
+ $post_id = wp_insert_post(
+ array(
+ 'post_author' => $meta['user_id'],
+ 'post_date' => $meta['published_at'],
+ 'post_date_gmt' => $meta['published_at'],
+ 'post_content' => $meta['body'],
+ 'post_title' => $meta['title'],
+ 'post_excerpt' => wp_filter_kses( $meta['custom_teaser'] ),
+ 'post_status' => 'publish',
+ 'comment_status' => 'closed',
+ 'ping_status' => 'closed',
+ 'post_modified' => $meta['updated_at'],
+ 'post_modified_gmt' => $meta['updated_at'],
+ 'post_parent' => '0',
+ 'post_category' => $categories,
+ 'post_tags' => explode( ',', $meta['tags'] ),
+ 'menu_order' => '0',
+ 'post_type' => 'post',
+ )
+ );
+
+ if ( 0 === $post_id ) {
+ die( "Error: Unable to insert post: {$meta['title']}." . PHP_EOL );
+ }
+
+ return array( $post_id, $thumb );
+}
+
+function migrate_images( array $meta ) : array {
+ $post_date = new DateTimeImmutable( $meta['published_at'] );
+ if ( ! $post_date ) {
+ die( "Error: Could not parse published_at date: {$meta['published_at']}." );
+ }
+
+ $thumb = null;
+
+ if ( isset( $meta['body'] ) ) {
+ $meta['body'] = preg_replace_callback(
+ '/<img src="([^"]*)" title="([^"]*)" alt="([^"]*)"[^>]*>/',
+ function( array $matches ) {
+ $remote_filename = $matches[1];
+ $filename = basename( $remote_filename );
+ $title = $matches[2];
+ $alt = $matches[3];
+
+ $uploads = wp_upload_dir( $post_date->format( 'Y/m' ) );
+ $target_file = implode( '/', array( $uploads['path'], $filename ) );
+ $target_url = implide( '/', array( $uploads['url'], $filename ) );
+
+ import_photo( $remote_filename, $target_file );
+
+ $mime = wp_get_image_mime( $target_file );
+ if ( ! $mime ) {
+ die( "Error: Unknown mime type for {$target_file}" . PHP_EOL );
+ }
+
+ $attachment_id = wp_insert_attachment(
+ array(
+ 'post_mime_type' => $mime,
+ 'guid' => $target_url,
+ 'post_paren' => 0,
+ 'post_title' => $filename,
+ ),
+ $target_file
+ );
+
+ if ( 0 === $attachment_id ) {
+ die( "Error: Could not create attachment for {$target_file}" . PHP_EOL );
+ }
+
+ if ( ! $thumb ) {
+ $thumb = $attachment_id;
+ return '';
+ } else {
+ return "<img src=\"{$target_url}\" title=\"{$title}\" alt=\"{$alt}\">";
+ }
+ },
+ $meta['body'],
+ );
+ }
+
+ return $thumb;
+}
+
+function import_photo( $remote_path, $target_filename ) {
+ $curl = curl_init( implode( '/', array( 'https://heavymetal.no', $remote_path ) ) );
+
+ if ( false === $curl ) {
+ die( 'Error: Unable to init curl' );
+ }
+
+ curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
+ $res = curl_exec( $curl );
+ file_put_contents( $target_filename, $res );
+}