VaLeXaR / wp-multilang

Multilingual plugin for WordPress.
131 stars 44 forks source link

issue with yoast SEO #174

Open Htmlbelov opened 3 years ago

Htmlbelov commented 3 years ago

on site 2 lang - ru & en save page in ru - showing ru meta on both. save page in en - showing en meta on both

Nekaravaev commented 3 years ago

As for me, temporary workaround was look like:

But instead of removing, I just re-add filter with new priority.

$fob->remove_filter( $tag, $filter['function'], $priority ); $fob->add_filter($tag, $filter['function'], $priority - 1, $filter['accepted_args']);

Then, I've just copy title & meta from %prefix%_postmeta to Yoast's indexable table through update. You need to use same wp_insert_post hook with maximum priority.

KoalaMontana commented 3 years ago

@Nekaravaev could you tell us more about your solution? Did you add filter to theme's function file or change files of WP-Multilang?

Nekaravaev commented 3 years ago

@KoalaMontana I'm stuck with that plugin after push site to production so solution dirty as.

Yoast change dramatically their plugin after 14 version and won't cooperate with users of multilang plugins, that store translation right in meta/posts table through shrotcode-like syntax (if you google some results, you saw so cold support responses as proof).

They change storage approach own data, moving to separate tables (which can store only one row for page). So if you save meta with WP Multilang translations, they sanitize it as simple string and collect to own table (which uses for formatting title, description, etc.). But post_meta field stay as we want.

So I decided to throw post_meta title & description to their table by hand (in functions.php to avoid modification of plugin files).

The problem here is it: they use \PHP_INT_MAX as own add_filter's priority. We need to override that value at first and copy meta then or changes will not apply.

Here modified popular helper: https://gist.github.com/Nekaravaev/77a0bc11fe8d1f4415b4609cb30a2e67

Then we just apply hook on wp_insert_post with dirty copy.

\add_action( "wp_insert_post", 'func', \PHP_INT_MAX, 1 );

func() {
        global $wpdb;
        $needed_fields = array('_yoast_wpseo_title', '_yoast_wpseo_focuskw', '_yoast_wpseo_metadesc');
        $bindings = array(
            '_yoast_wpseo_title' => 'title',
            '_yoast_wpseo_metadesc' => 'description',
            '_yoast_wpseo_focuskw' => 'primary_focus_keyword'
        );

        foreach ($needed_fields as $field ) {
            $meta_value = $wpdb->get_col( $wpdb->prepare( "SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s AND post_id = %d", $field, $post_id) );
            if ( !empty( $meta_value ) ) {
                $status = $wpdb->query("UPDATE " . $wpdb->prefix . "yoast_indexable SET " . $bindings[$field] . " = '".$meta_value[0]."' WHERE object_id = $post_id");
            }
        }
}

This will work only with plain text on Yoast's title field.

If you want to use Yoast's variables like PageTitle or Site Name, you should modify plugin's WPM_Yoast_Seo::translate_title function in same way: read from yoast_indexable table and manipulate raw data.

            $possible_placeholders = array("%%title%%", "%%sitename%%");
            $title_col = $wpdb->get_col($wpdb->prepare("SELECT title from {$wpdb->prefix}yoast_indexable WHERE object_id=%d", $post->ID) );
            if ( !empty( $title_col) ) {
                $title_col = wpm_translate_value($title_col[0]);
                $result_title = $title_col;
                foreach ( $possible_placeholders as $placeholder ) {
                    if ( strpos($title_col, $placeholder ) !== false ) {
                        switch ($placeholder) {
                            case "%%title%%":
                                $result_title = str_replace($placeholder, get_the_title(), $result_title);
                                break;
                            case "%%sitename%%":
                                $result_title = str_replace($placeholder, get_bloginfo('name'), $result_title);
                                break;
                        }
                    }
                }

                return $result_title;
           }
madkot commented 2 years ago

Hi, i try with \add_action( "wp_insert_post", 'func', \PHP_INT_MAX, 1 ); and catch _yoast_wpseo_title and _yoast_wpseo_metadesc and push it to "yoast_indexable" then i little change the code of WPM_Yoast_Seo::translate_title to return oryginal parameter $title this way public function translate_title( $title ) { return $title; } and for me this workaround works fine.