qtranslate / qtranslate-xt

qTranslate-XT (eXTended) - reviving qTranslate-X multilingual plugin for WordPress. A new community-driven plugin soon. Built-in modules for WooCommerce, ACF, slugs and others.
GNU General Public License v2.0
557 stars 107 forks source link

[WC] Translating variable product attributes #612

Closed wywarren closed 4 years ago

wywarren commented 6 years ago

Hi guys,

I made a similar post before on qtranslatex with no avail as well as on woocommerce's github so I will try to have a stab here.

This is my original post/hack solution on woocommerce: https://github.com/woocommerce/woocommerce/issues/16623

As described, when we key product level multilingual attributes and apply them to variable products in woocommerce, the select box options disappears on the product page. If you go to view the source, they show up but I think at runtime, something in javascript or something else causes the variable production options to disappear.

I've tried making this work around in woocommerce source code base to get them to show up, but as described in the thread above, the returned object is an array although somehow it works in my implementation. I tried making a plugin to get around this using filters but have not come up with any ideas. I suspect this could be fixed by altering qtranslatex but I haven't had the chance to take a deep dive into the makings of qtranslatex to make a workable fix.

Any ideas or suggestions would help.

Thanks!

wywarren commented 6 years ago

Changing it to this to remedy the array also works: ` public function get_variation_attributes() { if ( null === $this->variation_attributes ) { $this->variation_attributes = $this->data_store->read_variation_attributes( $this ); }

$attributes = array();
foreach ($this->variation_attributes as $key => $value): 
    $v = array();
    for($i=0;$i<count($value);$i++){
        $v[] = __($value[$i]);
    }
    $attributes[$key] = $v;
endforeach;

return $attributes;
//return $this->variation_attributes;

} `

however this also requires modifying the woocommerce code base which they refuse to do.

herrvigg commented 6 years ago

hello, thanks for reporting this. My priority is currently Gutenberg but i keep this to be checked later when we can deal with WooCommerce. It's definitely one important plugin that qTranslate should support as best as possible. I'll simply keep this open at the moment but we'll come back to it.

wywarren commented 6 years ago

One work around that took me almost two days to pull off that I'm working with right now is I ended up making a plugin that subclassed the variable product class native to WooCommerce. From there, I copied over some functions to modify while others I just used the same functions as the parent variable product class. One of which was the function listed above where I replaced the function, effectively overriding it, in the new product type. I can post the plugin code if it helps. But it's quite a big fix while the original variable product is still broken for multiling strings. At least it works for our application though. I have not verified yet if it works with REST API as well (which is also what we're using it for).

herrvigg commented 6 years ago

Let's see if we can integrate it directly in qTranslate-XT.

Actually some of the issues mentioned by other people should already be solved in the 1.4 version available on github, but the fixes were never released to the official repo on wordpress.org still in 1.3. Same happened for qTranslate-X, strange they were not directly synched for every release.

Anyway It makes no sense having a separate plugin for such a small thing (i mean the original add-on, not even for your patch) so my plan is to integrate it as an add-on. Imo this should be the case for all the extra components necessary to integrate major plugins such as WooCommerce. It makes the maintenance and evolutions so much easier and clearly these should be part of qTranslate-X-whatever-the-name.

I have already started doing some experiments in a local branch but it's not pushed yet. The main task is currently to avoid conflicts with the existing add-on as a separate plugin as i will restart from the same code. When this is is ready to test we can try to add your stuff on top of that.

herrvigg commented 6 years ago

I have now integrated the legacy add-on plugin, more info here: https://github.com/qtranslate/qtranslate-xt/issues/608. Let me know how it goes and we can build stuff on top of this.

herrvigg commented 6 years ago

I've added a new feature to automatically disable the legacy add-on plugin for easier integration. As mentioned in the other post this branch should fix the following issues with WooCommerce:

Changelog 1.4 (legacy!)

If this module works fine we can finally abandon the legacy add-on as a plugin to handle the fixes and evolutions more easily from the main project. Let's move forward ;)

herrvigg commented 6 years ago

@wywarren please check the woo-commerce branch if you can. I've just sent some updates to handle the new modules better. If it works i can merge this in the master branch for a new release.

wywarren commented 5 years ago

OK I'll give it a try later tomorrow. Right now on my own platform I've been still using my work around but I've been updating to the latest xt to see if it remedied the situation on the standard variable products. Thanks!

wywarren commented 5 years ago

Unfortunately it's still doing the same thing with the woocommerce branch. I can make a video for you if needed. It seems to be a front end thing that messes with it though. If you refresh and click the select dropdown it shows up really fast but shortly after everything loads the options become hidden.

herrvigg commented 5 years ago

OK but i simply integrated the previous plugin as a module. I thought some of the issues could be solved but i didn't add your patch yet. So at least we have a common base that should now be easier to manage for the fixes. I'll check later for more details and to see what can be done.

herrvigg commented 5 years ago

Merged into a new modules branch and PR sent: https://github.com/qtranslate/qtranslate-xt/pull/627

herrvigg commented 5 years ago

@wywarren I have just merged the new modules branch into master with this last version of the plugin (see https://github.com/qtranslate/qtranslate-xt/issues/661). You can now drop the old legacy plugin and try just with qTranslate-XT.

You should still see the last issues but it should now easier to debug (sources in qtranslate-xt/modules/woo-commerce). You can also send new PRs directly here.

farikus commented 5 years ago

@wywarren I have just merged the new modules branch into master with this last version of the plugin (see #661). You can now drop the old legacy plugin and try just with qTranslate-XT.

You should still see the last issues but it should now easier to debug (sources in qtranslate-xt/modules/woo-commerce). You can also send new PRs directly here.

Installed new qtranslate-XT with built-in modules, but same problem still exist.

When attributes are in different languages, it doesn't show in product page. http://www.mihome.az/en/shop/smartphones/mi-8-64-gb/

I was thinking maybe I want to delete old "WooCommerce & qTranslate-X" plugin and it will work with your built-in plugin. But it doesn't help. Even my products with attributes in only English aren't working: http://www.mihome.az/shop/smartphones/redmi-note-6-pro/

When I had "WooCommerce & qTranslate-X" plugin it was good. 32GB and 64GB options.

Now I try to download and active from here (https://wordpress.org/plugins/woocommerce-qtranslate-x/) or download from here (https://github.com/qTranslate-Team/woocommerce-qtranslate-x) and install it, it says:

Fatal error: Cannot redeclare qwc_init_language() (previously declared in /home/mihome/public_html/wp-content/plugins/qtranslate-xt-master/modules/woo-commerce/woo-commerce.php:9) in /home/mihome/public_html/wp-content/plugins/woocommerce-qtranslate-x/woocommerce-qtranslate-x.php on line 17

herrvigg commented 5 years ago

First of all, thank you @farikus for testing, we really need more people involved! This is especially true with plugins like WooCommerce that i don't use.

About the last error ("cannot redeclare"), this is because the modules are replacing the old legacy plugins. I could have renamed everything but actually i prefer a clear break so that users start switching to the modules because the old plugins are not maintained anymore - apart from rare exceptions like ACF (see https://github.com/qtranslate/qtranslate-xt/issues/661#issuecomment-480195095).

About the problem with the attributes, the current module should do exactly the same as the last version of the plugin that you can find on github: https://github.com/qTranslate-Team/woocommerce-qtranslate-x). So i think it's still "normal" to see these bugs. Note it's version 1.4 and this has not been released on WordPress.org. The current state of qTranslate is really insane, we need to move forward and forget about these old projects once for all.

In case of doubt we can check for regression but it should not be the case. If you want to test the plugin 1.4 you can go back to qTranslate-XT 3.5.5 (without modules).

From that point we can start to fix the bugs in the code inside the modules. It's a bit hard to me to reproduce the problems for WooCommerce because i don't have the data and i have no clue how it works. Either some developers can help either i need to import or reproduce a DB state somehow.

herrvigg commented 5 years ago

You can find all the releases here: https://github.com/qtranslate/qtranslate-xt/releases. You can also check them out with git (by commit SHA or by tag). It's also a good practice to always deactivate your current version before moving/renaming it. So after installing the new version you will have to reactivate the new one. Some code might be run only on activation (although currently it's not a big deal).

farikus commented 5 years ago

You can find all the releases here: https://github.com/qtranslate/qtranslate-xt/releases. You can also check them out with git (by commit SHA or by tag). It's also a good practice to always deactivate your current version before moving/renaming it. So after installing the new version you will have to reactivate the new one. Some code might be run only on activation (although currently it's not a big deal).

I solved the problem.

What was the issue? I uploaded XT 3.5.5 and activated it. Then I uploaded 1.4 qTranslate WooCommerce support plugin (from GitHub) and my regular custom attributes (without translation/in one language) has disappeared.

I deleted 1.4 and uploaded plugin from Wordpress.org (1.3 version).

Then I added Attributes in wp-admin/edit.php?post_type=product&page=product_attributes in 3 languages.

Then go to Product page. Adding attributes from "saved attributes" and then check box "Used for variations". Variations added from attributes and they are working great now.

Variations dropdown menu works great on product page and translated in each language. Product: http://www.mihome.az/en/shop/smartphones/redmi-smartphones/redmi-note-7/

So, the thing I learned from here: Don't use custom attributes like [:az]Qara[:en]Black[:ru]Черный[:] | [:az]Göy[:en]Blue[:ru]Синий[:].

herrvigg commented 5 years ago

Now i'm getting quite confused. Wasn't it possible to do this with the last version with the modules? Or with qT-XT 3.5.5 + support plugin 1.4? Why did you have to go back to 1.3? And what happens now if you upgrade back to 3.6.0.dev (master branch)?

farikus commented 5 years ago

Now i'm getting quite confused. Wasn't it possible to do this with the last version with the modules? Or with qT-XT 3.5.5 + support plugin 1.4? Why did you have to go back to 1.3? And what happens now if you upgrade back to 3.6.0.dev (master branch)?

I have a friend who is the Wordpress developer. I sent him this tickets and asked what to do. Because it wasn't working for me. He said that don't change anything in WooCommerce code. It's plugins problem. Because Polylang doesn't have this issue.

I went to Polylang's website to see how do they solve the problem. And I saw that they translate the attributes from wp-admin/edit.php?post_type=product&page=product_attributes.

So, I installed your last XT version (without modules) and my friend asked me to install stable WooCommerce for qTranslate plugin from Wordpress.org. So I did and everything works great now.

I actually didn't checked it with master version. If you want, I can check it this weekend.

herrvigg commented 5 years ago

Polylang and WPML are completely different to qTranslate, they create duplicate posts instead of duplicate content. There are pros and cons. I tend to prefer their solution if you had to scale up but WPML is not free and Polylang has some limitations. On the other hand qTranslate has a lot of complexity in the code. The client-side is a big dirty hack (i hate it) and the DB content is not so friendly if you look at every single post. But it's free, it's working fine for small sites having few languages and there are cool features with the URLs. Also, having unique posts simplifies other tasks so qTranslate has its place.

About WooCommerce, you should not change the code for sure. The integration with qTranslate is not easy but that's why we have github. Now things are moving so it's important to understand which versions you are using.

Maybe i have to give a small reminder of the history. Before the modules (that are new - currently under test on master), you would need the support plugin "WooCommerce for qTranslate", but this one exists in two fashions:

The problem is that it's not maintained anymore and no one here can change the github project like any other of the old "qTranslateTeam" (sic) so i'd like to get rid of them. I don't want to clone them, because we have some plans to continue with qTranslate-XT under a whole new different name and having everything "in-house" makes the refactoring much easier.

Now the module for Woo-Commerce should correspond to the last version of the support plugin, version 1.4. I don't know exactly why you had to move back to 1.3. My fear is that this process could have some impacts on the DB content and i would like to exclude this 1.3 entirely from any need of migration. But now since we are with the modules i would also like to exclude the support plugin entirely. For validation purposes, if it's not in production the best would be if you could restore your DB before all these changes and jump to the master branch directly (QTX_VERSION = 3.6.0.dev).

herrvigg commented 5 years ago

@wywarren what is the current status with the variable product attributes?

If some translation is missing maybe this action could help: woocommerce_create_product_variation ?

wywarren commented 5 years ago

Hi guys sorry for the inactivity. I've been using my subclassed version in my working environment to date. I will grab the latest build this week and set it up in my environment. If everything is working as expected, we can finally close this issue. Once again thanks for the great work!

herrvigg commented 5 years ago

No worry and welcome back! Don't have too many expectations for the variable product attributes, i don't think this is fixed. However everything is now in a much better shape with the modules for new updates. Also, preferably use the master branch (last updates from git). I'll probably send a new release soon.

wywarren commented 5 years ago

With the latest build, using the woo-commerce module will break the display of attribute values in both mono and multilingual scenarios I think. With it installed, I couldn't store values via REST API either. After removing the woo-commerce module it was back to normal. I've yet to dive in, but also with the latest version of woo-commerce even using my specialized custom product type (extending from variable product), the read_variation_attributes from the data store is empty for multilingual products but not for monolingual ones. If I can solve that at least I can continue using my existing method and dive into the module and see what's the cause.

herrvigg commented 5 years ago

@wywarren This sounds bad. I don't see why there would be so many regressions.

First thing, very important, have you reactivated (deactivate-activate) qTranslate-XT after the update? Second, for REST, did you update your permalink rules (save from permalink page)?

The module is essentially the same code as the legacy add-on plugin version 1.4. It's really hard for me to understand if the problems come from the changes from 1.3 to 1.4 (which are very old and i'm not involved) or later.

wywarren commented 5 years ago

I'll try digging a bit later but it could be the result of further woocommerce upgrades in later versions that caused this. In my findings yesterday trying my fix, I found another deeper issue that was the cause of the original problem.

For variable products, woocommerce calls a function 'read_variation_attributes' from a product's data_store object. The original function is located in: /includes/data-stores/class-wc-product-variable-data-store-cpt.php:166

I ended up rewriting it in my own product type as the following:

`public function read_variation_attributes( &$product ) { global $wpdb;

    $variation_attributes = array();
    $attributes           = $product->get_attributes();
    $child_ids            = $product->get_children();
    $cache_key            = WC_Cache_Helper::get_cache_prefix( 'products' ) . 'product_variation_attributes_' . $product->get_id();
    $cache_group          = 'products';
    $cached_data          = wp_cache_get( $cache_key, $cache_group );

    if ( false !== $cached_data ) {
        return $cached_data;
    }

    if ( ! empty( $child_ids ) && ! empty( $attributes ) ) {
        foreach ( $attributes as $attribute ) {
            if ( empty( $attribute['is_variation'] ) ) {
                continue;
            }

            // Get possible values for this attribute, for only visible variations.
            $values = array_unique(
                $wpdb->get_col(
                    $wpdb->prepare(
                        "SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s AND post_id IN (" . implode( ',', array_map( 'absint', $child_ids ) ) . ')', // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared
                        wc_variation_attribute_name( $attribute['name'] )
                    )
                )
            );

for($i=0;$i<count($values);$i++){ $values[$i] = __($values[$i]); }

            // Empty value indicates that all options for given attribute are available.
            if ( in_array( null, $values, true ) || in_array( '', $values, true ) || empty( $values ) ) {
                $values = $attribute['is_taxonomy'] ? wc_get_object_terms( $product->get_id(), $attribute['name'], 'slug' ) : wc_get_text_attributes( $attribute['value'] );
                // Get custom attributes (non taxonomy) as defined.
            } elseif ( ! $attribute['is_taxonomy'] ) {
                $text_attributes          = wc_get_text_attributes( $attribute['value'] );
                $assigned_text_attributes = $values;
                $values                   = array();

                // Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
                if ( version_compare( get_post_meta( $product->get_id(), '_product_version', true ), '2.4.0', '<' ) ) {
                    $assigned_text_attributes = array_map( 'sanitize_title', $assigned_text_attributes );
                    foreach ( $text_attributes as $text_attribute ) {
                        if ( in_array( sanitize_title( $text_attribute ), $assigned_text_attributes, true ) ) {
                            $values[] = $text_attribute;
                        }
                    }
                } else {
                    foreach ( $text_attributes as $text_attribute ) {
                        if ( in_array( $text_attribute, $assigned_text_attributes, true ) ) {
                            $values[] = $text_attribute;
                        }
                    }
                }
            }
            $variation_attributes[ $attribute['name'] ] = array_unique( $values );
        }
    }

    wp_cache_set( $cache_key, $variation_attributes, $cache_group );

    return $variation_attributes;
}`

essentially adding: for($i=0;$i<count($values);$i++){ $values[$i] = __($values[$i]); }

The important take away is that this function retrieves the product variation attributes in two separate ways:

1) The first one $values does a database raw value extract which contains all the translations, meanwhile, 2) wc_get_text_attributes( $attribute['value'] ) internally returns only the translated value for the current language.

Because of these two retrieval methods, the comparison never matches for a multilingual string and breaks the base variable product feature. I'm not sure if this is something that can be updated in the woocommerce core as my previous request had been rejected.

herrvigg commented 5 years ago

Good you manage to move forward! Unfortunately i don't know enough about WC to help you more for now. Do you think something should be done in qT-XT? Your last words make me think something is still missing.

wywarren commented 5 years ago

I could share my repo for my workaround product type but I feel like it hasn't solve the core of the problem. I'm not even 100% certain if it's something that can be fixed outside of woocommerce core. I need to take a look at how the modules for woocommerce are setup to have an idea where to start, but if it's something that can be fixed from that angle I could submit that update as well. If anyone else is running into similar problems and finds this thread maybe that can be the bandaid fix for now but the modules file is a bit foreign to me so I would need some time to take a look at it.

herrvigg commented 5 years ago

If i find a bit of time i may look at it but i can't promise. I would first need to have a better setup to test WC with the proper data. Apart from the variable product attributes, do the rest work as expected? No problem with REST or anything else? It's already good if we can validate that the most standard features work as expected.

wywarren commented 5 years ago

So here's what I kinda did to restore my custom variable product back to working state. I started with the last version of "WooCommerce & qTranslate-X" and did a diff check against the files in the modules folder. I found a bunch of stuff the same while some functions were new. I then started weeding out functions until I found the one that was forcefully removing my attribute option values. On around line 143 in modules/woo-commerce/qwc-front.php:

` /**

if ( defined( 'DOING_CRON' ) ) {

function qwc_deliver_webhook_async( $webhook_id, $arg ) {
    //qtranxf_dbg_log('qwc_deliver_webhook_async: $webhook_id=',$webhook_id);

    $page_configs = qtranxf_get_front_page_config();
    //qtranxf_dbg_log('$page_configs: ', $page_configs);
    if ( ! empty( $page_configs['']['filters'] ) ) {
        qtranxf_remove_filters( $page_configs['']['filters'] );
    }

    remove_filter( 'get_post_metadata', 'qtranxf_filter_postmeta', 5 );
    remove_filter( 'the_posts', 'qtranxf_postsFilter', 5 );
    remove_action( 'pre_get_posts', 'qtranxf_pre_get_posts', 99 );

    remove_filter( 'get_term', 'qtranxf_useTermLib', 0 );
    remove_filter( 'get_terms', 'qtranxf_useTermLib', 0 );
    //add_filter('get_term', 'qtranxf_useAdminTermLibJoin', 20);
    //add_filter('get_terms', 'qtranxf_useAdminTermLibJoin', 20);
}

add_action( 'woocommerce_deliver_webhook_async', 'qwc_deliver_webhook_async', 5, 2 );

} else { qwc_add_filters_front(); } `

Commenting this entire section out allowed my attribute option values to be stored as raw values again in REST API. I'm not sure when this function was introduced but it took me a while to find. I will continue to test it. Changing the product type to variable still doesn't work though, so I'm still resorting to my custom extended product type, but at least it has be restored to an operational previous state. I'm surprised others have not ran into similar problems. Doing the extended product type was a hint I got from stack overflow too, and it took me close to a day to figure out how to do it.

wywarren commented 5 years ago

Correction, commenting out the webhook meant that some front end areas will start showing raw values instead of filtered values for multilingual strings. I will try to rewrite this function to work in both scenarios.

chieh12lee commented 5 years ago

I'm also dealing with that problem...

cyberneco commented 5 years ago

Me too. We don't have any news about it? Many thanks for all

herrvigg commented 4 years ago

@wywarren @farikus @chieh301 @cyberneco could you try with PR https://github.com/qtranslate/qtranslate-xt/pull/790 to see if it fixes the problems with the variable product attributes? Not sure it solves everything but at least one part seems related.

cyberneco commented 4 years ago

Hi! The problem persists.

Many thanks! :)

herrvigg commented 4 years ago

@cyberneco can you describe exactly which problem and what versions you are using? There are actually many different issues and a bit of confusion due to different versions + legacy plugin being used.

Here in #612 there are also several points being discussed. Now i understand better the problem. There are mainly two situations:

Global attribute

Global attributes are handled as a taxonomy and this should work fine without any change! This is the solution used by @farikus (i will stop mentioning him anymore, i only realized later what worked for him). So you can also use this as a quick workaround.

Custom attribute

The problem is double:

herrvigg commented 4 years ago

Update: #707 and #752 are actually two different issues. PR #790 currently fixes the #707 issue only, see related PR for more details.

herrvigg commented 4 years ago

@wywarren @cyberneco great news! I finally found a new solution with woocommerce_dropdown_variation_attribute_options_args so i close this PR. It works for custom attributes, with only some limitations for the edition that need to be entered manually as described above. Improving this would require more work but it's quite independent. At least the main functionality with custom attributes should now work.

Let me know if it works, because i tested only the main product page showing the variations. I don't know if there are other places. For now it's only available on the master branch. This will be released as a patch update if it works for you.

herrvigg commented 4 years ago

I came to the same conclusions as @wywarren : we can't really use woocommerce_product_get_attributes because of an internal limitation in WC with the custom attributes only. The option labels are read directly from DB and all the values that don't match exactly the stored value are discarded. No other hook is called with the recent versions (it used to be different with product version < 2.4). Note this problem doesn't concern the global attributes, treated as a taxonomy. It's very specific to custom attributes.

I first tried using woocommerce_variation_option_name which looked nice and produced the proper HTML output, but again... this time option values non-matching with names (ID) are removed later in the browser by the script 'add-to-cart-variations.js'... i think they should review a bit their hooks that have way too many limitations, imo it's quite a hell of spaghetti code that should be deeply refactored for more simplicity... welcome to the WordPress world. At least with woocommerce_dropdown_variation_attribute_options_args it seems to works now - finally!

herrvigg commented 4 years ago

Fixed in 3.7.3