WPML Automatically duplicate secondary language to another secondary language (or set different fallback per language) - wordpress

WPML provides an option to set each domain as a separate language. As a result, we have a German AT (for the .at) domain and a German DE (for the .de domain), for example. English is the default language and it needs to remain that way because we have many other domains for other languages and each of them includes an English (and WPML falls back to the default language if a language doesn't have a translation, which works best as English).
WPML does not provide an option to set a different Fallback language per secondary language. They do provide a way to manually duplicate from one secondary language to another, but that is time consuming each time we want to update something.
I therefore wrote the following code:
function duplicate_wpml_language_on_update( $post_id, $post ) {
global $sitepress;
if ( defined( 'ICL_LANGUAGE_CODE' ) && $sitepress->is_translated_post_type( $post->post_type ) ) {
switch (ICL_LANGUAGE_CODE) {
case 'fr':
wp_schedule_single_event( time(), 'duplicate_post', array( $post_id, $post, 'frbe' ) );
break;
case 'de':
wp_schedule_single_event( time(), 'duplicate_post', array( $post_id, $post, 'deat' ) );
}
}
}
add_action( 'save_post', 'duplicate_wpml_language_on_update', 10, 2 );
add_action( 'woocommerce_update_product', 'duplicate_wpml_language_on_update', 10, 2 );
add_action( 'wpml_pro_translation_completed', 'duplicate_wpml_language_on_update', 10, 2 );
add_action( 'icl_pro_translation_completed', 'duplicate_wpml_language_on_update', 10, 2 );
add_action( 'wpml_save_translation_data', 'duplicate_wpml_language_on_update', 10, 2 );
function duplicate_post( $post_id, $post, $lang ) {
global $sitepress;
$trid = $sitepress->get_element_trid( $post_id, 'post_' . $post->post_type );
$translations = $sitepress->get_element_translations( $trid, 'post_' . $post->post_type );
if ( isset( $translations[$lang] ) ) {
$target_post_id = $translations[$lang]->element_id;
$duplicate_of = get_post_meta( $target_post_id, '_icl_lang_duplicate_of', true );
if ( $duplicate_of ) {
// Duplicate to $lang
$target_post_id = $sitepress->make_duplicate( $post_id, $lang );
}
}
}
add_action( 'duplicate_post', 'duplicate_post', 10, 3 );
The code works when using the default wordpress editor to edit a post and duplicates it to the secondary language. When using the classic translation editor though, it doesn't work. I'm assuming that the hook is not firing. As you can see, I tried multiple hooks and it's still not working. If it is firing, I don't see any reason for it not to work. I believe the trid would be the same for all languages of a particular post, and I believe _icl_lang_duplicate_of should function the same. Could anything be incorrect about the code? If not, is there another way to do this or get it to fire when saving a post after using the WPML Classic Editor?

Related

Custom field value set to permalink only on new post, But they change it every time it's updated

I want to set the permalink slug using the custom field value for the first save only, but it is not working.
The code below changes the slug not only for the first save, but also for every update.
function custom_slug_auto_setting( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
return $_POST['custom_field_title'];
}
add_filter( 'wp_unique_post_slug', 'custom_slug_auto_setting', 10, 6 );
For the second and subsequent saves, I want to keep the slug set for the first save.
I tried using the filter hook for wp_insert_post to specify post_name only for the first save, but that didn't work well either.
Is there any good solution?
Thank you.
save_post or save_post_{$post->post_type} Fires once a post has been saved. The dynamic portion of the hook name, {$post->post_type}, refers to the post type slug.
We need to discard any updates autosave or revision actions. The WordPress autosave system fire every 60 seconds.
#See https://wordpress.org/support/article/revisions/
The $update parameter is supposed to determined whether this is an existing post being updated. It applies more specifically to a post autosave revision. The $update parameter will always be true when firing through wp_publish_post. But that isn't true for its usage in wp_insert_post (See the following wordpress stackexchange answer and comments for more details...).
#See https://wordpress.stackexchange.com/a/185991/190376
In our case, the wp_publish_post function publish a post by transitioning the post status.
#See https://developer.wordpress.org/reference/functions/wp_publish_post/
By additionally crosschecking the post status we can effectively determine whether it is indeed a non-existing post.
If you are calling a function such as wp_update_post that includes the save_post hook, your hooked function will create an infinite loop. To avoid this, unhook your function before calling the function you need, then re-hook it afterward.
#See https://developer.wordpress.org/reference/hooks/save_post/#avoiding-infinite-loops
save_post will fire on post Update (eg: Autosave) or Publish which is why we're runing into an infinite loop.
#See https://wordpress.stackexchange.com/a/19539/190376
<?php
add_action( 'save_post', 'wpso74121743', 10, 3 ); //can be replaced by save_post_{$post->post_type}
if ( ! function_exists( 'wpso74121743' ) ) {
function wpso74121743( $post_id, $post, $update ) {
if ( ! wp_is_post_autosave( $post_id ) && ! wp_is_post_revision( $post_id ) && ! $update && $post->post_status == 'auto-draft' ) {
$override_post_name = sanitize_title( get_post_custom_values( 'custom_field_title', $post_id ), get_the_title( $post_id ) );
add_action( 'save_post', 'wpso74121743', 10, 3 ); //can be replaced by save_post_{$post->post_type}
wp_update_post( array(
'ID' => $post_id,
'post_name' => $self,
) );
add_action( 'save_post', 'wpso74121743', 10, 3 ); //can be replaced by save_post_{$post->post_type}
};
};
};

Wordpress - Setting custom template for multiple custom post types

I was wondering if anyone knew how to set up a single template for multiple custom post types. For example - I don't want to set up multiple templates that do the exact same thing.
Code
I found the following snippet while searching and it doesn't seem to work. I have placed this in functions.php in the theme I am using.
add_filter( 'single_template', function( $template ) {
$cpt = [ 'available-properties', 'leased-sold', 'norway' ];
return in_array( get_queried_object()->post_type, $cpt, true )
? 'path/to/country-single.php'
: $template;
} );
Found the answer
This seems to work great!
add_filter( 'template_include', function( $template )
{
// your custom post types
$my_types = array( 'available-properties', 'leased-sold' );
$post_type = get_post_type();
if ( ! in_array( $post_type, $my_types ) )
return $template;
return get_stylesheet_directory() . '/page-content__projects-single.php';
});

Hook to set product weight on save_post

Is there a way to set product weight with save_post hook?
I've following code, but I don't know how to overwrite weight:
add_action( 'save_post', 'change_weight' );
function change_weight($post_id) {
$WC_Product = wc_get_product($post_id);
}
If you use the woocommerce_process_product_meta_$product_type then you don't have to worry about nonces as you can piggy back on WooCommerce's sanity checks.
// This will work in both WC 2.6 and WC 2.7
add_action( 'woocommerce_process_product_meta_simple', 'so_42445796_process_meta' );
function so_42445796_process_meta( $post_id ) {
$weight = 100;
update_post_meta( $post_id, '_weight', $weight );
}
WC 2.7 will introduce CRUD methods that abstract how the data is saved. I suspect they will eventually move products and product meta out of default WordPress tables, but I can't know for sure. In 2.7 you can use the woocommerce_admin_process_product_object hook to modify the $product object before it is saved.
// Coming in WC2.7 you can use the CRUD methods instead
add_action( 'woocommerce_admin_process_product_object', 'so_42445796_process_product_object' );
function so_42445796_process_product_object( $product ) {
$weight = 100;
$product->set_weight( $weight );
}
To set the weight you need to update the post meta. This can be done like this:
update_post_meta( $post_id, '_weight', $weight );
$weight in the above code is a variable containing the value you want the weight to be. However the save_post hook is triggered every time any post is saved, so blog posts, pages, products, etc. You will probably want to validate that the post is a product. You can do that like this:
if ( get_post_type ( $post_id ) == 'shop_order' ) {
update_post_meta( $post_id, '_weight', $weight );
}
Also if you want to get the current weight of the product before you alter it you can do it like this:
$product = wc_get_product( $post_id );
$weight = $product->get_weight();

Where would I add this add_action() code influencing the product admin view?

I have a piece of code from another answer that customizes the way products are displayed in the admin view. It appears to be adding a WordPress hook using add_action().
add_action( 'manage_product_posts_custom_column', 'wpso23858236_product_column_offercode', 10, 2 );
function wpso23858236_product_column_offercode( $column, $postid ) {
if ( $column == 'offercode' ) {
echo get_post_meta( $postid, 'offercode', true );
}
}
However, I am unclear where I have to place this code for it to have the desired effect.

making your posts password-protected by default

I originally wanted to be able to password protect a category. At the very least I wanted it to be password-protected, but preferably a username and password login. Since I have been unsuccessful for days at finding a solution I have now resorted to using WordPress's built-in password protection for posts.
The issue I am having is I will be posting via e-mail and in order to have these posts password-protected I need to login to Wordpress and then manually select password-protected and enter a password in the dashboard.
I would like to be able to have all posts that appear in a specific category be password-protected with the same password by default. Eliminating having to log in to Wordpress and manually select password protect.
I know there is a function <?php post_password_required( $post ); ?> that I need to use but I am not sure how to implement it or where.
Based on this WordPress StackExchange answer. Tested only with a regular dashboard. Publishing via email has to be tested, but I suppose the hook gets called in this kind of posting.
add_action( 'save_post', 'wpse51363_save_post' );
function wpse51363_save_post( $post_id ) {
//Check it's not an auto save routine
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
//Check it's not an auto save routine
if ( wp_is_post_revision( $post_id ) )
return;
//Perform permission checks! For example:
if ( !current_user_can( 'edit_post', $post_id ) )
return;
$term_list = wp_get_post_terms(
$post_id,
'category',
array( 'fields' => 'slugs' )
);
if( in_array ( 'the-category-slug', $term_list ) )
{
// Unhook this function so it doesn't loop infinitely
remove_action( 'save_post', 'wpse51363_save_post' );
// Call wp_update_post update, which calls save_post again.
wp_update_post( array(
'ID' => $post_id,
'post_password' => 'default-password' )
);
// Re-hook this function
add_action( 'save_post', 'wpse51363_save_post' );
}
}
add_filter( 'wp_insert_post_data', function( $data, $postarr ){
if ( 'book' == $data['post_type'] && 'auto-draft' == $data['post_status'] ) {
$data['post_password'] = wp_generate_password();
}
return $data;
}, '99', 2 );

Resources