diff --git a/composer.json b/composer.json index 50a86c3..b4714e4 100644 --- a/composer.json +++ b/composer.json @@ -1,15 +1,16 @@ { "name": "petermolnar/wp-flatexport", - "description": "auto-export WordPress contents to folders and plain text + markdown files for longetivity and portability", + "description": "export WordPress content to Spress compatible text files", "require": { - "php": ">=5.4.0" + "php": ">=5.4.0", + "symfony/yaml": "^3.1" }, "license": "GPLv3", "authors": [ { "name": "Peter Molnar", - "email": "hello@petermolnar.eu", - "homepage": "https://petermolnar.eu" + "email": "hello@petermolnar.net", + "homepage": "https://petermolnar.net" } ] } diff --git a/readme.txt b/readme.txt index f73e0f7..ab26744 100644 --- a/readme.txt +++ b/readme.txt @@ -3,11 +3,11 @@ Contributors: cadeyrn Tags: plain text, export, backup Requires at least: 3.0 Tested up to: 4.5.3 -Stable tag: 0.5 +Stable tag: 0.8 License: GPLv3 License URI: http://www.gnu.org/licenses/gpl-3.0.html -Auto-export WordPress flat, structured, readable plain text. +Export WordPress to Spress compatible plain text files. == Description == @@ -17,11 +17,6 @@ It only works well with Markdown content. There are certain tricks done with the content. Please be aware of this. -Content will be exported to wp-content/flat/{post_slug}/ folder ( one folder per post), all attachments copied (or hardlinked, if possible with the filesystem; this is automatic ). - -The content will be placed into in item.md file. This is a markdown file, with some plain test headers. -Comments are exported into the same folder, named comment-{comment_id}.md; the format is similar for those as well. - **This is not a backup!** The goal of the plugin is to have a portable, plain text, easy to read, easy to copy version of you content on WordPress. Since not all data is exported, your site cannot be reconstructed from these exports. @@ -42,35 +37,3 @@ Version numbering logic: * every .B version indicates new features. * every ..C indicates bugfixes for A.B version. -= 0.5 = -*2016-07-22* - -* everything is through filters now -* moar magic formatting: -** stong/em moved to strict `**`/`_` from `__`/`*` -** definition lists moved to strict `: ` from lazy spaces -* code is strictly less, than 80 char per line -* comments format changed -* using index.txt instead of item.md -* - -= 0.3 = -*2016-07-14* - -* switched to filter-based content inserting for the end output; this way it's possible to add, remove, reorder, and insert in between the predefined output parts - -= 0.2 = -*2016-06-27* - -* plugin renamed to avoid confusion of the exports being backups -* removed YAML in favour of parseable plain text formatting - -= 0.1.1 = -*2016-03-08* - -* better debugging - -= 0.1 = -*2015-12-10* - -* first stable release diff --git a/wp-flatexport.php b/wp-flatexport.php index 1cd56d9..17551b6 100644 --- a/wp-flatexport.php +++ b/wp-flatexport.php @@ -2,8 +2,8 @@ /* Plugin Name: WP Flat Export Plugin URI: https://github.com/petermolnar/wp-flatexport -Description: auto-export WordPress flat, structured, readable plain text -Version: 0.6 +Description: auto-export WordPress content to Spress compatible text files +Version: 0.8 Author: Peter Molnar Author URI: http://petermolnar.net/ License: GPLv3 @@ -25,57 +25,74 @@ License: GPLv3 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -namespace WP_FLATEXPORTS; +namespace WP_FLATEXPORT; -//require (__DIR__ . '/vendor/autoload.php'); -//use KzykHys\FrontMatter\FrontMatter; -//use KzykHys\FrontMatter\Document; +require (__DIR__ . '/vendor/autoload.php'); +//use \Yosymfony\Toml; +use \Symfony\Component\Yaml; -define ( 'WP_FLATEXPORTS\FORCE', true ); -define ( 'WP_FLATEXPORTS\ROOT', \WP_CONTENT_DIR . DIRECTORY_SEPARATOR +define ( 'WP_FLATEXPORT\FORCE', true ); +define ( 'WP_FLATEXPORT\ROOT', \WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'flat' . DIRECTORY_SEPARATOR ); -define ( 'WP_FLATEXPORTS\POSTSROOT', ROOT . 'post' - . DIRECTORY_SEPARATOR ); -define ( 'WP_FLATEXPORTS\COMMENTROOT', ROOT . 'comments' - . DIRECTORY_SEPARATOR ); -define ( 'WP_FLATEXPORTS\FILESROOT', ROOT . 'files' - . DIRECTORY_SEPARATOR ); +define ( 'WP_FLATEXPORT\COMMENTROOT', ROOT . 'comment' . DIRECTORY_SEPARATOR ); -\register_activation_hook( __FILE__ , '\WP_FLATEXPORTS\plugin_activate' ); -\register_deactivation_hook( __FILE__ , '\WP_FLATEXPORTS\plugin_deactivate' ); + +\register_activation_hook( __FILE__ , '\WP_FLATEXPORT\plugin_activate' ); +\register_deactivation_hook( __FILE__ , '\WP_FLATEXPORT\plugin_deactivate' ); // init all the things -\add_action( 'init', '\WP_FLATEXPORTS\init' ); +\add_action( 'init', '\WP_FLATEXPORT\init' ); // export on any change made to a post -\add_action( 'transition_post_status', '\WP_FLATEXPORTS\export_auto' ); +\add_action( 'transition_post_status', '\WP_FLATEXPORT\export_auto' ); // cron based export for all posts -\add_action( 'wp_flatexport', '\WP_FLATEXPORTS\export_all' ); +\add_action( 'wp_flatexport', '\WP_FLATEXPORT\export_all' ); // display plain text with https://site.com/path/to/post/text -\add_action( 'template_redirect', '\WP_FLATEXPORTS\display' ); +\add_action( 'template_redirect', '\WP_FLATEXPORT\display' ); // -\add_action( 'wp', '\WP_FLATEXPORTS\export' ); +//\add_action( 'wp', '\WP_FLATEXPORT\export' ); /** * */ function post_filename ( &$post, $ext = 'md' ) { + $path = $post->post_name . '.' . $ext; + + $kind = wp_get_post_terms( $post->ID, 'category', + array( 'fields' => 'all' ) ); + + if(is_array($kind)) + $kind = array_pop( $kind ); + + if (is_object($kind) && isset($kind->slug)) { + $dir = ROOT . $kind->slug . DIRECTORY_SEPARATOR; + if ( ! is_dir( $dir ) ) + mkdir ( $dir ); + + $path = $dir . $path; + } + else { + $path = ROOT . $path; + } + + //$path = ROOT . $path; + //$timestamp = \get_the_time( 'U', $post->ID ); //$date = date( 'Y-m-d', $timestamp ); //if ( empty( $date ) ) //die ( json_encode( $post ) ); - return POSTSROOT . $post->post_name . '.' . $ext; + return $path; } /** * */ function check_rootdirs() { - $dirs = [ POSTSROOT, FILESROOT, COMMENTROOT ]; + $dirs = [ ROOT, COMMENTROOT ]; foreach ( $dirs as $dir ) { $dir = rtrim( $dir, '/' ); if ( ! is_dir( $dir ) ) { @@ -112,40 +129,25 @@ function init () { $filters = array ( 'wp_flatexport_txt' => array ( - 'txt_insert_title', - 'txt_insert_excerpt', + 'txt_insert_spress_frontmatter', 'txt_insert_content', - 'txt_insert_published', - 'txt_insert_urls', - 'txt_insert_author', - 'txt_insert_tags', - 'txt_insert_location', - 'txt_insert_attachments', - 'txt_insert_uuid', - ), - 'wp_flatexport_content' => array ( - 'post_content_resized2orig', - 'post_content_insert_featured', - 'post_content_absolute_images', - 'post_content_clear_imgids', - 'post_content_fix_emstrong', - 'post_content_fix_dl', - 'post_content_fix_surprises', - 'post_content_url2footnote', - 'post_content_setext_headers', + 'normalize_line_ends', ), + //'wp_flatexport_content' => array ( + //'post_content_add_excerpt', + //'post_content_resized2orig', + //'post_content_absolute_images', + //'post_content_clear_imgids', + //), 'wp_flatexport_comment' => array ( - 'comment_insert_type', + 'comment_insert_spress_frontmatter', 'comment_insert_content', - 'comment_insert_at', - 'comment_insert_from', - 'comment_insert_for', ), ); foreach ( $filters as $for => $subfilters ) { foreach ( $subfilters as $k => $filter ) { - \add_filter ( $for, "\\WP_FLATEXPORTS\\$filter", 5 * ( $k + 1 ), 2 ); + \add_filter ( $for, "\\WP_FLATEXPORT\\$filter", 5 * ( $k + 1 ), 2 ); } } @@ -154,11 +156,10 @@ function init () { if (!wp_get_schedule( 'wp_flatexport' )) wp_schedule_event ( time(), 'daily', 'wp_flatexport' ); - } /** - * + * on the fly text format, mostly for debugging */ function display () { global $wp_query; @@ -173,142 +174,11 @@ function display () { } /** - * + * Windows, go home */ -function depthmap () { - - return array ( - 1 => "=", // asciidoc, restuctured text, and markdown compatible - 2 => "-", // asciidoc, restuctured text, and markdown compatible - //3 => "~", // asciidoc only - //4 => "^", // asciidoc only - //5 => "+", // asciidoc only - ); -} - -/** - * - */ -function _insert_head ( $title, $depth = 2 ) { - if ( $depth > 2 ) { - $prefix = str_repeat( "#", $depth ); - $r = "\n\n{$prefix} {$title}"; - } - else { - $map = depthmap(); - $underline = str_repeat( $map[ $depth ], mb_strlen( $title) ); - $r = "\n\n{$title}\n${underline}"; - } - - if ( $depth > 1 ) - $r .= "\n"; - - return $r; - -} - -/** - * extends the $text with - * - * (post title) - * ============ - * - */ -function txt_insert_title ( $text, $post ) { - - $title = trim( $post->post_title ); - debug ( $title ); - - if ( empty( $title ) ) - return $text; - - // the linebreaks are here in case the order of inserting things is changed - $text .= _insert_head( $title, 1 ); - - return $text; - -} - -/** - * - * extends the $text with - * - * UUID - * ---- - * (post UUID) - * - * post UUID is an md5 hash of: - * post ID + (math add) epoch of post first publish date - * this should not ever change! - * - */ -function txt_insert_uuid ( $text, $post ) { - - $uuid = hash ( - 'md5', - (int)$post->ID + (int) get_post_time('U', true, $post->ID ) - ); - $text .= _insert_head( "UUID" ); - $text .= "{$uuid}"; - - return $text; - -} - -/** - * - * extends the $text with - * - * Attachments - * ----------- - * - * - * - */ -function txt_insert_attachments ( $text, $post ) { - - // get all the attachments - $attachments = \get_children( array ( - 'post_parent'=>$post->ID, - 'post_type'=>'attachment', - 'orderby'=>'menu_order', - 'order'=>'asc' - )); - - if ( empty( $attachments ) ) - return $text; - - $text .= _insert_head( "Attachments" ); - $a = array(); - foreach ( $attachments as $aid => $attachment ) { - $attachment_path = \get_attached_file( $aid ); - if ( empty( $attachment_path ) || ! is_file( $attachment_path ) ) - continue; - - array_push( $a, "- " . basename( $attachment_path ) ); - } - - $text .= join( "\n", $a ); - - return $text; - -} - -/** - * - * extends the $text with - * - * \n (post excerpt) - */ -function txt_insert_excerpt ( $text, $post ) { - - $excerpt = trim( $post->post_excerpt ); - - if( ! empty( $excerpt ) ) - $text .= "\n" . $excerpt; - - return $text; - +function normalize_line_ends( $content, $post ) { + //return preg_replace( "/(?<=[^\r]|^)\n/", "\n", $content ); + return preg_replace( "/\r/", "", $content ); } /** @@ -333,285 +203,126 @@ function txt_insert_content ( $text, $post ) { /** * - * extends the $text with - * - * Published - * --------- - * - (post publish date in Y-m-d H:i:s P format) - * [- (post last update date in Y-m-d H:i:s P format)] + * YAML version */ -function txt_insert_published ( $text, $post ) { - - $published = \get_the_time( 'Y-m-d H:i:s P', $post->ID ); - $modified = \get_the_modified_time( 'Y-m-d H:i:s P', $post->ID ); +function txt_insert_spress_frontmatter ( $content, $post ) { $published = \get_the_time( 'U', $post->ID ); $modified = \get_the_modified_time( 'U', $post->ID ); + $meta = [ + 'title' => trim( $post->post_title ), + 'date' => date('c', $published ), + /* + // the author is the same site-wise, so put it in the Spress config + 'author' => [ + 'name' => \get_the_author_meta ( 'display_name' , $post->post_author ), + 'email' => \get_the_author_meta ( 'email' , $post->post_author ), + 'url' => \get_the_author_meta ( 'url' , $post->post_author ), + ], + */ + ]; - $text .= _insert_head ( "Published" ); - //$text .= "initial - {$published}"; - $text .= "- " . date( 'Y-m-d H:i:s P', $published ); - - if ( $published != $modified && $modified > $published ) - $text .= "\n- " . date( 'Y-m-d H:i:s P', $modified ); - //$text .= "\ncurrent - {$modified}"; - - return $text; -} - -/** - * - * extends the $text with - * - * URLs - * ---- - * - http://site.com/post_ID - * - (post shortlink) - * - (post permalink) - * [- additional urls, one per line] - */ -function txt_insert_urls ( $text, $post ) { - - // basic ones - $slugs = list_urls( $post ); - $text .= _insert_head ( "URLs" ); - $text .= "- " . join ( "\n- ", $slugs ); - - return $text; -} - -/** - * get all urls that are pointing to this very post, including syndications - * - */ -function list_urls ( $post ) { - - $urls = array(); - $slugs = \get_post_meta ( $post->ID, '_wp_old_slug' ); - array_push ( $slugs, $post->post_name ); - array_push ( $slugs, $post->ID ); - - // eliminate revisions - foreach ( $slugs as $k => $slug ) { - if ( preg_match ( '/-(revision|autosave)-v?[0-9]+/', $slug ) ) - continue; - - // make them real URLs - // site_url does not allow numbers only as slugs, so we're doing it the - // hard way - array_push( $urls, rtrim ( \site_url( ), '/' ) . '/' . $slug ); + // updated + if ( $published != $modified && $modified > $published ) { + $mta['updated'] = date('c', $modified ); } - // just in case these differ - array_push ( $urls, \get_permalink( $post ) ); - //array_push ( $slugs, \wp_get_shortlink( $post->ID ) ); + // redirects from _wp_old_slug + // requires https://github.com/ajgarlag/AjglRedirectorSpressPlugin + if ( $olds = get_post_meta( $post->ID, '_wp_old_slug', false ) ) { + $olds_f = array(); + foreach( $olds as $c => $old ) { - // get syndicated URLs - $syndications = \get_post_meta ( $post->ID, 'syndication_urls', true ); - if ( ! empty( $syndications ) ) - $urls = array_merge( $urls, explode( "\n", trim( $syndications ) ) ); + // WP_SHORTSLUG add the epoch based base32 urls to the _wp_old_slug + // field; these should be handled separately and not in this very + // redirect method, so skip those + if ( class_exists( '\WP_SHORTSLUG' ) + && function_exists( '\WP_SHORTSLUG\url2epoch' ) ) { + $epoch = \WP_SHORTSLUG\url2epoch( $old ); + if ( $epoch == $published || $epoch == $modified ) { + continue; + } + } - $sorted = array(); - // get rid of trailing slashes; it's either no trailing slash or slash on - // everything, which breaks .html-like real document path URLs - foreach ( $urls as $k => $url ) { - if ( ! strstr( $url, 'http') ) - continue; - array_push( $sorted, rtrim( $url, '/' ) ); - } - - - - foreach ( $sorted as $c => $url ) { - $sorted[ $c ] = str_replace( 'http://', 'https://', $url ); - } - - // eliminate duplicates - $sorted = array_unique ( $sorted ); - - // make it more readable - usort( - $sorted, - function ( $a, $b ) { - return strlen( $a ) - strlen( $b ); + array_push( $olds_f, '/' . trim( $old, '/') . '/' ); } - ); - - return $sorted; -} - - -/** - * - * extends the $text with - * - * Author - * ------ - * Author Display Name [] - * author URLs - */ -function txt_insert_author ( $text, $post ) { - - $author_id = $post->post_author; - $author = \get_the_author_meta ( 'display_name' , $author_id ); - - if ( empty( $author ) ) - return $text; - - if ( $author_email = \get_the_author_meta ( 'email' , $author_id ) ) - $author .= " <{$author_email}>"; - - if ( $author_url = \get_the_author_meta ( 'url' , $author_id ) ) - $author .= "\n{$author_url}"; - - $text .= _insert_head ( "Author" ); - $text .= "{$author}"; - - return $text; -} - -/** - * - * extends the $text with - * - * Tags - * ---- - * \#(comma separated list of # tags) - */ -function txt_insert_tags ( $text, $post ) { - - $raw_tags = \wp_get_post_terms( $post->ID, 'post_tag' ); - - if ( empty( $raw_tags ) ) - return $text; - - $tags = array(); - foreach ( $raw_tags as $k => $tag ) { - array_push( $tags, "#{$tag->name}" ); + if ( count( $olds_f ) > 0 ) { + $meta['redirect_from'] = $olds_f; + } } - array_unique( $tags ); - $tags = join ( ', ', $tags ); + // category + $categories = wp_get_post_terms( $post->ID, 'category', + array( 'fields' => 'all' ) ); - $text .= _insert_head ( "Tags" ); - // these are hashtags, so escape the first one to avoid converting it into - // a header - $text .= "\\" . $tags; + if( is_array( $categories ) ) + $categories = array_pop( $categories ); - return $text; -} + $meta['categories'] = array( $categories->slug ); -/** - * - * extends the $text with - * - * Location - * -------- - * latitude,longitude[@altitude] - */ -function txt_insert_location ( $text, $post ) { + // add syndicated URLs, if any + if ( $syn = get_post_meta( $post->ID, 'syndication_urls', true ) ) { + $syn = explode( "\n", $syn ); + if ( count( $syn ) ) { + $meta['syndications'] = $syn; + } + } + + // tags + $raw_tags = \wp_get_post_terms( $post->ID, 'post_tag' ); + $tags = array(); + if ( ! empty( $raw_tags ) ) { + foreach ( $raw_tags as $k => $tag ) { + array_push( $tags, $tag->name ); + } + $meta['tags'] = $tags; + } // geo - $lat = \get_post_meta ( $post->ID, 'geo_latitude' , true ); - $lon = \get_post_meta ( $post->ID, 'geo_longitude' , true ); + $lat = floatval ( \get_post_meta ( $post->ID, 'geo_latitude' , true ) ); + $lon = floatval ( \get_post_meta ( $post->ID, 'geo_longitude' , true ) ); - if ( empty( $lat ) || empty( $lon ) ) - return $text; + if ( ! empty( $lat ) && ! empty( $lon ) ) { + $meta['location'] = [ + 'latitude' => $lat, + 'longitude' => $lon + ]; - $geo = "{$lat},{$lon}"; + $alt = floatval ( \get_post_meta ( $post->ID, 'geo_altitude' , true ) ); + if ( !empty( $alt ) ) { + $meta['location']['altitude'] = $alt; + } + } - $alt = \get_post_meta ( $post->ID, 'geo_altitude' , true ); - if ( !empty( $alt ) ) - $geo .= ",{$alt}"; - - - $text .= _insert_head ( "Location" ); - $text .= "{$geo}"; - - return $text; + return "---\n" . trim ( \Symfony\Component\Yaml\Yaml::dump( $meta, 1 ) ) + . "\n---\n" . $content; } /** * - * extends the $c with - * - * From - * ------ - * Author Display Name [] - * avatar URL - * [ author URL ] */ -function comment_insert_from ( $c, $comment ) { - $c .= _insert_head( "From" ); +function comment_insert_spress_frontmatter ( $c, $comment ) { - $c .= "{$comment->comment_author}"; - - if ( ! empty( $comment->comment_author_email ) ) - $c .= " <{$comment->comment_author_email}>"; - - //if ( $avatar = \get_comment_meta ($comment->comment_ID, "avatar", true)) - //$c .= "\n{$avatar}"; - //elseif ( ! empty( $comment->comment_author_email ) ) - //$c .= "\n". gravatar ( $comment->comment_author_email ); - - if ( ! empty( $comment->comment_author_url )) - $c .= "\n{$comment->comment_author_url}"; - - return $c; -} - -/** - * - * extends the $c with - * - * (Type) - * ====== - */ -function comment_insert_type ( $c, $comment ) { if ( empty ( $comment->comment_type ) ) $type = "Reply"; else $type = ucfirst( $comment->comment_type ); - $c .= _insert_head( $type, 1 ); + $meta = [ + 'from' => [ + 'name' => $comment->comment_author, + 'email' => $comment->comment_author_email, + 'url' => $comment->comment_author_url, + ], + 'type' => $type, + 'for' => \get_permalink( $comment->comment_post_ID ), + 'date' => date( 'c', strtotime( $comment->comment_date ) ), + ]; - return $c; -} - -/** - * - * extends the $text with - * - * For - * --- - * original post URL - * - */ -function comment_insert_for ( $c, $comment ) { - $c .= _insert_head( "For" ); - $postid = $comment->comment_post_ID; - $url = get_permalink( $postid ); - $c .= $url; - - return $c; -} - - -/** - * - * extends the $text with - * -* At - * -- - * (comment publish date in Y-m-d H:i:s P format) - */ -function comment_insert_at ( $c, $comment ) { - $c .= _insert_head( "At" ); - $c .= date( 'Y-m-d H:i:s P', strtotime( $comment->comment_date ) ); - - return $c; + return "---\n" . trim ( \Symfony\Component\Yaml\Yaml::dump( $meta, 1 ) ) + . "\n---\n" . $c; } /** @@ -628,291 +339,6 @@ function comment_insert_content ( $c, $comment ) { } -/** - * - */ -function post_content_absolute_images ( $content, $post ) { - - - $urlparts = parse_url( \site_url() ); - $domain = $urlparts ['host']; - $wp_upload_dir = \wp_upload_dir(); - $uploadurl = str_replace( - '/', - "\\/", - trim( str_replace( - \site_url(), - '', - $wp_upload_dir['url'] - ), '/') - ); - - $p = "/\((\/?{$uploadurl}\/.*?\.[a-zA-Z]{2,4})\)/i"; - preg_match_all( $p, $content, $images ); - if ( empty ( $images[1] )) - return $content; - - foreach ( $images[1] as $imgstr ) { - $fname = site_url( $imgstr ); - $content = str_replace ( $imgstr, $fname, $content ); - } - return $content; -} - - -/** - * fix all image attachments: resized -> original - * - */ -function post_content_resized2orig ( $content, $post ) { - - $urlparts = parse_url( \site_url() ); - $domain = $urlparts ['host']; - $wp_upload_dir = \wp_upload_dir(); - $uploadurl = str_replace( - '/', - "\\/", - trim( str_replace( - \site_url(), - '', - $wp_upload_dir['url'] - ), '/') - ); - - $pregstr = "/((https?:\/\/". $domain .")?" - . "\/". $uploadurl - . "\/.*\/[0-9]{4}\/[0-9]{2}\/)(.*)-([0-9]{1,4})×([0-9]{1,4})" - . "\.([a-zA-Z]{2,4})/"; - - preg_match_all( $pregstr, $content, $resized_images ); - - if ( !empty ( $resized_images[0] )) { - foreach ( $resized_images[0] as $cntr => $imgstr ) { - $done_images[ $resized_images[2][$cntr] ] = 1; - $fname = $resized_images[2][$cntr] . '.' . $resized_images[5][$cntr]; - $width = $resized_images[3][$cntr]; - $height = $resized_images[4][$cntr]; - //$r = $fname . '?resize=' . $width . ',' . $height; - if ( ! preg_match( '/https?:\/\//i', $fname ) ) - $fname = site_url ( $fname ); - - $content = str_replace ( $imgstr, $fname, $content ); - } - } - - $pregstr = "/(https?:\/\/". $domain .")?" - . "\/".$uploadurl - ."\/.*\/[0-9]{4}\/[0-9]{2}\/(.*?)\.([a-zA-Z]{2,4})/"; - - preg_match_all( $pregstr, $content, $images ); - if ( !empty ( $images[0] )) { - - foreach ( $images[0] as $cntr=>$imgstr ) { - if ( !isset($done_images[ $images[1][$cntr] ]) ){ - if ( !strstr($images[1][$cntr], 'http')) - $fname = $images[2][$cntr] . '.' . $images[3][$cntr]; - else - $fname = $images[1][$cntr] . '.' . $images[2][$cntr]; - - if ( ! preg_match( '/https?:\/\//i', $fname ) ) - $fname = site_url ( $fname ); - - $content = str_replace ( $imgstr, $fname, $content ); - } - } - } - - return $content; -} - -/** - * insert featured image - * - */ -function post_content_insert_featured ( $content, $post ) { - - $thid = \get_post_thumbnail_id( $post->ID ); - if ( ! empty( $thid ) ) { - $src = \wp_get_attachment_image_src( $thid, 'full' ); - if ( isset($src[0]) ) { - $url = \site_url( $src[0] ); - $meta = \wp_get_attachment_metadata($thid); - - if ( empty( $meta['image_meta']['title'] ) ) - $title = $post->post_title; - else - $title = $meta['image_meta']['title']; - - $featured = "\n\n![{$title}]({$url}){#img-{$thid}}"; - $content .= apply_filters ( - 'wp_flatexport_featured_image', - $featured, - $post - ); - } - } - - return $content; -} - -/** - * get rid of markdown extra {#img-ID} -s - * - */ -function post_content_clear_imgids ( $content, $post ) { - - $content = preg_replace( "/\{\#img-[0-9]+.*?\}/", "", $content ); - - return $content; -} - -/** - * find markdown links and replace them with footnote versions - * - */ -function post_content_url2footnote ( $content, $post ) { - - // - $pattern = "/[\s*_\/]+(\[([^\s].*?)\]\((.*?)(\s?+[\\\"\'].*?[\\\"\'])?\))/"; - preg_match_all( $pattern, $content, $m ); - // [1] -> array of []() - // [2] -> array of [] - // [3] -> array of () - // [4] -> (maybe) "" titles - if ( ! empty( $m ) && isset( $m[0] ) && ! empty( $m[0] ) ) { - foreach ( $m[1] as $cntr => $match ) { - $name = trim( $m[2][$cntr] ); - $url = trim( $m[3][$cntr] ); - if ( ! strstr( $url, 'http') ) - $url = \site_url( $url ); - - $title = ""; - - if ( isset( $m[4][$cntr] ) && !empty( $m[4][$cntr] ) ) - $title = " {$m[4][$cntr]}"; - - $refid = $cntr+1; - - $footnotes[] = "[{$refid}]: {$url}{$title}"; - $content = str_replace ( - $match, - "[" . trim( $m[2][$cntr] ) . "][". $refid ."]" , - $content - ); - } - - $content = $content . "\n\n" . join( "\n", $footnotes ); - } - - return $content; -} - -/** - * find markdown links and replace them with footnote versions - * - */ -function post_content_fix_emstrong ( $content, $post ) { - - // these regexes are borrowed from https://github.com/erusev/parsedown - $invalid = array ( - 'strong' => array( - //'**' => '/[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', - '__' => '/__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us', - ), - 'em' => array ( - '*' => '/[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', - //'_' => '/_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', - ) - ); - - $replace_map = array ( - '*' => '_', - //'_' => '/', - //'**' => '*', - '__' => '**', - ); - - - foreach ( $invalid as $what => $regexes ) { - $m = array(); - foreach ( $regexes as $key => $regex ) { - preg_match_all( $regex, $content, $m ); - if ( empty( $m ) || ! isset( $m[0] ) || empty( $m[0] ) ) - continue; - - foreach ( array_keys ( $m[1] ) as $cntr ) { - $content = str_replace ( - $m[0][$cntr], - $replace_map[ $key ] . $m[1][$cntr] . $replace_map[ $key ], - $content - ); - } - - } - } - - return $content; -} - -/** - * - * - */ -function post_content_fix_dl ( $content, $post ) { - preg_match_all( '/^.*\n(:\s+).*$/mi', $content, $m ); - - if ( empty( $m ) || ! isset( $m[0] ) || empty( $m[0] ) ) - return $content; - - foreach ( $m[0] as $i => $match ) { - $match = str_replace( $m[1][$i], ': ', $match ); - $content = str_replace( $m[0][$i], $match, $content ); - } - - return $content; -} - -/** - * - * - */ -function post_content_fix_surprises ( $content, $post ) { - $content = str_replace ( ''', "'", $content ); - $content = str_replace ( "\r\n", "\n", $content ); - $content = str_replace ( "\n\r", "\n", $content ); - - return $content; -} - - - - -/** - * find all second level markdown headers and replace them with - * underlined version - * - */ -function post_content_setext_headers ( $content, $post ) { - - $map = depthmap(); - preg_match_all( "/^([#]+)\s?+(.*)$/m", $content, $m ); - - if ( ! empty( $m ) && isset( $m[0] ) && ! empty( $m[0] ) ) { - foreach ( $m[0] as $cntr => $match ) { - $depth = strlen( trim( $m[1][$cntr] ) ); - - if ( $depth > 2 ) - continue; - - $title = trim( $m[2][$cntr] ); - $u = str_repeat( $map[ $depth ], mb_strlen( $title ) ); - $content = str_replace ( $match, "{$title}\n{$u}", $content ); - } - } - - return $content; -} - /** * */ @@ -970,42 +396,6 @@ function export_auto ( $new_status = null , $old_status = null, export ( $post ); } -function export_attachments( $attachments, $post ) { - - // hardlink all the attachments; no need for copy - // unless you're on a filesystem that does not support hardlinks, then copy - foreach ( $attachments as $aid => $attachment ) { - $attachment_path = \get_attached_file( $aid ); - if ( empty( $attachment_path ) || ! is_file( $attachment_path ) ) - continue; - - $attachment_file = basename( $attachment_path); - $target_file = FILESROOT . $attachment_file; - //$target_file = dirname( post_filename( $post ) ) . DIRECTORY_SEPARATOR . $attachment_file; - debug ( "exporting {$attachment_file}", 6 ); - - if ( is_file( $target_file ) ) { - debug ( "{$target_file} already exists", 7 ); - continue; - } - - if ( link( $attachment_path, $target_file ) ) { - debug ( "{$attachment_path} was hardlinked to {$target_file}", 7 ); - continue; - } - else { - if ( copy( $attachment_path, $target_file ) ) { - debug ( "{$attachment_path} was copied to {$target_file}", 7 ); - continue; - } - else { - debug( "could not link or copy '{$attachment_path}'" - . " to '{$target_file}'; saving attachment failed!", 4); - } - } - } -} - /** * */ @@ -1032,19 +422,7 @@ function export ( $post = null, $mode = 'normal' ) { $file_timestamp = @filemtime ( $flatfile ); } - // get all the attachments - $attachments = \get_children( array ( - 'post_parent'=>$post->ID, - 'post_type'=>'attachment', - 'orderby'=>'menu_order', - 'order'=>'asc' - )); - - if ( ! empty( $attachments ) ) { - export_attachments( $attachments, $post ); - } - - // deal with comments + //// deal with comments $comments = get_comments ( array( 'post_id' => $post->ID ) ); if ( $comments ) { foreach ($comments as $comment) { @@ -1104,15 +482,6 @@ function export_comment ( $post, $comment ) { touch ( $cfile, $c_timestamp ); } -/** - * generate gravatar img link - */ -function gravatar ( $email ) { - return sprintf( - 'https://s.gravatar.com/avatar/%s?=64', - md5( strtolower( trim( $email ) ) ) - ); -} /** * do everything to get the Post object