Coder Social home page Coder Social logo

inpsyde / wpml2mlp Goto Github PK

View Code? Open in Web Editor NEW
10.0 15.0 6.0 1.18 MB

Convert posts from an existing WPML multilingual site via WXR Export/Import for MultilingualPress

Home Page: https://wordpress.org/plugins/wpml-to-multilingualpress/

License: GNU General Public License v2.0

PHP 99.61% CSS 0.03% JavaScript 0.36%
wordpress plugin transfer wpml-plugin multilingual

wpml2mlp's People

Contributors

bueltge avatar derpixler avatar dnaber-de avatar jonziemlich avatar nullbytes avatar s7nkuridza avatar sailingcode avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wpml2mlp's Issues

Importer: add importer to wp tools

If wpml2mlp in a Multisite aktiv also there have to exisxts under (Tools/import)[wp-admin/import.php]a section for the wpml2mlp wxr parser.

wpml2mlp_import_modul

Make export possible on single site

Despite the Readme says it is possible to activate the plugin on a single site, this does not work. The export should be accessible on a single site, the import functions must be disabled then.

Implement wxr importer

We have to implement a custom wxr importer for the created wxr export files from single wmpl installation. We could not use the WordPress Importer-Plugin, there is no Hook to parse custom wxr elements.

If wpml2mlp in a Multisite aktiv also there have to exisxts under (Tools/import)[wp-admin/import.php]a section for the wpml2mlp wxr parser.

wpml2mlp_import_modul

At the 0.0.1.2 version of wpml2mlp we have turned the xliff export format to the WordPress defauld wxr. On every Post there have Translations that are appended at the post item.

    <wp:translation lang="en" post_id="2401"/>
    <wp:translation lang="de" post_id="2491"/>
    <wp:translation lang="nl" post_id="2071"/>
    <wp:translation lang="es" post_id="2566"/>
    <wp:translation lang="fr" post_id="2593"/>

Our wxr parser have to map the Translations to mlp.


Subtasks:

  • #25 Importer: XML-Parsing
    • Iterators
    • User parser
    • Term parser
    • Post parser
    • Comment parser
  • #49 Importer: Element Filter
    • Duplicate post filter
    • Duplicate term filter
    • Duplicate comment filter
    • Duplicate user filter
  • #26 Importer: Datawriting
    • User Importer
    • Term Importer
    • Post Importer
    • File importer
    • Comment Importer
  • #32 Importer: API
    • Type\ImportUser
    • Type\ImportTerm
    • Type\ImportPost
    • Type\ImportComment
  • Modules: Object worker (connect iterators, parser, filters ( #49 ) and importer)
    • User
    • Terms
    • Posts
    • Comments
  • Module: MLP relation
    • Link posts
    • Link terms
  • Ancestor resolving
    • resolve post ancestors
    • resolve term ancestors
    • resolve comment ancestors
  • Relation resolving
    • post/author relations
    • comment/post relations
    • post/term relations
  • Logging
  • WP-CLI
    • import command
  • DI
    • Configure DI Container

[Importer] Consistent API to map element IDs in meta-values

Whenever element IDs are stored as meta data value, the relation will break on import when these IDs changes. So right before we import meta data we provide a filter passing the meta data and the instance of the ID mapper.

As everything else, this API has to be independent of the progress of the import, so it is not stated that the ID is available at the moment of the first processing.

This will be part of the meta-data importer described in #57

Todo:

  • Provide an interface for value filters Import\Filter\ValueFilterableInterface.
  • Provide implementations of this filter to handle simple serialized and non-serialized meta values ( SingleIdMetaValueFilter, RecursiveIdMetaValueFilter
  • Provide a list that composes all filters for any type/key pair Import\Data\MetaFilterListInterface and Import\Data\MetaFilterListInterface
  • Provide a connector for the importer objects that applies the filters from the list to the value right before input Import\Service\ImportMetaFilterInterface and Import\Service\ImportMetaFilter
  • Fire the action w2m_import_meta_not_filterable (in the connector service) when a filter is not filterable right now
  • Provide a collector that listens to this action Import\Data\ImportListeningMetaFilterList
  • Provide a module that tries to resolve all postponed filters at the end of the import Import\Module\ResolvingPendingMetaFilter
  • Provide a controller that connects everything Controller\MetaFilterApi
  • Provide an action to apply custom filters to the list w2m_import_meta_filter
  • Use an internal composite in Data\MetaFilterList to have only one filter instance per type/key pair. If one of the composed filter is not able to filter the value, no other filter must be applied in the first time (Service\ImportMetaFilter). Otherwise we would get in trouble with multiple record metas on clean-up.
  • Apply all this for user, comment and term-meta if we respect these in future
  • Document all the stuff

Term Locals as Object

at the current solution we work with an array like this:

'locale_relations' => array(
                'en_US' => 13,
                'fr_CH' => 32
            )

A better way is working in this case with an object:

interface W2M\Import\Type\LocaleRelationInterface {

    /**
     * @return int
     */
    public function origin_id();

    /**
     * @return string
     */
    public function locale();
}

wpml2mlp Splash screen

If the Plugin aktivated in Singlesite with wmpl we show a splesh screen with informations to install a neu Multisite oder setup a multisite from the current Installation.

At the splash Screen are the Exportfiles linked. At the end of the Screen is a Button like Plugin deactivate now click on it the export files will deleted and the Plugin turns off.

Refactor Observer interfaces, provide listener interfaces instead.

The current idea of the observer interface depends on the mutable behavior of the Type\WpImport{TYPE} objects. This has two downsides:

  • it forces the Importer instances to actual call $importType->id( $new_id ); which breaks encapsulation.
  • it is overall redundant. We can solve each task (primarily the ID mapping) by simply listening to the w2m_{TYPE}_imported actions.

Further, the current Import\Data\IdObserverInterface is limited to be used for all types. Listeners to single types are not designated, which violates the interface-segregation principle.

The refactored structure:

interface Import\Data\PostImportListenerInterface {

    /**
     * @wp-hook w2m_post_imported
     *
     * @param WP_Post $wp_post
     * @param Import\Type\ImportPostInterface $import_post
     *
     * @return void
     */
    public function record_post( WP_Post $wp_post, Type\ImportPostInterface $import_post );
}

along with that there are Import\Data\ImportTermListenerInterface, Import\Data\ImportUserListenerInterface and of course Import\Data\ImportCommentListenerInterface.

The Import\Data\IdObserverInterface will be replaced by Import\Data\ImportListenerInterface which is just a »semantic« interface and extends all these new four types:

interface ImportListenerInterface extends 
    ImportPostListenerInterface,
    ImportTermListenerInterface,
    ImportUserListenerInterface,
    ImportCommentListenerInterface 
{}

This requires also a refactoring of Import\Data\PresetUserTypeIdMapper, Import\Data\ImportListeningTypeIdMapper and Controller\DataIdObserverProvider.

Corrupt destination language at export

The destination language on xliff-files is wrong.

Note: wpml set the current lang at admin area by Filter at the post overview and at the admin bar!

In this case the current lang is set by the method Wpml2mlp_Helper::get_main_language(); here is going some wrong, so that we get not the real current lang.

italian

italian-source-view


Solution

A save way to get the current lang-code is to use the constant ICL_LANGUAGE_CODE lock at the wpml API

Multisite: don't activate plugins network wide

When the Multisite is already installed, the WPML and WPML2MLP plugins need to be activated on the main single site that needs to be exported, not network wide. I got confused that the export didn't work.

To do: Enhance the documentation and maybe adding a admin notice that both plugins need to be installed at the main sub-site when activating them network wide.

Exporter: Add taxonomy as separate node to term

Currently the structure of an exported term looks like this:

<wp:category>
    <wp:term_id />
    <wp:category_nicename />
    <wp:category_parent />
    <wp:cat_name />
    <wp:category_description />
</wp:category>

This forces the importer to tread terms depending on their taxonomy.
It would be way easier to pass the taxonomy as a separate node to the complete term:

<wp:category>
    <wp:term_id />
    <wp:category_nicename />
    <wp:category_parent />
    <wp:cat_name />
    <wp:category_description />
    <wp:taxonomy>category</wp:taxonomy>
</wp:category>

[Importer] Consolidate error action names and signatures in WpPostImporter

Currently there are several error actions for errors that may occur during one logical process (importing post, importing file, importing term).

I would like to see them combined to one action per entity:

  • wp_import_post_error when something went wrong with the post importing process (including set term relations and meta) The domain should be handled by WP_Errors error code (post, post_meta, post_terms).
  • wp_import_file_error. This includes errors on any file system operation as well as HTTP.

The signature should follow the those of the other importers (described in #39 ): First parameter is an instance of WP_Error followed by the import object. Any other contextual data (response values, IDs, etc.) can be passed as data with the WP_Error object.

Subtask of this: #51

Export: improve get_language_info()

In inc/Wpml2mlp_Helper.php the function get_language_info() retrieves the language for the given post. The SQL retrieves the first entry it gets by the post ID from the database. However, in the wp_icl_translations table there can be more than one entry for the post ID, with a different element_type, on grown WPML installations:

test1

As you can see in the above screenshot, the row with the element_type comment has a different language_code as the second entry, which is the one we need. As in the get_language_info() function the SQL only gets the first row, the exported XLIFF files are completely mixed up with wrong entries on each language file.

To do: The SQL does not only need to check on the correct post ID, but also on the correct post type. In the function get_all_posts() of the inc/Wpml2mlp_Helper.php file, the post types are selected and used to retrieve the posts needed for the export. The same get_post_types() function can be used to check on all possible post types within the wp_icl_translations table for retrieving the correct language of each post.

Error with package antecedent/patchwork:1.4.0 in integration tests

After updating the dependencies I get the following errors:

$ composer update --prefer-dist
Loading composer repositories with package information
Updating dependencies (including require-dev)
  - Removing antecedent/patchwork (1.3.5)
  - Installing antecedent/patchwork (1.4.0)
    Loading from cache

$ phpunit -c phpunit-integration.xml

Warning: flock(): Illegal operation argument in /var/www/projects/inpsyde/wpml-to-mlp/wp-content/plugins/wpml2mlp/vendor/antecedent/patchwork/src/CodeManipulation/Stream.php on line 185

Warning: file_put_contents(): Exclusive locks are not supported for this stream in /var/www/projects/inpsyde/wpml-to-mlp/wp-content/plugins/wpml2mlp/vendor/inpsyde/wp-tests-starter/src/WpTestsStarter/WpTestsStarter.php on line 304

When setting the dependencies back to the previous state, the errors not longer appears.

Importer: API

Reflect the structure from the parsed data #25 in an API. Don't deal with arrays.

Blank screen after activation on empty site

Hi,

I've got an empty site.
Just installed Multilingual Press (free version) and WPML to MLP.

When I "network activate" wpml to mlp I've got this error

Fatal error: Call to a member function get_name() on string in /mysite/wp-content/plugins/multilingual-press/inc/db/Mlp_Content_Relations.php on line 47

Split Service\ObjectImporterInterface into generic type importers

Currently there's the Service\ObjectImporterInterface with the methods import_post() and import_term() (and later there would have been import_author().

For many reasons it makes more sense to split these interface into three separate ones:

namespace W2M\Import\Service;

use 
    W2M\Import\Type;

interface PostImporterInterface {

    public function import_post( Type\ImportPostInterface $post );
}
namespace W2M\Import\Service;

use 
    W2M\Import\Type;

interface TermImporterInterface {

    public function import_post( Type\ImportTermInterface $term );
}
namespace W2M\Import\Service;

use 
    W2M\Import\Type;

interface UserImporterInterface {

    public function import_post( Type\ImportUserInterface $post );
}

The implementations should have the names WpPostImporter, WpTermImporter and WpUserImporter.

XLIFF Background

Format for Ex-Import is XLIFF.

Spezifikation

Validator

Examples:

<?xml version="1.0" encoding="utf-8" ?>
<xliff version="1.1" xml:lang='en'>
 <file source-language='en' target-language='de' datatype="plaintext" original="Sample.po">
  ...
   <body>
    <trans-unit id="1" restype="button" resname="IDC_TITLE">
     <source>Title</source>
    </trans-unit>
    <trans-unit id="2" restype="label" resname="IDC_STATIC">
     <source>&amp;Path:</source>
    </trans-unit>
  ...
 </file>
 <file source-language='en' target-language='fr' datatype="plaintext" original="Sample.po">
    <trans-unit id="1" restype="button" resname="IDC_TITLE">
  ...
   </body>
 </file>
</xliff>
<?xml version="1.0" ?>
<xliff version="1.0">
    <file original="global" source-language="en_US" target="fi" datatype="plaintext">
        <body>
          <trans-unit id="1">
            <source>Application Name</source>
            <target>Sovelluksen nimi</target>
          </trans-unit>
          <trans-unit id="2">
            <source>Home</source>
            <target>Koti</target>
          </trans-unit>
          <trans-unit id="3">
            <source>Exit</source>
            <target>Poistua</target>
          </trans-unit>
        </body>
    </file>
  </xliff>
  • Another example
<xliff xmlns='urn:oasis:names:tc:xliff:document:2.0' version='2.0'
 srcLang='en' trgLang='fr'>
 <file id='1'>
  <val:validation xmlns:val='urn:oasis:names:tc:xliff:validation:2.0'>
   <val:rule startsWith='*'/>
  </val:validation>
  <unit id='1'>
   <originalData>
    <data id='d1'>&lt;B></data>
    <data id='d2'>&lt;/B></data>
   </originalData>
   <segment>
    <source>* Hello <pc id='1' dataRefStart='d1' dataRefEnd='d2' type='fmt' subType='xlf:b'>World</pc>! </source>
    <target>* Bonjour <pc id='1' dataRefStart='d1' dataRefEnd='d2' type='fmt' subType='xlf:b'>tout le monde</pc> ! </target>
   </segment>
   <segment>
    <source>Welcome in the universe of <pc id='2' dataRefStart='d1' dataRefEnd='d2' type='fmt' subType='xlf:b'>XLIFF 2</pc>.</source>
   </segment>
  </unit>
 </file>
</xliff>

PHP class

Improve migration process

What happens when the new MultiSite is different to the source?

Example: Pictures are loaded from the source by there `attachment_url ' and imported to WordPress with default sizes. Is on the source a Theme activated, which uses its own thumbnail formats and this is not installed or active on the target Thumbnails are not generated.

Question: Should wpml2mlp migrate not only the content but remember also to characteristics of the source, when differences block the import and provide instructions to the user?

Fact is: the real problem arises if the new multisite characteristics are not equal to the source. Users perform a export/import and expect that everything works as before. In some cases that will not work because the user forgot to set your systems equal. This affects not only that thumbnail example!


Was passiert eigentlich wenn die neu aufgesetzt Multisite sich von der Quelle unterscheidet?

​**Beispiel:**​ Es werden Bilder anhand der `attachment_url’ von der Quelle geladen und nach WP-Standard Importiert. Hat die Quelle nun ein Theme, welches eigene thumbnail formate nutzt und ist dieses auf dem Ziel nicht installiert oder aktive werden Thumbnails nicht erzeugt.

​**Frage:**​ Sollte wpml2mlp nicht nur die Inhalte migrieren sondern sich auch auf Eigenschaften der Quelle merken, Prüfen, bei Differenzen den Import blockieren und dem Benutzer Handlungsanweisungen geben?

Fakt ist: das eigentliche Problem entsteht denn wenn die neue Multisite installiert wird. Benutzer führen einen Export, einen Import durch und erwarten, dass alles wie gehabt funktioniert. Es wird Anwendungsfälle geben, bei den das nicht funktionieren wird, weil die Benutzer vergessen Ihre Systeme gleich einzustellen. Das betrifft nicht nur, dass Thumbnail Beipsiel!

Import: Attachments

Implement attachment import.

Example on how to use wp_handle_sideload(): http://wordpress.stackexchange.com/a/36083/31323 (the answer shows the usage of media_handle_sideload() but the structure of the parameter is identical to the one for wp_handle_sideload().

  • Update W2M\Import\Type\ImportPostInterface:
namespace W2M\Import\Type;

interface ImportPostInterface {

    /**
     * ...
     */

    /**
     * @return string
     */
    public function remote_attachment_url();

}
  • Implement the new method in W2M\Import\Type\WpImportPost.
  • Parse <wp:attachment_url> in W2M\Import\Service\WpPostParser if exists. Propagate an error if it not exists and the post is of type attachment.
  • Update W2M\Import\Service\WpPostImporter to handle the file:
    • Download the file to a temporary file
    • »Handle sideload«
    • Import relevant metadata (but skip these, that pointing to data structures of the remote system like _wp_attached_file if we cannot force a 1:1 mirror of the file paths of the remote system)
    • delete the temporary file

Code style issues

Hi,

the following notes are the result of a short review. They are in no particular order.

  • Please use another prefix. mlp_ is reserved for the main plugin.
  • Use the MultilingualPress autoloader. See A basic plugin for MultilingualPress for an example.
  • Make sure that WPML is actually active before your try to access its API. The plugin dies with a fatal error otherwise.
  • Separate object creation and class declaration: Move the class WPML2MLP_Importer to a separate file.
  • Use existing instances. There is no need to recreate instances of Mlp_Site_Relations or Mlp_Content_Relations, they are provided by MultilingualPress.
  • We will introduce unit and integration tests for MultilingualPress and its extensions soon. Please make your code ready for that:
    • Do not use singletons.
    • Do not register hook callbacks (add_action() and add_filter()) in constructors, this is not testable.
    • Try to limit the cyclomatic complexity to 5, the NPath complexity to 50. The PHP Mess Detector is very useful for such checks (usable in PhpStorm via Composer).
  • Add the hook to the doc block of callback handlers to make the code easier to understand. Example:
/**
 * Adds the menu option to the settings
 * 
 * @wp-hook network_admin_menu
 */
public function add_menu_option() {
}
  • Add an admin notice with a link to the settings page after activation.
  • The settings page is not clear: Yes/no options should be expressed with checkboxes, not with radio buttons. What happens when the user selects no? Please make that clear, or use just two different submit buttons. The user should never have to guess.
  • Use proper localization functions for visible strings. Include a text domain, because _e( 'WPML 2 MLP' ) is not translatable.
  • In WPML2MLP_Importer::run_import(), move the POST handling to a separate method or class, make sure you do not import everything again after a page reload. Use admin-post.php as form action, and redirect the user back to the settings page when you are done. For the export, see this instruction.
  • Why is there a class for zip files in the plugin? WordPress comes with PclZip, can we use that instead?

Implement custom term support

At the current version is no custom term support implemented. Custom terms have to included at the export files. Custom term support have to implement as a additional service via filter or something like else.

Importer: XML-Parsing

The following structures has to be read out of the XML-File:

  • User wp:user
  • Terms wp:category, wp:tag(?), wp:nav_menu_item(?), wp:term(?)
    • Term relations
  • Posts item
    • MetaData
    • Post relations
  • Comments

The interface format of the entities…

User

Attributes:

 int:    origin_user_id
 string: name
 string: email
 string: display_name
[string: first_name]
[string: last_name]
[object: roles]

[]… maybe empty values
roles has to be defined later

Terms

Attributes:

 int:    origin_term_id
 string: taxonomy
 string: name
 string: slug
[string: description]
[int:    origin_parent_term_id]
[array:  locale_relations]

Term locale relations

 int:      origin_post_id
 string:   locale

Posts

Attributes:

 int:      origin_post_id
 string:   post_title
 string:   post_guid
 DateTime: post_date
 string:   comment_status
 string:   ping_status
 string:   post_status
 string:   post_type
 bool:     is_sticky
[string:   origin_link]
[string:   post_excerpt]
[string:   post_content]
[string:   post_name]
[int:      origin_post_parent_id]
[int:      menu_order]
[string:   post_password]
[array:    terms]
[array:    meta]
[array:    locale_relations]

Post meta

Attributes:

 string:   meta_key
 mixed:    meta_value

Post terms

Attributes:

 int:      origin_term_id
 string:   taxonomy
 string:   name
 string:   slug

Post locale relations

Attributes:

 int:      origin_post_id
 string:   locale

Comments

Attributes:

  int         origin_post_id
  string      author_name
  string      author_email
  string      author_url
  string      author_ip
  DateTime    date
  string      content
  int         karma
  string      approved
  string      agent
  string      type
  int         origin_user_id
  int         origin_parent_comment_id
  array       meta

Consolidate action signatures in Service\Wp{TYPE}Importer's

Replace {TYPE} with

  • user
  • term
  • post
  • comment

Use always singular unless it is specified in a different way!

Import (wp_insert_{TYPE}) failed

/**
 * Attach error handler/logger here
 *
 * @param WP_Error $error
 * @param Type\Import{TYPE}Interface $import_{TYPE}
 */
do_action( 'w2m_import_{TYPE}_error', $error, $import_{TYPE} );

Parent object does not exist

(Only for term, post and comment.)

/**
 * @param WP_{TYPE} $wp_{TYPE}
 * @param Type\Import{TYPE}Interface $import_{TYPE}
 */
do_action( 'w2m_import_missing_{TYPE}_ancestor', $wp_{TYPE}, $import_{TYPE} );

{TYPE} successfully imported

/**
 * @param WP_{TYPE} $wp_{TYPE}
 * @param Type\Import{TYPE}Interface $import_{TYPE}
 */
do_action( 'w2m_{TYPE}_imported', $wp_{TYPE}, $import_{TYPE} );

Additional errors

E.g. when linking of terms or insertion of meta data fails.
Please use the following scheme for the parameter signature of any actions:
WP_Error, Import_Element
Pass any contextual data with the WP_Error object like it's done in the parsers.

Persistent activation errors

I tried to activate the plugin on a single site install:

  1. with no other plugins active. -> Error: WPML is needed.
  2. with WPML active -> Error: Multisite needed.

In both cases I couldn't return to the plugin list, to deactivate the plugin. The wp_die() always blocked access. Needed to rename the plugins folder. -> Possible but annoying.

Auto deactivate the plugin on fail with an error on top of the list would be nice.

Export: change translations tag

at the current version of export files the translation relations will saved as a single tag with attributes.

<wp:translation lang="de" post_id="2485"/>
<wp:translation lang="nl" post_id="769"/>
<wp:translation lang="es" post_id="2563"/>
<wp:translation lang="fr" post_id="2594"/>
<wp:translation lang="it" post_id="2546"/>

For consistency parsing we want use this format.

<wp:translation>
    <wp:locale>nl_NL</wp:locale>
    <wp:element_id>4711</wp:element_id>
</wp:translation>

Failed to move categories

I converted a lower german website with the plugin and the categories didn't make it into the new sites. There is just the uncategorized category.

Here the original category list, it's still complete in the base site:
bildschirmfoto 2015-07-23 um 12 27 39

PSR4 Autoloading

Apply namespaces and PSR 4 autoloading using composer.
Base namespace: W2M\

Import causes WPML to check for own tables

When we create the new sites and we start to import data my local errorlog files up with requests for wp_3_icl_translations tables. We should advice the users not to enable WPML for the network.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.