Connect and Translate WooCommerce Attributes

Connect and Translate WooCommerce Attributes

Connect and Translate WooCommerce Attributes
MultilingualPress is built to perfectly integrate with the WooCommerce environment. And hence it can also properly connect and translate the WooCommerce Attributes.
Let』s check how this works in this brief tutorial.

Table of Contents

Create an attribute, an exampleSame attribute on different sub site: set the connectionMultilingualPress attribute connection established
1. Create an attribute, an example
Before connecting WooCommerce attributes in MultilingualPress, we first need to create one.
So, let』s create an attribute in our WordPress Multisite Network Shops: for example we create a color attribute in the English sub site.
To achieve that we go to Products->Attributes . From here we set the attribute name as color and the related slug as color.
After that we can then configure some Terms using the Configure Terms link shown in the picture below.
Create WooCommerce Attributes and Terms
Hence we have some Terms (Blue, Gary, Green, Red, Yellow) for the color attribute.
2. Same attribute on different sub site: set the connection
Suppose now to set a similar attribute on another sub site, let』s say a Spanish version of the English one described in the previous section.
In that case we can similarly proceed in creating an attribute, but this time the Terms will be properly translated in Spanish language.
Let』s focus on the 「Blue」 Term. This in Spanish language is 「Azul」. We proceed and create this Term.
At this point we need to understand how to connect the Attribute between the two sites.
We want that the color attribute in the English site is connected via MultlingualPress to the color attribute in the Spanish site. To achieve that they have to share exactly the same slug: color in this case.
As we can see the slug in the English site is color .
WooCommerce Attribute slug in English language site set as 「color」
And similarly in the Spanish site the slug is still color.
WooCommerce Attribute slug in Spanish language site set as 「color」
In the following picture we see again that the color attribute in the Spanish version site with the slug set as color but we also show that the Azul Term is configured.
Create WooCommerce Attributes and Terms in Spanish language site
3. MultilingualPress attribute connection established
Now that the color WooCommerce Attributes share the same slug, it is easily possible to set the language relations of the Terms of through the translation metaboxes.
In fact, as reported in the picture below, when you edit one of the terms and search for related term in the other language site,  MultilingualPress will try to find the term within the attribute with the same slug.
In that case and will not look for term in attribute called Size for example. Instead it will check for the slug color .
The Translation Metabox is now able to properly find and connect the related Terms
Filling the form with the 「Az」 values, will let MultilingualPress search within the English color Attribute, and retrieve the Azul Term.
If you want to know more about how to properly set your MultilingualPress environment have a look at our Getting Started with MultilingualPress tutorial.

How to programmatically connect content

How to programmatically connect content

How to programmatically connect content
If you want to connect content programmatically across sites you need to know the IDs of the posts you want to connect beforehand. So let say that we have 3 sites with site ids 1, 2 and 3 and we want to connect a post with the following post ids on each site:
post id 42 in site 1
post id 123 in site 2
post id 321 in site 3
Following code snippet creates the $contentIds array of key value pairs with site id as key and post id as value. Afterwards we pass it to the createRelationship method as first parameter to connect the content.
$api = InpsydeMultilingualPressresolve(
InpsydeMultilingualPressFrameworkApiContentRelations::class
);

$contentIds = [
1 => 42,
2 => 123,
3 => 321,
];

$api->createRelationship($contentIds, 'post');

How to translate Custom Fields with MultilingualPress 3

How to translate Custom Fields with MultilingualPress 3

How to translate Custom Fields with MultilingualPress 3
In this document, we』ll explain how to translate custom fields using MultilingualPress 3. For the sake of simplicity, we are going to use the Advanced Custom Fields Plugin to create the custom fields. Just keep in mind that the process described here is the same for any other Plugin that allows you to create custom fields or if you are creating them manually using WordPress Custom Fields API.
Note: MultilingualPress offers since version 3.5.0 full compatibility for Advanced Custom Fields. Therefore, Advanced Custom Fields can also be translated for connected pages within the WordPress editor. Here is a special Tutorial for translating Advanced Custom Fields explaining all functions.
There are currently two approaches about how to implement custom field translations.

Table of Contents

Creating a new site based on an existing oneCreating the custom fields manually in each siteInstall and Network activate Advanced Custom FieldsCreate a custom field in the main siteCreate the custom field in site 2Connect the posts that contain the custom fields
1. Creating a new site based on an existing one
The first one is setting up the main site, create the custom fields and the content. Once everything is created we can create a new site based on the existing one. Doing so will copy everything to the new site and we are only going to need to translate the content. Everything else including the custom fields will be automatically created in the new site.
Here is a quick video showing the process of creating a new site based on an existing one with existing custom fields:

Video Playerhttps://multilingualpress.org/wp-content/uploads/sites/12/2020/03/create-site-custom-fields.mp400:0000:0000:00Use Up/Down Arrow keys to increase or decrease volume.

2. Creating the custom fields manually in each site
The second approach is when you already have two or more sites connected and you want to include custom fields. In that case, the custom fields need to be created manually on each site.
In this article, we are going to explain the second approach. To do so we´ll create a new WordPress Multisite installation with two sites connected:
Two connected sites in a multisite using MultilingualPress 3
2.1. Install and Network activate Advanced Custom Fields
Install the Plugin Advanced Custom Fields
Go to My Sites -> Network Admin -> Plugins and install Advanced Custom Fields. In this case, we are network activating it, that decision will depend on the nature of each Plugin if it includes support for Multisite or not. If you are in doubt, the recommended way is to activate individually on each site, like you usually do in a single site.
2.2. Create a custom field in the main site
Advanced Custom Fields UI – create a new group and a field
In site 1 create a new group and a new field using Advanced Custom Fields UI.
Set value of the custom field in a post
In site 1 fill the value of the custom field in a post.
2.3. Create the custom field in site 2
In order to create the custom fields in site 2, we can use the export/import functionality provided by Advanced Custom Fields on the Tools page. But because in our example we are only dealing with one single group with one single field, we are going to create it manually in site 2.
Create the custom field in site 2
The most important thing to keep in mind here is to ensure that the field slugs are exactly the same across all connected sites. That way the code displaying the fields will grab the correct translation based on the site the visitor is currently in. So let』s say that you create a new field with the slug 『some_field』 on site 1, you need to create a field with the same exact slug 『some_field』 in site 2.
2.4. Connect the posts that contain the custom fields
Connect the posts with custom fields
Finally, in order to be able to connect custom fields across sites, you simply need to connect the posts containing the fields using MultilingualPress translation metabox.

How to disable broken save_post callbacks

How to disable broken save_post callbacks

How to disable broken save_post callbacks
This tutorial is part of our MultilingualPress 2 documentation. In case you are using the newer version 3, please switch to MultilingualPress 3.
Many plugins are not multisite aware. This is rarely a problem, because each site in a network works almost like a normal site in a single-site installation. But sometimes … things go really wrong.
There is a hook, the action save_post, that can be called multiple times when a post is saved: one time for each site. Many plugins are not aware of this, they run their own code on every call to save_post without a check for the site context. The result is that they are either deleting user data on the other sites, or they overwrite existing data.
This happens when MultilingualPress updates the post translations.
Site A save_post - MultilingualPress {
creates or updates translations:
- switch_to_blog( Site B) -> save_post
- switch_to_blog( Site C) -> save_post
- switch_to_blog( Site D) -> save_post

return to Site A
}
MultilingualPress removes all POST data before the other save_post actions are called, and it restores it when it switches back. Normal plugins use a nonce as a basic security check before they try to save anything. Since we remove the nonce along with the POST data, they will not do anything. So far, so good.
Unfortunately, some plugin author don』t use nonces. They just try to save their data, without proper context checks. There is nothing we can do about that.
But you can. You have to find the code (function or class method) that is registered for the save_post action and then remove it earlier. There is another hook that runs right before save_post: the filter wp_insert_post_data. You can hook your own custom callback to that filter, check if the current context is in a switched site and then remove the 「evil」 callback. Don』t forget to return the filtered value, that』s necessary for filters.
Here is an example for the Custom Sidebars plugin:
add_filter( 'wp_insert_post_data', function( $data ) {

if ( is_multisite()
&& ms_is_switched()
&& class_exists( 'CustomSidebarsEditor' )
) {
$cse = CustomSidebarsEditor::instance();
remove_action( 'save_post', array( $cse, 'store_replacements' ) );
}

return $data;
});
If you are a plugin or theme author and want to be sure that your code is safe to run in a multisite: please contact me. I,or one of my colleagues, will look at it and tell you what needs to be changed.

How to move from MarketPress to MultilingualPress.org

How to move from MarketPress to MultilingualPress.org

How to move from MarketPress to MultilingualPress.org
This tutorial is part of our MultilingualPress 2 documentation. In case you are using the newer version 3, please switch to MultilingualPress 3.
As of January 13th 2017, we only offer MultilingualPress Premium Support on our own platforms multilingualpress.org for english support and multilingualpress.de for german support. If you have questions please contact us via our contact form or directly at [email protected].

You own a MultilingualPress Premium Support licence from MarketPress? For the renewal of your license, you will receive a 30$ voucher via the MarketPress renewal newsletter. With this you can purchase MultilingualPress Premium Support on multilingualpress.org.

 
Thank you very much and welcome to your new MultilingualPress community!

 
Your  MultilingualPress  Team – proudly Powered by Inpsyde

Requirements – What do I need to get MultilingualPress running smoothly?

Requirements – What do I need to get MultilingualPress running smoothly?

Requirements – What do I need to get MultilingualPress running smoothly?
This tutorial is part of our MultilingualPress 2 documentation. In case you are using the newer version 3, please switch to MultilingualPress 3.

To have MultilingualPress running smoothly on your website, it should meet the following requirements:

WordPress as multi-site, at least Version 4.2.
at least PHP 5.4.0. Newer versions are faster.

MultilingualPress cannot be used in a single-site WordPress installation. You need to have a multi-site installed. See our tutorial How to install multi-site.

MultilingualPress site duplication issue: a solution

MultilingualPress site duplication issue: a solution

MultilingualPress site duplication issue: a solution
One of the powerful features available in MultilingualPress is the so called 「Based on」 option. Through this option you can create a  new site as a duplication of an already existing other sub site.
Hence this feature let you to create a new sub site as a copy of another, copying also the source site content , the configurations and the translation connections.
But in a particular case one or more third party plugins could interrupt the process. Let』s see what the problem is and how MultilingualPress solves it.

Table of Contents

Duplicate your site in one clickDuplication issue due to third party plugins redirectionThe solution: uncheck plugin activation option
1. Duplicate your site in one click
Suppose you have a shop in your own language, but you wish also to create a new one in another language.
The two shops should be quite similar, only languages will be different.
In that case would be much faster for you if the new site is created as a duplication of the former one. No manual settings, just get what you need in one click.
That』s what you can achieve with MultilingualPress!
What you need to do is to select the 「Based on」 option on the new site creation page. For further details on this feature please have a look to our Getting Started with MultilingualPress guide.
2. Duplication issue due to third party plugins redirection
Unfortunately if the source site has installed some third party plugins whose activation includes also redirection, this  could interrupt the duplication process .
What happen is this: when you create a new site as a copy of another, depending on the settings, MultilingualPress will activate all the plugins of the source site also in the new one.
But if any of these plugins perform a redirection within the activation, this would lead to a process interruption. The redirection will stop the duplication process.
3. The solution: uncheck plugin activation option
How to solve this? Luckily MultilingualPress has another option that prevent this issue to happen right before to start the creation process.
You just need to uncheck the 「Activate all plugins that are active on the source site「 as reported in the picture here below.
Create a new site preventing redirects on activation
This way MultilingualPress duplicates the source site, but it also does not activate all the plugin in the remote site during the process.
So no redirection happens, and the duplication completes properly.
Of course, after the creation, all the needed plugin need to be manually activated.

How to copy post meta to the remote sites

How to copy post meta to the remote sites

How to copy post meta to the remote sites
This code snippet shows how to copy post meta to the remote site(s). In the example it gets the value of yoast_wpseo_title post meta from the request and then updates the value in the connected sites.
add_action('multilingualpress.metabox_after_relate_posts', function($context, $request) {

// get post meta value from source site
$yoastWpseoTitleValue = (string)$request->bodyValue(
'yoast_wpseo_title',
INPUT_POST,
FILTER_SANITIZE_STRING
);

// switch to remote sites and save post meta
$remoteSiteId = $context->remoteSiteId();
$remotePostId = $context->remotePostId();
switch_to_blog($remoteSiteId);
update_post_meta($remotePostId, '_yoast_wpseo_title', $yoastWpseoTitleValue);
restore_current_blog();
}, 10, 2);
The above example shows a case when a plugin registers the custom field, but it is also possible to connect custom fields generated by WordPress from Custom Fields UI in post editor, so let say we have created a new custom field my-field in site one and we want to synchronize the value to the same custom field in site 2, once we have created the custom field with the same name in site 2, we can use the multilingualpress.metabox_after_relate_posts action like so:
add_action('multilingualpress.metabox_after_relate_posts', function ($context, $request) {
// switch to source site
switch_to_blog($context->sourceSiteId());

// grab post meta value
$value = get_post_meta($context->sourcePostId(), 'my-field', true);

// switch to remote site
restore_current_blog();

// update post meta
update_post_meta($context->remotePostId(), 'my-field', $value);
}, 10, 2);

How to translate Advanced Custom Fields (ACF) with MultilingualPress 3

How to translate Advanced Custom Fields (ACF) with MultilingualPress 3

How to translate Advanced Custom Fields (ACF) with MultilingualPress 3
Starting from version 3.5 MultilingualPress offers a new module that lets you easily manage the custom fields translation through the Plugin Advanced Custom Fields (ACF). To show how this feature works in your Multilingual site, here we provide a brief tutorial on the topic.
Note: For custom fields created by using other Plugins or the WordPress API for custom fields, we recommend this tutorial.

Table of Contents

Environment settings: WordPress Multisite and MultilingualPressACF installation and activationACF Module ActivationACF SettingsACF Translation
1. Environment settings: WordPress Multisite and MultilingualPress
First of all, create a Multisite WordPress installation and then install MultilingualPress version 3.5 or above. In case you need support to install a multisite environment, you can follow the instruction here reported: how-to-install-wordpress-multisite
When your Network is ready you can then proceed in installing and network activating MultilingualPress. Also in this case, if you need support you can refer to the following document: Installing-MultilingualPress-3
You are just a step far for creating your Multilingual site: proceed in creating two or more subsites as explained in Create-a-new-website-within-the-multisite-and-set-the-language-for-the-site, and connect them in MultilingualPress through the Relationships section.
If now we go to MySites→Network Admin→MultilingualPress we see that the ACF Module is disabled.
If ACF Plugin is not installed and activated the MultilingualPress module is disabled
This because we haven』t installed yet the ACF Plugin in the Network. To accomplish that let』s proceed to the next section.
2. ACF installation and activation
In this section, we can now proceed in installing the Advanced Custom Fields Plugin. To do so you can log into your WordPress installation back end and then go to My Sites→Network Admin→Plugins.
From there, search for Advanced Custom Fields By Elliot Condon Plugin, then install and activate the Plugin by clicking on the button.
Download, install and activate ACF Plugin
This way you activated the ACF Plugin on your site.
3. ACF Module Activation
The next step is to activate the ACF module in MultilingualPress. This can be easily accomplished by going into MySites→Network Admin and selecting the MultilingualPress link in the left menu.
This way you access the MultilingualPress settings page. From there, in the Modules tab, click on the ACF checkbox and finally press the Save Changes button to activate the ACF module.
ACF Module Activation in MultilingualPress
4. ACF Settings
In this section, we provide an example of how the custom fields should be set.
Suppose we want to add a proverb every time we create a post. To achieve that let』s create a group of new custom fields to be added to the standard posts called Proverbs Group.
Go to your main subsite Dashboard and then head to Custom Fields→Add New. Fill in the group text field the name Proverbs Group as shown below.
Create a group field using ACF Plugin
In the Location section, it is possible to specify to which post type the new fields will be added.
Right under the Field Group name, it is possible to add one or more custom fields pressing the Add Field button . Let』s create a text area field with label Proverb as shown below.
Create a custom field using ACF Plugin
The ACF Plugin lets you configure several types of fields, for further details you can refer to the official documentation
At this point the fields are ready in our main subsite, but now we also need to create the same custom fields in all the subsites where we want manage their translation through MultilingualPress.
To proceed, go to the main subsite Dashboard and there head to Custom Fields→Tools . In that section, it is possible to export the custom fields we want to replicate in other subsites.
Select the Proverbs Group checkbox in the Export Field Group meta-box, then press Export File to create the file with the data to export.
Export the custom filed through the ACF Tool
Similarly, from the Dashboard of a secondary sub-site related with the main one, the site it in our example, import the previously exported file: head to Custom Fields→Tools and in the Import Field Group section upload the file and then press Import File .
Import the custom filed through the ACF Tool
At this point, we have the same custom fields in two subsites connected through MultilingualPress.
Finally let』s check how MultilingualPress manages such fields.
5. ACF Translation
At this point we are ready to work with the custom field through MultilingualPress.
To do so, let』s create a new post in the main subsite and let』s fill the Proverb field with the sentence  「You can lead a horse to water, but you can』t make him drink.「, as shown in the picture below.
Insert a proverb in a new post
Then in the translation meta-box that relates the content with the connected subsite, it in our example, we select the radio button option in order to create a copy of our post.
Creating the post on the remote site via translation meta-box
After this selection, the other tabs are enabled: we can access the ACF tab and set the checkbox in order to overwrite the remote custom field content with the proverb sentence we previously inserted.
Copy ACF field option on translation meta-box
After that we can save our post and go to the second subsite, it in our case. There we will find the new post created via MultilingualPress with the same custom field filled with the expected proverb content.
In the remote subsite, the post is duplicated and the custom field content is duplicated too
Similarly, you will be able to propagate any custom field content to all the related subsites. Just working only on a single post, all the related ones will be then properly managed by MultilingualPress.

How to get translations programmatically

How to get translations programmatically

How to get translations programmatically
This tutorial is part of our MultilingualPress 2 documentation. In case you are using the newer version 3, please switch to MultilingualPress 3.
The most important API in MultilingualPress for you is probably the Language API. This API has a method get_translations() that you can use to get a prepared set of translations for posts of any post type, terms of any taxonomy, a search term, the front page or a blog page.
You can access that API with a filter:
$mlp_language_api = apply_filters( 'mlp_language_api', NULL );
MultilingualPress will transform that NULL value now into an instance of the class Mlp_Language_Api. In other words: The variable $mlp_language_api is an object now. But you should still test that, just in case the user has deactivated MultilingualPress:
$mlp_language_api = apply_filters( 'mlp_language_api', NULL );

if ( ! is_a( $mlp_language_api, 'Mlp_Language_Api_Interface' ) )
return;
As you can see, you should test against the Interface Mlp_Language_Api_Interface, not against the concrete class. This enables other plugins to replace our implementation with a custom translation handler.
Today, we are looking just at $mlp_language_api->get_translations( $args );

Table of Contents

Arguments for Mlp_Language_Api::get_translations()Methods for Mlp_TranslationMethods for Mlp_LanguageExample: Add translation links to the post contentTheme integration
Arguments for Mlp_Language_Api::get_translations()
$args is an array, we can pass some options here to tweak the results.

Name
Type
Description

site_id
int
Base site. Usually the current site.

content_id
int
post or term_taxonomy ID, not term ID.

type
string
Either post, term, post_type_archive, search or front_page.

strict
bool
When TRUE (default) only matching exact translations will be included.

search_term
string
If you want to translate a search.

post_type
string
For post type archives.

include_base
bool
Include the base site in returned list.

All parameters are optional. MultilingualPress will try to find proper values for them. We recommend to set the content_id for terms and posts though, because that is not always available, at least not in a reliable way.
Now let』s see how our code could look like:
$mlp_language_api = apply_filters( 'mlp_language_api', NULL );

if ( ! is_a( $mlp_language_api, 'Mlp_Language_Api_Interface' ) )
return;

$args = array (
'strict' => TRUE,
'include_base' => TRUE
);

/** @var Mlp_Language_Api_Interface $mlp_language_api */
$translations = $mlp_language_api->get_translations( $args );

if ( empty ( $translations ) )
return;
Note that $mlp_language_api->get_translations( $args ) will return an empty array if there are no translations even when we set include_base to TRUE.
Now, let』s say the translations are not empty. We get an array of objects, each an instance of Mlp_Translation which implements the Mlp_Translation_Interface. That sounds complicated, but it just means that we have a set of methods on each object to get information about the translation.
Methods for Mlp_Translation

Method
Return type
Description

get_source_site_id()
int
The site ID the translation is based on.

get_target_site_id()
int
The ID of the site where the translation can be found.

get_page_type()
string
Either post, term, post_type_archive, search or front_page.

get_icon_url()
Mlp_Url_Interface
An object, an instance of a class implementing the Mlp_Url_Interface. It has a magic method __toString(), so we can cast it to a string and get an escaped URL.

get_target_title()
string
The title of the translation, for example the post title or the term name.

get_target_content_id()
int
The term_taxonomy_id or the post id. This is empty for other translation types like post type archives or search.

get_remote_url()
string
The URL for the translation.

get_language()
Mlp_Language_Interface
An object, an instance of a class implementing the Mlp_Language_Interface.

The Mlp_Translation::get_language() object deserves an explanation. It has three public methods.
Methods for Mlp_Language

Method
Return type
Description

get_priority()
int
A number between 0 and 10. See the post about Language negotiation for an explanation.

is_rtl()
bool
Whether the translation is in a right-to-left language (like Hebrew) or not.

get_name( $name )
string
Different representations of the language. Default is the language in its native writing, eg. Deutsch for German. We strongly recommend to use that, because that』s most easily to recognize for your readers.
Other allowed parameters are english to get the English name, http to get the HTTP value (for example de-AT) or custom to get the custom name you have set in the site properties.
You can also use language_short to get just the first part of a language code with subsets, eg. just de.

Example: Add translation links to the post content
Let』s see what we can do with all this code. The following example adds very simple translation links to the post content. It uses the first part of the language code and sets it to uppercase. The images are used too, if they are available.
add_filter( 'the_content', function( $content ) {

if ( ! is_singular() )
return $content;

$mlp_language_api = apply_filters( 'mlp_language_api', NULL );

if ( ! is_a( $mlp_language_api, 'Mlp_Language_Api_Interface' ) )
return $content;

$args = array (
'strict' => TRUE,
'include_base' => TRUE
);

/** @var Mlp_Language_Api_Interface $mlp_language_api */
$translations = $mlp_language_api->get_translations( $args );

if ( empty ( $translations ) )
return $content;

$links = array();

/** @type Mlp_Translation_Interface $translation */
foreach ( $translations as $translation ) {

$current = $img = '';

if ( $translation->get_target_site_id() === get_current_blog_id() )
$current = ' class="current"';

$img_url = $translation->get_icon_url();

if ( '' !== (string) $img_url )
$img = " ";

$text = $translation->get_language()->get_name( 'language_short' );
$text = mb_strtoupper( $text, 'UTF-8' );

$links[] = sprintf(
'%4$s',
$translation->get_remote_url(),
esc_attr( $translation->get_target_title() ),
$current,
$img . $text
);
}

$links = '

'
. join( ' | ', $links )
. '

';

return $content . $links;
});
The result should look like this:

Theme integration
You can use such a function in other places too, of course. In a theme you should add a custom action wherever you need it and assign a callback handler to that action. This way, your theme will not break when the user deactivates MultilingualPress.
So in a template file add this line:
do_action( 'translation_box' );
And in your functions.php create a callback function and register it for that action:
add_action( 'translation_box', 'show_mlp_translation' );

function show_mlp_translation() {
// find and print translation links
}
Any questions or suggestions? Or do you have used this tutorial successfully? Please let me know.