plugin_name = $plugin_name; $this->version = $version; $this->faq_url = 'https://wordpress.org/plugins/fg-spip-to-wp/faq/'; $upload_dir = wp_upload_dir(); $this->log_file = $upload_dir['basedir'] . '/' . $this->plugin_name . '.logs'; $this->log_file_url = $upload_dir['baseurl'] . '/' . $this->plugin_name . '.logs'; // Replace the protocol if the WordPress address is wrong in the WordPress General settings if ( is_ssl() ) { $this->log_file_url = preg_replace('/^https?/', 'https', $this->log_file_url); } // Progress bar $this->progressbar = new FG_Spip_to_WordPress_ProgressBar($this); } /** * The name of the plugin used to uniquely identify it within the context of * WordPress and to define internationalization functionality. * * @since 1.0.0 * @return string The name of the plugin. */ public function get_plugin_name() { return $this->plugin_name; } /** * Register the stylesheets for the admin area. * * @since 1.0.0 */ public function enqueue_styles() { wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/fg-spip-to-wp-admin.css', array(), $this->version, 'all' ); } /** * Register the JavaScript for the admin area. * * @since 1.0.0 */ public function enqueue_scripts() { wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/fg-spip-to-wp-admin.js', array( 'jquery', 'jquery-ui-progressbar' ), $this->version, false ); wp_localize_script( $this->plugin_name, 'objectL10n', array( 'delete_imported_data_confirmation_message' => __( 'All previously imported data will be deleted from WordPress.', 'fg-spip-to-wp' ), 'delete_all_confirmation_message' => __( 'All content will be deleted from WordPress.', 'fg-spip-to-wp' ), 'delete_no_answer_message' => __( 'Please select a remove option.', 'fg-spip-to-wp' ), 'import_completed' => __( 'IMPORT COMPLETED', 'fg-spip-to-wp' ), 'content_removed_from_wordpress' => __( 'Content removed from WordPress', 'fg-spip-to-wp' ), 'settings_saved' => __( 'Settings saved', 'fg-spip-to-wp' ), 'importing' => __( 'Importing…', 'fg-spip-to-wp' ), 'import_stopped_by_user' => __( 'IMPORT STOPPED BY USER', 'fg-spip-to-wp' ), 'internal_links_modified' => __( 'Internal links modified', 'fg-spip-to-wp' ), ) ); wp_localize_script( $this->plugin_name, 'objectPlugin', array( 'log_file_url' => $this->log_file_url, 'progress_url' => $this->progressbar->get_url(), )); } /** * Initialize the plugin */ public function init() { register_importer('fg-spip-to-wp', __('SPIP', 'fg-spip-to-wp'), __('Import categories, articles, news and images from a SPIP database into WordPress', 'fg-spip-to-wp'), array($this, 'importer')); } /** * Display the stored notices * * @since 2.0.0 */ public function display_notices() { foreach ( $this->notices as $notice ) { echo '
[' . $this->plugin_name . '] ' . $notice['message'] . "
(.*)#', '
$1', $text); $text = preg_replace('#
#', '$1', $text); // Line feeds $text = preg_replace(",\r\n?,S", "\n", $text); $text = preg_replace(",[:space:]],iS", "\n\n\\0", $text); $text = preg_replace(",
[:space:]],iS", "\\0\n\n", $text); // Tables $text = preg_replace(",^\n?[|],S", "\n\n|", $text); $text = preg_replace(",\n\n+[|],S", "\n\n\n\n|", $text); $text = preg_replace(",[|](\n\n+|\n?$),S", "|\n\n\n\n", $text); $regs = array(); if (preg_match_all(',[^|](\n[|].*[|]\n)[^|],UmsS', $text, $regs, PREG_SET_ORDER)) { foreach ($regs as $t) { $text = str_replace($t[1], $this->process_table_shortcodes($t[1]), $text); } } // Ordered and unordered lists if ( (strpos($text, "\n-*") !== false) || (strpos($text, "\n-#") !== false) ) { $text = $this->process_lists_shortcodes($text); } // Row starts $text = $this->process_row_starts($text); return $text; } /** * Convert the unordered and ordered lists SPIP shortcodes * * @param string $text Text * @return string Text */ private function process_lists_shortcodes($text) { $parags = preg_split(",\n[[:space:]]*\n,S", $text); $text = ''; $regs = array(); $pile_li = array(); $pile_type = array(); foreach ( $parags as $para ) { $niveau = 0; $lignes = explode("\n-", "\n" . $para); $type = ''; $first_item = true; foreach ( $lignes as $item ) { if ( $first_item ) { $text .= $item; $first_item = false; continue; } if ( preg_match(",^([*]*|[#]*)([^*#].*)$,sS", $item, $regs) ) { $profond = strlen($regs[1]); if ( $profond > 0 ) { $ajout=''; $nouv_type = (substr($item,0,1) == '*') ? 'ul' : 'ol'; $change_type = ($type AND ($type <> $nouv_type) AND ($profond == $niveau)) ? 1 : 0; $type = $nouv_type; while ( $niveau > $profond - $change_type ) { $ajout .= $pile_li[$niveau]; $ajout .= $pile_type[$niveau]; if (!$change_type) { unset ($pile_li[$niveau]); } $niveau --; } if ( $niveau == $profond && !$change_type ) { $ajout .= $pile_li[$niveau]; } while ( $niveau < $profond ) { if ( $niveau == 0 ) { $ajout .= "\n\n"; } $niveau ++; $ajout .= "<$type>"; $pile_type[$niveau] = "$type>"; } $ajout .= ""; $pile_li[$profond] = " "; } else { $ajout = "\n-"; } $text .= $ajout . $regs[2]; } } $ajout = ''; while ( $niveau > 0 ) { $ajout .= $pile_li[$niveau]; $ajout .= $pile_type[$niveau]; $niveau --; } $text .= $ajout; $text .= "\n\n"; } return substr($text, 0, -2); } /** * Convert the SPIP table shorcodes to HTML * * @since 2.14.0 * * @param string $text Text * @return string Text */ private function process_table_shortcodes($text) { $regs = array(); $thead = array(); $cols = array(); preg_match_all(',([|].*)[|]\n,UmsS', $text, $regs, PREG_PATTERN_ORDER); $lignes = array(); $debut_table = $summary = ''; $l = 0; $numeric = true; $reg_line1 = ',^(\|(' . _RACCOURCI_TH_SPAN . '))+$,sS'; $reg_line_all = ',^' . _RACCOURCI_TH_SPAN . '$,sS'; foreach ($regs[1] as $ligne) { $l++; if ($l == 1) { $cap = array(); if (preg_match(',^\|\|([^|]*)(\|(.*))?$,sS', rtrim($ligne,'|'), $cap)) { $l = 0; $caption = trim($cap[1]); if ( !empty($caption) ) { $debut_table .= "".$caption." \n"; } $summary = isset($cap[3])? ' summary="'.esc_html(trim($cap[3])).'"' : ''; } else if ( preg_match($reg_line1, $ligne, $thead) ) { preg_match_all('/\|([^|]*)/S', $ligne, $cols); $ligne = ''; $cols = $cols[1]; $colspan = 1; for ( $c = count($cols)-1; $c >= 0; $c-- ) { $attr = ''; if ( $cols[$c] == '<' ) { $colspan++; } else { if ( $colspan > 1 ) { $attr = " colspan='$colspan'"; $colspan = 1; } $ligne = "$cols[$c] $ligne"; } } $debut_table .= "" . $ligne." \n"; $l = 0; } } if ($l) { if ( strpos($ligne,"\n-*") !== false OR strpos($ligne,"\n-#") !== false ) { $ligne = $this->process_lists_shortcodes($ligne); } $ligne = preg_replace("/\n{2,}/", "
\n", $ligne); preg_match_all('/\|([^|]*)/S', $ligne, $cols); $lignes[] = $cols[1]; } } $rowspans = $numeric = array(); $n = count($lignes[0]); $k = count($lignes); for ( $i = 0; $i < $n; $i++ ) { $align = true; for ( $j = 0; $j < $k; $j++ ) { $rowspans[$j][$i] = 1; } for ( $j = 0; $j < $k; $j++ ) { $cell = trim($lignes[$j][$i]); if ( preg_match($reg_line_all, $cell) ) { $r = array(); if ( !preg_match('/^\d+([.,]?)\d*$/', $cell, $r) ) { $align = ''; break; } elseif ($r[1]) { $align = $r[1]; } } } $numeric[$i] = !$align ? '' : (" style='text-align: " . (/* $align !== true ?"\"$align\"" : */ 'right') . "'"); } $html = ''; for ( $l = count($lignes)-1; $l >= 0; $l-- ) { $cols = $lignes[$l]; $colspan = 1; $ligne = ''; for ( $c = count($cols)-1; $c >= 0; $c-- ) { $attr = isset($numeric[$c])? $numeric[$c] : ''; $cell = trim($cols[$c]); if ( $cell == '<' ) { $colspan++; } elseif( $cell == '^' ) { $rowspans[$l-1][$c] += $rowspans[$l][$c]; } else { if( $colspan>1 ) { $attr .= " colspan='$colspan'"; $colspan = 1; } if ( isset($rowspans[$l][$c]) && ($x=$rowspans[$l][$c]) > 1 ) { $attr .= " rowspan='$x'"; } $ligne = "\n' . $cols[$c] . ' ' . $ligne; } } $class = $this->alternate($l+1, 'even', 'odd'); $html = "$ligne \n$html"; } return "\n\n\n" . $debut_table . "\n" . $html . "\n" . "
\n\n"; } /** * Filter |alternate * * @param int $i Row number * @return mixed */ private function alternate($i) { $num = func_num_args(); $args = func_get_args(); if ( $num == 2 && is_array($args[1]) ) { $args = $args[1]; array_unshift($args,''); $num = count($args); } return $args[(intval($i)-1)%($num-1)+1]; } /** * Replace the starts of the rows * * @since 2.14.0 * * @param string $text Text * @return string Text */ private function process_row_starts($text) { $text = preg_replace( array( "/\n(----+|____+)/S", "/\n-- */S", "/\n_ +/S" ), array( "\n\n
\n\n", "\n
— ", "\n
" ), $text ); return $text; } /** * Clean the cache * */ public function clean_cache($terms = array()) { delete_option("category_children"); clean_term_cache($terms, 'category'); } /** * Import articles * * @return bool Import successful or not */ private function import_articles() { $this->log(__('Importing articles...', 'fg-spip-to-wp')); // Anti-duplicate $this->test_antiduplicate = false; // Hook for doing other actions before the import do_action('fgs2wp_pre_import_articles'); do { if ( $this->import_stopped() ) { break; } $posts = $this->get_articles($this->chunks_size); // Get the Spip articles $posts_count = count($posts); if ( is_array($posts) ) { foreach ( $posts as $post ) { $new_post_id = $this->import_article($post); if ( $new_post_id === false ) { return false; } // Hook for doing other actions after importing the post do_action('fgs2wp_post_import_post', $new_post_id, $post, 'article'); } } $this->progressbar->increment_current_count($posts_count); } while ( ($posts != null) && ($posts_count > 0) ); if ( !$this->import_stopped() ) { // Hook for doing other actions after the import do_action('fgs2wp_post_import_articles'); } return true; } /** * Import an article * * @since 2.0.0 * * @param array $post Post data * @return int new post ID | false | WP_Error */ public function import_article($post) { $object_type = 'article'; $post['titre'] = FG_Spip_to_WordPress_Tools::fix_encoding($post['titre']); $post['texte'] = $this->convert_spip1_longblob($post['texte']); // SPIP 1.x LONGBLOB $post['texte'] = FG_Spip_to_WordPress_Tools::fix_encoding($post['texte']); $post['chapo'] = FG_Spip_to_WordPress_Tools::fix_encoding($post['chapo']); // Anti-duplicate if ( !$this->test_antiduplicate ) { sleep(2); $test_post_id = $this->get_wp_post_id_from_spip_article_id($post['id']); if ( !empty($test_post_id) ) { $this->display_admin_error(__('The import process is still running. Please wait before running it again.', 'fg-spip-to-wp')); return false; } $this->test_antiduplicate = true; } $post['titre'] = $this->remove_id($post['titre']); // Remove the ID from the title // Hook for modifying the Spip post before processing $post = apply_filters('fgs2wp_pre_process_post', $post, $object_type); // Date $post_date = $this->sanitize_date($post['date']); $content = $post['texte']; $chapo = $post['chapo']; // Medias if ( !$this->plugin_options['skip_media'] ) { // Featured image $featured_image = $this->get_featured_image($post['id'], $object_type); list($featured_image, $post) = apply_filters('fgs2wp_pre_import_media', array($featured_image, $post)); $img_featured_image = ''; if ( !empty($featured_image) ) { $img_featured_image = ''; } // Replace documents shortcodes $chapo = $this->replace_document_shortcodes($chapo); $content = $this->replace_document_shortcodes($content); // Import media $result = $this->import_media_from_content($img_featured_image . $chapo . $content, $post_date); $post_media = $result['media']; $this->media_count += $result['media_count']; // Add the logo into the content if ( ($this->plugin_options['logo'] != 'as_featured') && !empty($img_featured_image) ) { $content = '' . $img_featured_image . '
' . $content; } } else { // Skip media $post_media = array(); } // Category $categories_ids = array(); $category_id = $post['id_rubrique']; if ( array_key_exists($category_id, $this->imported_categories) ) { $categories_ids[] = $this->imported_categories[$category_id]; } if ( count($categories_ids) == 0 ) { $categories_ids[] = 1; // default category } // Header $excerpt = ''; if ( !empty($chapo) ) { switch ( $this->plugin_options['introtext'] ) { case 'in_excerpt': $excerpt = $chapo; break; case 'in_content': $content = '' . $chapo . '
' . "\n\n" . $content; break; case 'in_excerpt_and_content': $excerpt = $chapo; $content = '' . $chapo . '
' . $content; break; } } // Process content $excerpt = $this->process_content($excerpt, $post_media); $content = $this->process_content($content, $post_media); // Insert the post $new_post = array( 'post_category' => $categories_ids, 'post_content' => $content, 'post_date' => $post_date, 'post_excerpt' => $excerpt, 'post_status' => $this->get_status($post['statut']), 'post_title' => $post['titre'], 'post_name' => sanitize_title($post['titre']), 'post_type' => $this->post_type, 'comment_status' => ($post['accepter_forum'] == 'non')? 'closed' : 'open', ); // Hook for modifying the WordPress post just before the insert $new_post = apply_filters('fgs2wp_pre_insert_post', $new_post, $post, $object_type); $new_post_id = wp_insert_post($new_post, true); // Increment the Spip last imported article ID update_option('fgs2wp_last_spip_article_id', $post['id']); if ( is_wp_error($new_post_id) ) { $this->display_admin_error(sprintf(__('Article #%d:', 'fg-spip-to-wp'), $post['id']) . ' ' . $new_post_id->get_error_message()); } else { // Add links between the post and its medias $this->add_post_media($new_post_id, $new_post, $post_media, $this->plugin_options['logo'] != 'in_content'); // Add the Spip ID as a post meta in order to modify links after add_post_meta($new_post_id, '_fgs2wp_old_article_id', $post['id'], true); if ( $this->post_type == 'page' ) { $this->pages_count++; } else { $this->posts_count++; } // Hook for doing other actions after inserting the post do_action('fgs2wp_post_insert_post', $new_post_id, $post, $object_type); } return $new_post_id; } /** * Convert a SPIP 1.x LONGBLOB to TEXT with the UTF8 encoding * * @since 2.10.0 * * @param string $text Text * @return string Text */ public function convert_spip1_longblob($text) { if ( $this->blob_encoding && ($this->spip_charset != 'utf-8') ) { $text = utf8_encode($text); } return $text; } /** * Import news * * @return bool Import successful or not */ private function import_news() { $this->log(__('Importing news...', 'fg-spip-to-wp')); // Anti-duplicate $this->test_antiduplicate = false; // Hook for doing other actions before the import do_action('fgs2wp_pre_import_news'); do { if ( $this->import_stopped() ) { break; } $posts = $this->get_news($this->chunks_size); // Get the Spip news $posts_count = count($posts); if ( is_array($posts) ) { foreach ( $posts as $post ) { $new_post_id = $this->import_one_news($post); if ( $new_post_id === false ) { return false; } // Hook for doing other actions after importing the post do_action('fgs2wp_post_import_post', $new_post_id, $post, 'breve'); } } $this->progressbar->increment_current_count($posts_count); } while ( ($posts != null) && ($posts_count > 0) ); if ( !$this->import_stopped() ) { // Hook for doing other actions after the import do_action('fgs2wp_post_import_news'); } return true; } /** * Import a news (breve) * * @since 2.0.0 * * @param array $post Post data * @return int new post ID | false | WP_Error */ public function import_one_news($post) { $object_type = 'breve'; $post['titre'] = FG_Spip_to_WordPress_Tools::fix_encoding($post['titre']); $post['texte'] = $this->convert_spip1_longblob($post['texte']); // SPIP 1.x LONGBLOB $post['texte'] = FG_Spip_to_WordPress_Tools::fix_encoding($post['texte']); // Anti-duplicate if ( !$this->test_antiduplicate ) { sleep(2); $test_post_id = $this->get_wp_post_id_from_spip_news_id($post['id']); if ( !empty($test_post_id) ) { $this->display_admin_error(__('The import process is still running. Please wait before running it again.', 'fg-spip-to-wp')); return false; } $this->test_antiduplicate = true; } // SPIP 2.0 fixes if ( version_compare($this->spip_version, '3', '<') ) { $post['titre'] = $this->remove_id($post['titre']); // Remove the ID from the title } // Hook for modifying the Spip post before processing $post = apply_filters('fgs2wp_pre_process_post', $post, $object_type); // Date $post_date = $this->sanitize_date($post['date_heure']); $content = $post['texte']; // Medias if ( !$this->plugin_options['skip_media'] ) { // Featured image $featured_image = $this->get_featured_image($post['id'], $object_type); list($featured_image, $post) = apply_filters('fgs2wp_pre_import_media', array($featured_image, $post)); $img_featured_image = ''; if ( !empty($featured_image) ) { $img_featured_image = ''; } // Replace documents shortcodes $content = $this->replace_document_shortcodes($content); // Import media $result = $this->import_media_from_content($img_featured_image . $content, $post_date); $post_media = $result['media']; $this->media_count += $result['media_count']; // Add the logo into the content if ( ($this->plugin_options['logo'] != 'as_featured') ) { $content = '' . $img_featured_image . '
' . $content; } } else { // Skip media $post_media = array(); } // Category $categories_ids = $this->get_wp_category_ids($post['id_rubrique'], $this->imported_categories); // Process content $content = $this->process_content($content, $post_media); // Insert the post $new_post = array( 'post_category' => $categories_ids, 'post_content' => $content, 'post_excerpt' => '', 'post_date' => $post_date, 'post_status' => $this->get_status($post['statut']), 'post_title' => $post['titre'], 'post_name' => sanitize_title($post['titre']), 'post_type' => 'post', ); // Hook for modifying the WordPress post just before the insert $new_post = apply_filters('fgs2wp_pre_insert_post', $new_post, $post, $object_type); $new_post_id = wp_insert_post($new_post, true); // Increment the Spip last imported post ID update_option('fgs2wp_last_spip_news_id', $post['id']); if ( is_wp_error($new_post_id) ) { $this->display_admin_error(sprintf(__('Article #%d:', 'fg-spip-to-wp'), $post['id']) . ' ' . $new_post_id->get_error_message()); } else { // Add links between the post and its medias $this->add_post_media($new_post_id, $new_post, $post_media, $this->plugin_options['logo'] != 'in_content'); // Add the Spip ID as a post meta in order to modify links after add_post_meta($new_post_id, '_fgs2wp_old_news_id', $post['id'], true); // Add the extra SPIP fields if ( !empty($post['lien_titre']) ) { add_post_meta($new_post_id, 'lien_titre', $post['lien_titre'], true); } if ( !empty($post['lien_url']) ) { add_post_meta($new_post_id, 'lien_url', $post['lien_url'], true); } $this->posts_count++; // Hook for doing other actions after inserting the post do_action('fgs2wp_post_insert_post', $new_post_id, $post, $object_type); } return $new_post_id; } /** * Get the WordPress status from the SPIP status * * @since 1.9.0 * * @param string $spip_status SPIP status * @return string WordPress status */ public function get_status($spip_status) { switch ( $spip_status ) { case 'publie': // published $status = 'publish'; break; case 'prop': // pending $status = 'pending'; break; default: $status = 'draft'; } return $status; } /** * Remove the ID at the beginning of a string * * @param string $string String * @return string String */ public function remove_id($string) { $result = preg_replace('/^\d+\. /', '', $string); return $result; } /** * Replace the articles shortcodes (art, br) in the post content * * @since 2.30.0 * * @param string $content Content * @return string Content */ private function replace_articles_shortcodes($content) { $matches = array(); // Replace the shortcodes like [anchor_text->art99] or [anchor_text->br99] if ( preg_match_all('#\[(.*?)->(art|br)(\d+)\]#', $content, $matches, PREG_SET_ORDER) > 0 ) { foreach ($matches as $match ) { $anchor_text = $match[1]; $short_object_type = $match[2]; // art | br $id = $match[3]; $object_type = ($short_object_type == 'br')? 'breve' : 'article'; if ( empty($anchor_text) ) { $anchor_text = $this->get_article_or_news_title($id, $object_type); } $replacement = '' . $anchor_text . ''; $content = preg_replace('#' . preg_quote($match[0]) . '#', $replacement, $content); } } return $content; } /** * Get the title of the article (or the news) * * @since 2.30.0 * * @param int $id Object ID * @param string $object_type Object type * @return string Title */ private function get_article_or_news_title($id, $object_type) { if ( $object_type == 'br' ) { $title = $this->get_news_title($id); } else { $title = $this->get_article_title($id); } return $title; } /** * Get a news title * * @since 2.30.0 * * @param int $id News ID * @return string Title */ private function get_news_title($id) { $title = 'Breve ' . $id; $prefix = $this->plugin_options['prefix']; $sql = " SELECT titre FROM ${prefix}breves b WHERE b.id_breve = '$id' LIMIT 1 "; $result = $this->spip_query($sql); if ( count($result) > 0 ) { $title = $result[0]['titre']; } return $title; } /** * Get an article title * * @since 2.30.0 * * @param int $id Article ID * @return string Title */ private function get_article_title($id) { $title = 'Article ' . $id; $prefix = $this->plugin_options['prefix']; $sql = " SELECT titre FROM ${prefix}articles a WHERE a.id_article = '$id' LIMIT 1 "; $result = $this->spip_query($sql); if ( count($result) > 0 ) { $title = $result[0]['titre']; } return $title; } /** * Replace the documents shortcodes (doc, img, emb, pdf) in the post content * @param string $content Content * @return string Content */ private function replace_document_shortcodes($content) { $matches = array(); $matches_align = array(); // Import the medias that use the SPIP shortcodes, , or if ( preg_match_all('#<(doc|img|emb|pdf)(\d+)(\|(.*?))?>#', $content, $matches, PREG_SET_ORDER) > 0 ) { foreach ($matches as $match ) { // $doc_embed_type = $match[1]; // doc | img | emb | pdf $doc_id = $match[2]; $doc_align = isset($match[4])? $match[4]: ''; $document = $this->get_document($doc_id); if ( !empty($document) ) { $filename = $document['fichier']; if ( !preg_match('/^http/', $document['fichier']) ) { $filename = $this->media_path . $filename; } if ( preg_match('/^txt=(.*)/', $doc_align, $matches_align) ) { $doc_title = $matches_align[1]; } elseif ( !empty($document['titre']) ) { $doc_title = $document['titre']; } else { $doc_title = basename($document['fichier']); } $filetype = wp_check_filetype($filename); // Description $description = !empty($document['descriptif'])? ' data-description="' . $document['descriptif'] . '"' : ''; if ( preg_match('/image/', $filetype['type']) ) { // Image // Alignment $alignment = ''; if ( !empty($doc_align) ) { $alignment = ' align="' . $doc_align . '"'; } if ( !empty($document['titre']) ) { // With caption $replacement = ''; } else { $replacement = ''; } } elseif ( preg_match('#^https://www.youtube.com#', $filename) ) { // Embed YouTube video $replacement = '[embed]' . $filename . '[/embed]'; } else { // Not an image $replacement = '' . $doc_title . ''; } $content = preg_replace('#' . preg_quote($match[0]) . '#', $replacement, $content); } } } // Import the medias that use the SPIP shortcodes [anchor_text->img] if ( preg_match_all('#\[(.*?)->(doc|img|emb|pdf)(\d+)\]#', $content, $matches, PREG_SET_ORDER) > 0 ) { foreach ($matches as $match ) { $anchor_text = $match[1]; // $doc_embed_type = $match[2]; // doc | img | emb | pdf $doc_id = $match[3]; $document = $this->get_document($doc_id); if ( !empty($document) ) { $filename = $this->media_path . $document['fichier']; // Description $description = !empty($document['descriptif'])? ' data-description="' . $document['descriptif'] . '"' : ''; $replacement = '' . $anchor_text . ''; $content = preg_replace('#' . preg_quote($match[0]) . '#', $replacement, $content); } } } return $content; } /** * Get the matching WP category ID from a SPIP category * * @since 2.5.0 * * @param int $category_id SPIP category ID * @param array $imported_categories Mapping table of SPIP and WP categories IDs * @return array List of categories IDs */ public function get_wp_category_ids($category_id, $imported_categories) { $categories_ids = array(); if ( array_key_exists($category_id, $imported_categories) ) { $categories_ids[] = $imported_categories[$category_id]; } if ( count($categories_ids) == 0 ) { $categories_ids[] = 1; // default category } return $categories_ids; } /** * Stop the import * */ public function stop_import() { update_option('fgs2wp_stop_import', true); } /** * Test if the import needs to stop * * @return boolean Import needs to stop or not */ public function import_stopped() { return get_option('fgs2wp_stop_import'); } /** * Get Spip categories * * @param int $limit Number of categories max * @return array of Categories */ protected function get_categories($limit=1000) { $categories = array(); $prefix = $this->plugin_options['prefix']; $last_category_id = (int)get_option('fgs2wp_last_category_id'); // to restore the import where it left $sql = " SELECT r.id_rubrique, r.id_parent, r.titre, r.descriptif, r.texte FROM ${prefix}rubriques r WHERE r.id_rubrique > '$last_category_id' ORDER BY r.id_rubrique LIMIT $limit "; $sql = apply_filters('fgs2wp_get_categories_sql', $sql, $prefix); $categories = $this->spip_query($sql); $categories = apply_filters('fgs2wp_get_categories', $categories); return $categories; } /** * Get Spip articles * * @param int $limit Number of articles max * @return array of articles */ protected function get_articles($limit=1000) { $articles = array(); $last_spip_article_id = (int)get_option('fgs2wp_last_spip_article_id'); // to restore the import where it left $prefix = $this->plugin_options['prefix']; // Hooks for adding extra cols and extra joins $extra_cols = apply_filters('fgs2wp_get_posts_add_extra_cols', '', 'article'); $extra_joins = apply_filters('fgs2wp_get_posts_add_extra_joins', '', 'article'); $sql = " SELECT a.id_article AS id, a.titre, a.id_rubrique, a.chapo, a.texte, a.date, a.statut, a.visites, a.accepter_forum $extra_cols FROM ${prefix}articles a $extra_joins WHERE a.statut NOT IN ('refuse', 'poubelle') -- don't get the cancelled and the removed articles AND a.id_article > '$last_spip_article_id' ORDER BY a.id_article LIMIT $limit "; $sql = apply_filters('fgs2wp_get_posts_sql', $sql, $prefix, $extra_cols, $extra_joins, $last_spip_article_id, $limit); $articles = $this->spip_query($sql); return $articles; } /** * Get Spip news * * @param int $limit Number of news max * @return array of news */ protected function get_news($limit=1000) { $news = array(); $last_spip_news_id = (int)get_option('fgs2wp_last_spip_news_id'); // to restore the import where it left $prefix = $this->plugin_options['prefix']; // Hooks for adding extra cols and extra joins $extra_cols = apply_filters('fgs2wp_get_posts_add_extra_cols', '', 'breve'); $extra_joins = apply_filters('fgs2wp_get_posts_add_extra_joins', '', 'breve'); $sql = " SELECT b.id_breve AS id, b.titre, b.id_rubrique, b.texte, b.date_heure, b.statut, b.lien_titre, b.lien_url $extra_cols FROM ${prefix}breves b $extra_joins WHERE b.statut NOT IN ('refuse', 'poubelle') -- don't get the cancelled and the removed news AND b.id_breve > '$last_spip_news_id' ORDER BY b.id_breve LIMIT $limit "; $sql = apply_filters('fgs2wp_get_posts_sql', $sql, $prefix, $extra_cols, $extra_joins, $last_spip_news_id, $limit); $news = $this->spip_query($sql); return $news; } /** * Get the featured image of an article or from a news * * @param int $post_id * @param string $object_type article | breve * @return string Image path */ protected function get_featured_image($post_id, $object_type) { $images_path = trailingslashit($this->get_media_root_path()) . $this->media_path; // Object type switch ( $object_type ) { case 'article': $prefix = 'arton'; break; case 'breve': $prefix = 'breveon'; break; default: return ''; // unknown type } // Extensions $extensions = array('jpg', 'JPG', 'png', 'PNG', 'gif', 'GIF'); foreach ( $extensions as $extension ) { $image_file_path = $images_path . $prefix . $post_id . '.' . $extension; if ( $this->file_exists($image_file_path) ) { return $image_file_path; } } return ''; } /** * Get the media root path * * @since 2.3.0 * * @return string Media root path */ public function get_media_root_path() { $path = ''; switch ( $this->plugin_options['media_import_method'] ) { case 'http': $path = $this->plugin_options['url']; break; case 'local': $path = $this->plugin_options['root_directory']; break; } return $path; } /** * Test if a file exists * * @since 2.3.0 * * @param string $filePath * @return boolean True if the file exists */ public function file_exists($filePath) { switch ( $this->plugin_options['media_import_method'] ) { case 'http': return $this->url_exists($filePath); case 'local': return file_exists($filePath); } } /** * Test if a remote file exists * * @param string $filePath * @return boolean True if the file exists */ public function url_exists($filePath) { $url = str_replace(' ', '%20', $filePath); // Try the get_headers method $headers = @get_headers($url); $result = preg_match("/200/", $headers[0]); if ( !$result && strpos($filePath, 'https:') !== 0 ) { // Try the fsock method $url = str_replace('http://', '', $url); if ( strstr($url, '/') ) { $url = explode('/', $url, 2); $url[1] = '/' . $url[1]; } else { $url = array($url, '/'); } $fh = fsockopen($url[0], 80); if ( $fh ) { fputs($fh,'GET ' . $url[1] . " HTTP/1.1\nHost:" . $url[0] . "\n"); fputs($fh,"User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36\n\n"); $response = fread($fh, 22); fclose($fh); $result = (strpos($response, '200') !== false); } else { $result = false; } } return $result; } /** * Get the image path * * @return string Image path */ public function get_image_path() { $dir_img = $this->get_spip_meta('dir_img'); if ( empty($dir_img) ) { $dir_img = 'IMG/'; } return $dir_img; } /** * Get the SPIP version * * @return string SPIP version */ private function get_spip_version() { $version = 0; $raw_plugin_info = $this->get_spip_meta('plugin'); if ( strpos($raw_plugin_info, 'a:') !== false ) { $plugin_info = @unserialize($raw_plugin_info); if ( !$plugin_info ) { $plugin_info = @unserialize(utf8_decode($raw_plugin_info)); } $version = isset($plugin_info['SPIP']['version'])? $plugin_info['SPIP']['version']: 0; } else { $version_installee = $this->get_spip_meta('version_installee'); $version = !empty($version_installee)? $version_installee: 0; } return $version; } /** * Get the meta value from the SPIP meta table * * @param string $meta_key * @return string meta value */ public function get_spip_meta($meta_key) { $meta_value = ''; $prefix = $this->plugin_options['prefix']; $sql = " SELECT m.valeur FROM ${prefix}meta m WHERE m.nom = '$meta_key' LIMIT 1 "; $result = $this->spip_query($sql); if ( isset($result[0]['valeur']) ) { $meta_value = $result[0]['valeur']; } return $meta_value; } /** * Test if the texts are encoded as blob * * @return bool */ private function is_text_encoded_as_blob() { global $spip_db; $blob_encoded = false; $prefix = $this->plugin_options['prefix']; $table = 'articles'; $column = 'texte'; switch ( $this->plugin_options['driver'] ) { case 'mysql': $sql = "SHOW COLUMNS FROM ${prefix}${table} LIKE '$column'"; break; case 'sqlite': $sql = "PRAGMA table_info(${prefix}${table})"; break; } $query = $spip_db->query($sql, PDO::FETCH_ASSOC); if ( $query !== false ) { if ( $this->plugin_options['driver'] == 'sqlite' ) { // SQLite $result = $query->fetchAll(); foreach ( $result as $row ) { if ( isset($row['name']) && ($row['name'] == $column) ) { if ( preg_match('/blob/', $row['type']) ) { $blob_encoded = true; } break; } } } else { // MySQL $result = $query->fetch(); if ( isset($result['Type']) && preg_match('/blob/', $result['Type']) ) { $blob_encoded = true; } } } return $blob_encoded; } /** * Import post medias from content * * @param string $content post content * @param date $post_date Post date (for storing media) * @param array $options Options * @return array: * array media: Medias imported * int media_count: Medias count */ public function import_media_from_content($content, $post_date, $options=array()) { $media = array(); $media_count = 0; $matches = array(); $alt_matches = array(); $title_matches = array(); $description_matches = array(); if ( preg_match_all('#<(img|a)(.*?)(src|href)="(.*?)"(.*?)>#', $content, $matches, PREG_SET_ORDER) > 0 ) { if ( is_array($matches) ) { foreach ($matches as $match ) { $filename = $match[4]; $other_attributes = $match[2] . $match[5]; // Image Alt $image_alt = ''; if (preg_match('#alt="(.*?)"#', $other_attributes, $alt_matches) ) { $image_alt = wp_strip_all_tags(stripslashes($alt_matches[1]), true); } // Image caption $image_caption = ''; if (preg_match('#title="(.*?)"#', $other_attributes, $title_matches) ) { $image_caption = $title_matches[1]; } // Image description $image_description = ''; if (preg_match('#data-description="(.*?)"#', $other_attributes, $description_matches) ) { $image_description = $description_matches[1]; } $attachment_id = $this->import_media($image_alt, $filename, $post_date, $options, $image_caption, $image_description); if ( $attachment_id !== false ) { $media_count++; $media[$filename] = $attachment_id; } } } } return array( 'media' => $media, 'media_count' => $media_count ); } /** * Import a media * * @param string $name Image name * @param string $filename Image URL * @param date $date Date * @param array $options Options * @param string $image_caption Image caption * @param string $image_description Image description * @return int attachment ID or false */ public function import_media($name, $filename, $date, $options=array(), $image_caption='', $image_description='') { if ( $date == '0000-00-00 00:00:00' ) { $date = date('Y-m-d H:i:s'); } $import_external = ($this->plugin_options['import_external'] == 1) || (isset($options['force_external']) && $options['force_external'] ); $filename = urldecode(html_entity_decode($filename)); // for filenames with spaces or accents $filetype = wp_check_filetype($filename); if ( empty($filetype['type']) || ($filetype['type'] == 'text/html') ) { // Unrecognized file type return false; } $media_root_path = $this->get_media_root_path(); // Upload the file from the Spip web site to WordPress upload dir if ( preg_match('/^http/', $filename) ) { if ( $import_external || // External file preg_match('#^' . $media_root_path . '#', $filename) // Local file ) { $old_filename = $filename; } else { return false; } } elseif ( strpos($filename, $media_root_path) !== 0 ) { // Don't add the media_root_path if it has already been added if ( strpos($filename, '/') === 0 ) { // Avoid a double slash $old_filename = untrailingslashit($media_root_path) . $filename; } else { $old_filename = trailingslashit($media_root_path) . $filename; } } else { $old_filename = $filename; } if ( $this->plugin_options['media_import_method'] == 'http' ) { $old_filename = str_replace(" ", "%20", $old_filename); // for filenames with spaces } $img_dir = strftime('%Y/%m', strtotime($date)); $uploads = wp_upload_dir($img_dir); $new_upload_dir = $uploads['path']; $new_filename = $filename; if ( $this->plugin_options['import_duplicates'] == 1 ) { // Images with duplicate names $new_filename = preg_replace('#.*'. untrailingslashit($this->media_path) . '/#', '', $new_filename); $new_filename = str_replace('http://', '', $new_filename); $new_filename = str_replace('/', '_', $new_filename); } $basename = basename($new_filename); $basename = sanitize_file_name($basename); $new_full_filename = $new_upload_dir . '/' . $basename; if ( $this->plugin_options['force_media_import'] || !file_exists($new_full_filename) || (filesize($new_full_filename) == 0) ) { // print "Copy \"$old_filename\" => $new_full_filename
"; switch ( $this->plugin_options['media_import_method'] ) { case 'http': // HTTP remote copy if ( ! @$this->remote_copy($old_filename, $new_full_filename) ) { $error = error_get_last(); $error_message = $error['message']; $this->display_admin_error("Can't copy $old_filename to $new_full_filename : $error_message"); return false; } break; case 'local': // Local copy if ( !copy($old_filename, $new_full_filename) ) { $error = error_get_last(); $error_message = $error['message']; $this->display_admin_error("Can't copy $old_filename to $new_full_filename : $error_message"); return false; } break; } } $post_title = !empty($name)? $name : preg_replace('/\.[^.]+$/', '', $basename); // Image Alt $image_alt = ''; if ( !empty($name) ) { $image_alt = wp_strip_all_tags(stripslashes($name), true); } // GUID $upload_dir = wp_upload_dir(); $guid = str_replace($upload_dir['basedir'], $upload_dir['baseurl'], $new_full_filename); $attachment_id = $this->insert_attachment($post_title, $basename, $new_full_filename, $guid, $date, $filetype['type'], $image_alt, $image_caption, $image_description); return $attachment_id; } /** * Check if the attachment exists in the database * * @param string $name * @return object Post */ private function get_attachment_from_name($name) { $name = preg_replace('/\.[^.]+$/', '', basename($name)); $r = array( 'name' => $name, 'post_type' => 'attachment', 'numberposts' => 1, ); $posts_array = get_posts($r); if ( is_array($posts_array) && (count($posts_array) > 0) ) { return $posts_array[0]; } else { return false; } } /** * Save the attachment and generates its metadata * * @param string $attachment_title Attachment name * @param string $basename Original attachment filename * @param string $new_full_filename New attachment filename with path * @param string $guid GUID * @param date $date Date * @param string $filetype File type * @param string $image_alt Image description * @param string $image_caption Image caption * @param string $image_description Image description * @return int|false Attachment ID or false */ public function insert_attachment($attachment_title, $basename, $new_full_filename, $guid, $date, $filetype, $image_alt='', $image_caption='', $image_description='') { $post_name = 'attachment-' . sanitize_title($attachment_title); // Prefix the post name to avoid wrong redirect to a post with the same name // If the attachment does not exist yet, insert it in the database $attachment_id = 0; $attachment = $this->get_attachment_from_name($post_name); if ( $attachment ) { $attached_file = basename(get_attached_file($attachment->ID)); if ( $attached_file == $basename ) { // Check if the filename is the same (in case of the legend is not unique) $attachment_id = $attachment->ID; } } if ( $attachment_id == 0 ) { $attachment_data = array( 'guid' => $guid, 'post_date' => $date, 'post_mime_type' => $filetype, 'post_name' => $post_name, 'post_title' => $attachment_title, 'post_status' => 'inherit', 'post_content' => $image_description, 'post_excerpt' => $image_caption, ); $attachment_id = wp_insert_attachment($attachment_data, $new_full_filename); add_post_meta($attachment_id, '_fgs2wp_imported', 1, true); // To delete the imported attachments } if ( !empty($attachment_id) ) { if ( preg_match('/(image|audio|video)/', $filetype) ) { // Image, audio or video // you must first include the image.php file // for the function wp_generate_attachment_metadata() to work require_once(ABSPATH . 'wp-admin/includes/image.php'); $attach_data = wp_generate_attachment_metadata( $attachment_id, $new_full_filename ); wp_update_attachment_metadata($attachment_id, $attach_data); // Image Alt if ( !empty($image_alt) ) { update_post_meta($attachment_id, '_wp_attachment_image_alt', addslashes($image_alt)); // update_post_meta expects slashed } } return $attachment_id; } else { return false; } } /** * Get a document by its ID * * @param int $doc_id SPIP document ID * @return array document data */ private function get_document($doc_id) { $document = array(); $prefix = $this->plugin_options['prefix']; $sql = " SELECT d.id_document, d.fichier, d.titre, d.descriptif, d.taille, d.date FROM ${prefix}documents d WHERE d.id_document = '$doc_id' LIMIT 1 "; $documents = $this->spip_query($sql); if ( isset($documents[0]) ) { $document = $documents[0]; } return $document; } /** * Process the post content * * @param string $content Post content * @param array $post_media Post medias * @return string Processed post content */ public function process_content($content, $post_media=array()) { if ( !empty($content) ) { $content = $this->replace_articles_shortcodes($content); $content = $this->spip_format($content); $content = preg_replace("/\\\\+'/", "'", $content); // Fix the multiple escapes of ' // Replace media URLs with the new URLs $content = $this->process_content_media_links($content, $post_media); // Replace video links $content = $this->process_video_links($content); // For importing backslashes $content = addslashes($content); $content = apply_filters('fgs2wp_process_content', $content); } return $content; } /** * Replace media URLs with the new URLs * * @param string $content Post content * @param array $post_media Post medias * @return string Processed post content */ private function process_content_media_links($content, $post_media) { $matches = array(); $matches_caption = array(); if ( is_array($post_media) ) { // Get the attachments attributes $attachments_found = false; $medias = array(); foreach ( $post_media as $old_filename => $attachment_id ) { $media = array(); $media['attachment_id'] = $attachment_id; $media['url_old_filename'] = urlencode($old_filename); // for filenames with spaces if ( preg_match('/image/', get_post_mime_type($attachment_id)) ) { // Image $image_src = wp_get_attachment_image_src($attachment_id, 'full'); $media['new_url'] = $image_src[0]; $media['width'] = $image_src[1]; $media['height'] = $image_src[2]; } else { // Other media $media['new_url'] = wp_get_attachment_url($attachment_id); } $medias[$old_filename] = $media; $attachments_found = true; } if ( $attachments_found ) { // Remove the links from the content $this->post_link_count = 0; $this->post_link = array(); $content = preg_replace_callback('#<(a) (.*?)(href)=(.*?)#i', array($this, 'remove_links'), $content); $content = preg_replace_callback('#<(img) (.*?)(src)=(.*?)>#i', array($this, 'remove_links'), $content); // Process the stored medias links foreach ($this->post_link as &$link) { $new_link = $link['old_link']; $alignment = ''; if ( preg_match('/(align="|float: )(left|right|center)/', $new_link, $matches) ) { $alignment = 'align' . $matches[2]; } if ( preg_match_all('#(src|href)="(.*?)"#i', $new_link, $matches, PREG_SET_ORDER) ) { $caption = ''; foreach ( $matches as $match ) { $old_filename = $match[2]; $link_type = ($match[1] == 'src')? 'img': 'a'; if ( array_key_exists($old_filename, $medias) ) { $media = $medias[$old_filename]; if ( array_key_exists('new_url', $media) ) { if ( (strpos($new_link, $old_filename) > 0) || (strpos($new_link, $media['url_old_filename']) > 0) ) { // URL encode the filename $new_filename = basename($media['new_url']); $encoded_new_filename = rawurlencode($new_filename); $new_url = str_replace($new_filename, $encoded_new_filename, $media['new_url']); $new_link = preg_replace('#(' . preg_quote($old_filename) . '|' . preg_quote($media['url_old_filename']) . ')#', $new_url, $new_link, 1); if ( $link_type == 'img' ) { // images only // Define the width and the height of the image if it isn't defined yet if ((strpos($new_link, 'width=') === false) && (strpos($new_link, 'height=') === false)) { $width_assertion = isset($media['width']) && ($media['width'] != 0)? ' width="' . $media['width'] . '"' : ''; $height_assertion = isset($media['height']) && ($media['height'] != 0)? ' height="' . $media['height'] . '"' : ''; } else { $width_assertion = ''; $height_assertion = ''; } // Caption shortcode if ( preg_match('/class=".*caption.*?"/', $link['old_link']) ) { if ( preg_match('/title="(.*?)"/', $link['old_link'], $matches_caption) ) { $caption_value = str_replace('%', '%%', $matches_caption[1]); $align_value = ($alignment != '')? $alignment : 'alignnone'; $caption = '[caption id="attachment_' . $media['attachment_id'] . '" align="' . $align_value . '"' . $width_assertion . ']%s' . $caption_value . '[/caption]'; } } $align_class = ($alignment != '')? $alignment . ' ' : ''; $new_link = preg_replace('##', "', $new_link); } } } } } // Add the caption if ( $caption != '' ) { $new_link = sprintf($caption, $new_link); } } $link['new_link'] = $new_link; } // Reinsert the converted medias links $content = preg_replace_callback('#__fg_link_(\d+)__#', array($this, 'restore_links'), $content); } } return $content; } /** * Remove all the links from the content and replace them with a specific tag * * @param array $matches Result of the preg_match * @return string Replacement */ private function remove_links($matches) { $this->post_link[] = array('old_link' => $matches[0]); return '__fg_link_' . $this->post_link_count++ . '__'; } /** * Restore the links in the content and replace them with the new calculated link * * @param array $matches Result of the preg_match * @return string Replacement */ private function restore_links($matches) { $link = $this->post_link[$matches[1]]; $new_link = array_key_exists('new_link', $link)? $link['new_link'] : $link['old_link']; return $new_link; } /** * Add a link between a media and a post (parent id + thumbnail) * * @param int $post_id Post ID * @param array $post_data Post data * @param array $post_media Post medias IDs * @param boolean $set_featured_image Set the featured image? */ public function add_post_media($post_id, $post_data, $post_media, $set_featured_image=true) { $thumbnail_is_set = false; if ( is_array($post_media) ) { foreach ( $post_media as $attachment_id ) { $attachment = get_post($attachment_id); if ( !empty($attachment) ) { $attachment->post_parent = $post_id; // Attach the post to the media $attachment->post_date = $post_data['post_date'] ;// Define the media's date wp_update_post($attachment); // Set the featured image. If not defined, it is the first image of the content. if ( $set_featured_image && !$thumbnail_is_set ) { set_post_thumbnail($post_id, $attachment_id); $thumbnail_is_set = true; } } } } } /** * Modify the video links * * @param string $content Content * @return string Content */ private function process_video_links($content) { if ( strpos($content, '{"video"') !== false ) { $content = preg_replace('/(