diff --git a/README.md b/README.md index f34e867..6658f3c 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,67 @@ # Ultimate Member - Polylang -Integrates the **Ultimate Member** community plugin with the **Polylang** multilingual plugin. -__Note:__ This is a free extension created for the community. The Ultimate Member team does not provide any support for this extension. +Integrates the **Ultimate Member** community plugin with the **Polylang** multilingual plugin. ## Key features + +- Localized permalinks for the Account and User (profile) pages. +- Ability to duplicate Ultimate Member forms for all languages in one click. +- Ability to duplicate Ultimate Member pages for all languages in one click. - Ability to translate email templates. - Ability to translate bio (description) field in profile. -- Proper permalinks for the Account and User (profile) pages. ## Installation __Note:__ This plugin requires the [Ultimate Member](https://wordpress.org/plugins/ultimate-member/) and [Polylang](https://uk.wordpress.org/plugins/polylang/) plugins to be installed first. -### Clone from GitHub +### How to install from GitHub + Open git bash, navigate to the **plugins** folder and execute this command: `git clone --branch=main git@github.com:umdevelopera/um-polylang.git um-polylang` Once the plugin is cloned, enter your site admin dashboard and go to _wp-admin > Plugins > Installed Plugins_. Find the "Ultimate Member - Polylang" plugin and click the "Activate" link. -### Install from ZIP archive -You can install this plugin from the [ZIP archive](https://drive.google.com/file/d/175PVG6tLK7z1wcrAawFfQdTVIC071Eup/view) as any other plugin. Follow [this instruction](https://wordpress.org/support/article/managing-plugins/#upload-via-wordpress-admin). +### How to install from ZIP archive + +You can install this plugin from the [ZIP archive](https://drive.google.com/file/d/1Lpgu5b-6CLkjK0Ik24CBB836aIcRcmaj/view) as any other plugin. Follow [this instruction](https://wordpress.org/support/article/managing-plugins/#upload-via-wordpress-admin). ## How to use -Go to *wp-admin > Ultimate Member > Settings > Email* to translate email templates. Click the "+" icon unter the flag to translate a template for the needed language. The plugin saves translated email templates to locale subfolders in the theme. See details [here](https://docs.ultimatemember.com/article/1335-email-templates). -Go to *wp-admin > Pages* to translate pages Account, Login, Members, Password Reset, Register, User. Click the "+" icon unter the flag to translate a page for the needed language. See details [here](https://docs.ultimatemember.com/article/1449-how-to-translate-plugin#forms). +Go to *wp-admin > Pages* to translate Ultimate Member pages. Click the **Create Pages** button in the notice to duplicate Ultimate Member pages for all languages. Or click the "+" icon unter the flag to duplicate each page manually. -Go to *wp-admin > Settings > Permalinks* and click the "Save Changes" button to update rewrite rules for the Account and Profile permalinks. +Image - Translate pages. +![Pages](https://github.com/umdevelopera/um-polylang/assets/113178913/40543c1b-d428-4832-9090-d2cc9166b616) -__Note:__ The "Post name" permalink structure is recommended. +Go to *wp-admin > Ultimate Member > Forms* to translate Ultimate Member forms. Click the **Create Forms** button in the notice to duplicate Ultimate Member forms for all languages. Or click the "+" icon unter the flag to duplicate each form manually. -### Screenshots: +Once forms for languages are created you can open these forms and translate fields. You have to translate a **Label** for custom fields. You also can translate **Placeholder** and **Help Text** if needed. -Image - Translate email templates. -![UM Settings, Email (polylang)](https://github.com/umdevelopera/um-polylang/assets/113178913/65d14995-257d-4311-a93a-8f944ea12ba9) +Image - Translate forms. +![Forms](https://github.com/umdevelopera/um-polylang/assets/113178913/76763122-a774-4778-ab2c-748b3e983779) -Image - Translate pages. -![WP Pages (polylang)](https://github.com/umdevelopera/um-polylang/assets/113178913/1329f025-a464-4c52-bf9f-99261fb5e242) +Go to *wp-admin > Ultimate Member > Settings > Email* to translate email templates. Click the "+" icon unter the flag to translate a template for the language. The plugin saves translated email templates to locale subfolders in the theme, see [Email Templates](https://docs.ultimatemember.com/article/1335-email-templates). + +Image - Translate emails. +![Email](https://github.com/umdevelopera/um-polylang/assets/113178913/17167ba5-8564-4fe9-ba33-ef69bfb67f57) + +Go to *wp-admin > Settings > Permalinks* and click the "Save Changes" button if you need to update rewrite rules for the Account and Profile permalinks. Image - Permalink settings. ![WP Settings, Permalink (default)](https://github.com/umdevelopera/um-polylang/assets/113178913/69be91c9-12dd-490c-9145-b163c5beb26d) -## Related links: +__Note:__ The "Post name" permalink structure is recommended. + +## Support + +This is a free extension created for the community. The Ultimate Member team does not provide support for this extension. Open new [issue](https://github.com/umdevelopera/um-polylang/issues) if you face a problem. + +## Related links + Ultimate Member home page: https://ultimatemember.com/ Ultimate Member documentation: https://docs.ultimatemember.com/ Ultimate Member on wordpress.org: https://wordpress.org/plugins/ultimate-member/ -Article: [How to translate plugin](https://docs.ultimatemember.com/article/1449-how-to-translate-plugin#switch) +Article: [How to translate plugin](https://docs.ultimatemember.com/article/1449-how-to-translate-plugin#switch). diff --git a/includes/admin/class-admin.php b/includes/admin/class-admin.php new file mode 100644 index 0000000..4298cd0 --- /dev/null +++ b/includes/admin/class-admin.php @@ -0,0 +1,301 @@ +settings_email_tab(); + + // Forms table styles. + add_action( 'admin_footer', array( $this, 'styles' ) ); + } + + + /** + * The "Create Forms" button handler. + */ + public function action_create_forms() { + $args = array( + 'fields' => 'ids', + 'nopaging' => true, + 'post_status' => 'publish', + 'post_type' => 'um_form', + ); + $posts = get_posts( $args ); + + UM()->Polylang()->setup()->create_posts( $posts, 'um_form' ); + + $url = add_query_arg( 'update', 'um_pll_create_forms', admin_url( 'edit.php?post_type=um_form' ) ); + exit( wp_safe_redirect( $url ) ); + } + + + /** + * The "Create Pages" button handler. + */ + public function action_create_pages() { + $posts = UM()->config()->permalinks; + + UM()->Polylang()->setup()->create_posts( $posts, 'page' ); + + $url = add_query_arg( 'update', 'um_pll_create_pages', admin_url( 'edit.php?post_type=page' ) ); + exit( wp_safe_redirect( $url ) ); + } + + + /** + * Display a notice with the "Create Forms" button. + * + * @return void + */ + public function notice_create_forms() { + $screen = get_current_screen(); + if ( ! is_object( $screen ) || 'edit-um_form' !== $screen->id ) { + return; + } + + $languages = pll_languages_list(); + if ( empty( $languages ) ) { + return; + } + + $args = array( + 'fields' => 'ids', + 'nopaging' => true, + 'post_status' => 'publish', + 'post_type' => 'um_form', + ); + $posts = get_posts( $args ); + if ( empty( $posts ) ) { + return; + } + + $need_translations = array(); + foreach ( $posts as $post => $post_id ) { + $post_translations = pll_get_post_translations( $post_id ); + if ( array_diff( $languages, array_keys( $post_translations ) ) ) { + $need_translations[] = $post_id; + break; + } + } + + if ( $need_translations ) { + $url_params = array( + 'um_adm_action' => 'um_pll_create_forms', + '_wpnonce' => wp_create_nonce( 'um_pll_create_forms' ), + ); + + $url = add_query_arg( $url_params ); + + ob_start(); + ?> + +

+ get_allowed_html( 'admin_notice' ) + ); + ?> +

+

+ + +

+ + 'notice-warning', + 'message' => $message, + 'dismissible' => true, + ); + + UM()->admin()->notices()->add_notice( 'um_pll_create_forms', $notice_data, 20 ); + } + } + + + /** + * Display a notice with the "Create Pages" button. + * + * @return void + */ + public function notice_create_pages() { + $screen = get_current_screen(); + if ( ! is_object( $screen ) || 'edit-page' !== $screen->id ) { + return; + } + + $languages = pll_languages_list(); + if ( empty( $languages ) ) { + return; + } + + $posts = UM()->config()->permalinks; + if ( empty( $posts ) ) { + return; + } + + $need_translations = array(); + foreach ( $posts as $post => $post_id ) { + $post_translations = pll_get_post_translations( $post_id ); + if ( array_diff( $languages, array_keys( $post_translations ) ) ) { + $need_translations[] = $post_id; + break; + } + } + + if ( $need_translations ) { + $url_params = array( + 'um_adm_action' => 'um_pll_create_pages', + '_wpnonce' => wp_create_nonce( 'um_pll_create_pages' ), + ); + + $url = add_query_arg( $url_params ); + + ob_start(); + ?> + +

+ get_allowed_html( 'admin_notice' ) + ); + ?> +

+

+ + +

+ + 'notice-warning', + 'message' => $message, + 'dismissible' => true, + ); + + UM()->admin()->notices()->add_notice( 'um_pll_create_pages', $notice_data, 20 ); + } + } + + + /** + * Display a notice after um_adm_action. + * + * @param array $messages Admin notice messages. + * @param string $update Update action key. + * + * @return array + */ + public function notice_update( $messages, $update ) { + + switch ( $update ) { + + case 'um_pll_create_forms': + $messages[0]['content'] = __( 'Forms have been duplicated successfully.', 'um-polylang' ); + break; + + case 'um_pll_create_pages': + $messages[0]['content'] = __( 'Pages have been duplicated successfully.', 'um-polylang' ); + break; + } + + return $messages; + } + + + /** + * Filters the list of post types available for translation. + * + * @param string[] $post_types List of post type names (as array keys and values). + * @param bool $is_settings True when displaying the list of custom post types in Polylang settings. + * + * @return string[] List of post type names. + */ + public function pll_get_post_types( $post_types, $is_settings ) { + $post_types['um_form'] = 'um_form'; + return array_unique( $post_types ); + } + + + /** + * Extend settings Email tab. + * + * @return um_ext\um_polylang\admin\Mail() + */ + public function settings_email_tab() { + if ( empty( UM()->classes['um_polylang_admin_mail'] ) ) { + require_once 'class-mail.php'; + UM()->classes['um_polylang_admin_mail'] = new Mail(); + } + return UM()->classes['um_polylang_admin_mail']; + } + + + /** + * Fix column width in the "Forms" table. + */ + public function styles() { + $screen = get_current_screen(); + if ( ! is_object( $screen ) || 'edit-um_form' === $screen->id ) { + ?> +Polylang()->is_default() ? '' : '_' . UM()->Polylang()->get_current( 'locale' ); + $value = UM()->options()->get( $email_key . '_sub' . $locale ); + $value_default = UM()->options()->get( $email_key . '_sub' ); + + $section_fields[2]['id'] = $email_key . '_sub' . $locale; + $section_fields[2]['value'] = empty( $value ) ? $value_default : $value; + + return $section_fields; + } + + + /** + * Create email template file in the theme folder. + * + * @since 1.1.0 + * + * @param array $settings Input data. + * @return array + */ + public function create_email_template_file( $settings ) { + if ( isset( $settings['um_email_template'] ) ) { + $template = $settings['um_email_template']; + $template_path = UM()->mail()->get_template_file( 'theme', $template ); + + if ( ! file_exists( $template_path ) ) { + $template_dir = dirname( $template_path ); + + if ( wp_mkdir_p( $template_dir ) ) { + file_put_contents( $template_path, '' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents + } + } + } + return $settings; + } + + + /** + * Add header for the column 'translations' in the Email table. + * + * @since 1.1.0 + * + * @param array $columns The Email table headers. + * @return array + */ + public function email_table_columns( $columns ) { + + $languages = pll_languages_list(); + if ( count( $languages ) > 0 ) { + + $flags = ''; + foreach ( $languages as $language ) { + $language = PLL()->model->get_language( $language ); + $flag = is_object( $language ) ? $language->flag : $language; + $flags .= '' . $flag . ''; + } + + $new_columns = array(); + foreach ( $columns as $column_key => $column_content ) { + $new_columns[ $column_key ] = $column_content; + if ( 'email' === $column_key && ! isset( $new_columns['pll_translations'] ) ) { + $new_columns['pll_translations'] = $flags; + } + } + + $columns = $new_columns; + } + + return $columns; + } + + + /** + * Add cell for the column 'translations' in the Email table. + * + * @since 1.1.0 + * + * @param array $email_notifications Email templates data. + * @return string + */ + public function email_table_items( $email_notifications ) { + $languages = pll_languages_list(); + + foreach ( $email_notifications as &$email_notification ) { + $email_notification['pll_translations'] = ''; + foreach ( $languages as $language ) { + $email_notification['pll_translations'] .= $this->email_table_link( $email_notification['key'], $language ); + } + } + + return $email_notifications; + } + + + /** + * Get a link to Add/Edit email template for a certain language. + * + * @since 1.1.0 + * + * @param string $template The email template slug. + * @param string $code Slug or locale of the queried language. + * @return string + */ + public function email_table_link( $template, $code ) { + + $language = PLL()->model->get_language( $code ); + $default = pll_default_language(); + $locale = $code === $default ? '' : trailingslashit( $language->get_prop( 'locale' ) ); + + // theme location. + $template_path = trailingslashit( get_stylesheet_directory() . '/ultimate-member/email/' . $locale ) . $template . '.php'; + + // plugin location for default language. + if ( empty( $locale ) && ! file_exists( $template_path ) ) { + $template_path = UM()->mail()->get_template_file( 'plugin', $template ); + } + + $link = add_query_arg( + array( + 'email' => $template, + 'lang' => $code, + ) + ); + + if ( file_exists( $template_path ) ) { + + // translators: %s - language name. + $hint = sprintf( __( 'Edit the translation in %s', 'polylang' ), $language->get_prop( 'name' ) ); + $icon_html = sprintf( + '%3$s', + esc_url( $link ), + esc_html( $hint ), + esc_html( $hint ) + ); + } else { + + // translators: %s - language name. + $hint = sprintf( __( 'Add a translation in %s', 'polylang' ), $language->get_prop( 'name' ) ); + $icon_html = sprintf( + '%3$s', + esc_url( $link ), + esc_attr( $hint ), + esc_html( $hint ) + ); + } + + return $icon_html; + } + +} diff --git a/includes/core/class-fields.php b/includes/core/class-fields.php index f3c7a96..5d59961 100644 --- a/includes/core/class-fields.php +++ b/includes/core/class-fields.php @@ -29,6 +29,7 @@ public function __construct() { add_filter( 'um_profile_bio_key', array( &$this, 'profile_bio_key' ), 20, 2 ); } + /** * Get translated biography key * @@ -41,7 +42,7 @@ public function __construct() { */ public function profile_bio_key( $key, $args ) { if ( 'description' === $key ) { - $curlang_slug = pll_current_language(); + $curlang_slug = UM()->Polylang()->get_current(); $curlang_key = 'description_' . $curlang_slug; if ( um_profile( $curlang_key ) || UM()->fields()->editing ) { $key = $curlang_key; @@ -68,7 +69,7 @@ public function profile_bio_value( $value, $data, $key = null ) { $key = $data['metakey']; } if ( 'description' === $key ) { - $curlang_slug = pll_current_language(); + $curlang_slug = UM()->Polylang()->get_current(); $curlang_key = 'description_' . $curlang_slug; if ( um_profile( $curlang_key ) ) { $value = um_profile( $curlang_key ); @@ -83,22 +84,22 @@ public function profile_bio_value( $value, $data, $key = null ) { /** * Save translated biography * - * @since 2.1.7 - * @hook um_after_user_updated + * @since 1.0.0 + * @hook um_after_user_updated * * @param integer $user_id User ID. * @param array $args Form Data. */ public function profile_bio_update( $user_id, $args ) { - $curlang_slug = pll_current_language(); + $curlang_slug = UM()->Polylang()->get_current(); $curlang_key = 'description_' . $curlang_slug; if ( isset( $args[ $curlang_key ] ) ) { update_user_meta( $user_id, $curlang_key, $args[ $curlang_key ] ); - if ( pll_default_language() === $curlang_slug ) { + if ( UM()->Polylang()->is_default() ) { update_user_meta( $user_id, 'description', $args[ $curlang_key ] ); } - } elseif ( isset( $args[ 'description' ] ) ) { - update_user_meta( $user_id, 'description', $args[ 'description' ] ); + } elseif ( isset( $args['description'] ) ) { + update_user_meta( $user_id, $curlang_key, $args['description'] ); } } diff --git a/includes/core/class-form.php b/includes/core/class-form.php index 8e8a5ba..ebac06d 100644 --- a/includes/core/class-form.php +++ b/includes/core/class-form.php @@ -23,12 +23,38 @@ class Form { * Class Form constructor. */ public function __construct() { + add_filter( 'shortcode_atts_ultimatemember', array( &$this, 'shortcode_atts_ultimatemember' ), 20, 1 ); add_filter( 'um_pre_args_setup', array( &$this, 'pre_args_setup' ), 20, 1 ); } /** - * Get arguments from original form if translated form doesn't have this data. + * Filters shortcode attributes. + * Replaces 'form_id' attribute if translated form exists. + * + * @since 1.1.0 + * + * @link https://developer.wordpress.org/reference/hooks/shortcode_atts_shortcode/ + * + * @param array $args Shortcode arguments. + * + * @return array Shortcode arguments. + */ + public function shortcode_atts_ultimatemember( $args ){ + if ( isset( $args['form_id'] ) ) { + $form_id = absint( $args['form_id'] ); + $translated_form_id = pll_get_post( $form_id, pll_current_language() ); + + if ( $translated_form_id && $translated_form_id !== $form_id ) { + $args['form_id'] = $translated_form_id; + } + } + return $args; + } + + + /** + * Gets data from the original form if the translated form doesn't have this data. * * @hook um_pre_args_setup * @@ -46,7 +72,7 @@ public function pre_args_setup( $args ) { $original_post_data = UM()->query()->post_data( $original_form_id ); foreach ( $original_post_data as $key => $value ) { - if ( ! isset( $args[ $key ] ) ) { + if ( ! array_key_exists( $key, $args ) ) { $args[ $key ] = $value; } } diff --git a/includes/core/class-mail.php b/includes/core/class-mail.php index 0e19b1e..484297c 100644 --- a/includes/core/class-mail.php +++ b/includes/core/class-mail.php @@ -23,43 +23,13 @@ class Mail { * Class Mail constructor. */ public function __construct() { - // Email table. - add_filter( 'um_email_templates_columns', array( &$this, 'email_table_columns' ), 10, 1 ); - add_filter( 'um_email_notifications', array( &$this, 'email_table_items' ), 10, 1 ); - // Email settings. - add_filter( 'um_admin_settings_email_section_fields', array( &$this, 'admin_settings_email_section_fields' ), 10, 2 ); add_filter( 'um_email_send_subject', array( &$this, 'localize_email_subject' ), 10, 2 ); - - // Email template file. add_filter( 'um_change_email_template_file', array( &$this, 'change_email_template_file' ), 10, 1 ); - add_filter( 'um_change_settings_before_save', array( &$this, 'create_email_template_file' ), 8, 1 ); add_filter( 'um_locate_email_template', array( &$this, 'locate_email_template' ), 10, 2 ); } - /** - * Adding locale suffix to the "Subject Line" field. - * Example: change 'welcome_email_sub' to 'welcome_email_sub_de_DE' - * - * @since 1.0.0 - * - * @param array $section_fields The email template fields. - * @param string $email_key The email template slug. - * @return array - */ - public function admin_settings_email_section_fields( $section_fields, $email_key ) { - $locale = UM()->Polylang()->is_default() ? '' : '_' . UM()->Polylang()->get_current( 'locale' ); - $value = UM()->options()->get( $email_key . '_sub' . $locale ); - $value_default = UM()->options()->get( $email_key . '_sub' ); - - $section_fields[2]['id'] = $email_key . '_sub' . $locale; - $section_fields[2]['value'] = empty( $value ) ? $value_default : $value; - - return $section_fields; - } - - /** * Change email template for searching in the theme folder. * @@ -76,159 +46,6 @@ public function change_email_template_file( $template ) { } - /** - * Create email template file in the theme folder. - * - * @since 1.0.0 - * - * @param array $settings Input data. - * @return array - */ - public function create_email_template_file( $settings ) { - if ( isset( $settings['um_email_template'] ) ) { - $template = $settings['um_email_template']; - $template_path = UM()->mail()->get_template_file( 'theme', $template ); - - if ( ! file_exists( $template_path ) ) { - $template_dir = dirname( $template_path ); - - if ( wp_mkdir_p( $template_dir ) ) { - file_put_contents( $template_path, '' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents - } - } - } - return $settings; - } - - - /** - * Add header for the column 'translations' in the Email table. - * - * @since 1.0.0 - * - * @global object $polylang The Polylang instance. - * - * @param array $columns The Email table headers. - * @return array - */ - public function email_table_columns( $columns ) { - global $polylang; - $languages = pll_languages_list(); - - if ( count( $languages ) > 0 ) { - - $flags_column = ''; - foreach ( $languages as $language ) { -// if ( UM()->Polylang()->get_current() === $language ) { -// continue; -// } - $language = $polylang->model->get_language( $language ); - $flags_column .= '' . $language->flag . ''; - } - - $new_columns = array(); - foreach ( $columns as $column_key => $column_content ) { - $new_columns[ $column_key ] = $column_content; - if ( 'email' === $column_key && ! isset( $new_columns['pll_translations'] ) ) { - $new_columns['pll_translations'] = $flags_column; - } - } - - $columns = $new_columns; - } - - return $columns; - } - - - /** - * - * Add cell for the column 'translations' in the Email table. - * - * @since 1.0.0 - * - * @param array $email_notifications Email templates data. - * @return string - */ - public function email_table_items( $email_notifications ) { - $languages = pll_languages_list(); - - foreach ( $email_notifications as &$email_notification ) { - $email_notification['pll_translations'] = ''; - foreach ( $languages as $language ) { -// if ( UM()->Polylang()->get_current() === $language ) { -// continue; -// } - $email_notification['pll_translations'] .= $this->email_table_cell_pll_translations( $email_notification['key'], $language ); - } - } - - return $email_notifications; - } - - /** - * Get content for the cell of the column 'translations' in the Email table. - * - * @since 2.1.6 - * - * @global object $polylang The Polylang instance. - * - * @param string $template The email template slug. - * @param string $code Slug or locale of the queried language. - * @return string - */ - public function email_table_cell_pll_translations( $template, $code ) { - global $polylang; - - $language = $polylang->model->get_language( $code ); - $default = pll_default_language(); - - $lang = ''; - if ( $code !== $default ) { - $lang = $language->locale . '/'; - } - - // theme location. - $template_path = trailingslashit( get_stylesheet_directory() . '/ultimate-member/email' ) . $lang . $template . '.php'; - - // plugin location for default language. - if ( empty( $lang ) && ! file_exists( $template_path ) ) { - $template_path = UM()->mail()->get_template_file( 'plugin', $template ); - } - - $link = add_query_arg( - array( - 'email' => $template, - 'lang' => $code, - ) - ); - - if ( file_exists( $template_path ) ) { - - // translators: %s - language name. - $hint = sprintf( __( 'Edit the translation in %s', 'polylang' ), $language->name ); - $icon_html = sprintf( - '%3$s', - esc_url( $link ), - esc_html( $hint ), - esc_html( $hint ) - ); - } else { - - // translators: %s - language name. - $hint = sprintf( __( 'Add a translation in %s', 'polylang' ), $language->name ); - $icon_html = sprintf( - '%3$s', - esc_url( $link ), - esc_attr( $hint ), - esc_html( $hint ) - ); - } - - return $icon_html; - } - - /** * Replace email Subject with translated value on email send. * Example: change 'welcome_email_sub' to 'welcome_email_sub_de_DE' diff --git a/includes/core/class-permalinks.php b/includes/core/class-permalinks.php index 82246fd..783a133 100644 --- a/includes/core/class-permalinks.php +++ b/includes/core/class-permalinks.php @@ -14,37 +14,26 @@ /** * Localize permalinks. * + * @version 1.1.0 static method `update_core_pages` removed. + * * @package um_ext\um_polylang\core */ class Permalinks { - /** - * Update meta for translated core pages. - * This is needed because the 'um_is_core_page' filter was removed. - */ - public static function update_core_pages() { - $languages = pll_languages_list(); - foreach ( $languages as $language ) { - foreach ( UM()->config()->permalinks as $page => $page_id ) { - $lang_post_id = pll_get_post( $page_id, $language ); - if ( $lang_post_id && is_numeric( $lang_post_id ) && $lang_post_id !== $page_id ) { - update_post_meta( $lang_post_id, '_um_wpml_' . $page, 1 ); - update_post_meta( $lang_post_id, '_icl_lang_duplicate_of', $page_id ); - } - } - } - } - - /** * Class Permalinks constructor. */ public function __construct() { add_filter( 'rewrite_rules_array', array( &$this, 'add_rewrite_rules' ), 10, 1 ); + // Links in emails. + add_filter( 'um_activate_url', array( &$this, 'localize_activate_url' ), 10, 1 ); + + // Pages. add_filter( 'um_get_core_page_filter', array( &$this, 'localize_core_page_url' ), 10, 3 ); add_filter( 'um_localize_permalink_filter', array( &$this, 'localize_profile_permalink' ), 10, 2 ); + // Buttons. add_filter( 'um_login_form_button_two_url', array( &$this, 'localize_page_url' ), 10, 2 ); add_filter( 'um_register_form_button_two_url', array( &$this, 'localize_page_url' ), 10, 2 ); @@ -63,12 +52,10 @@ public function __construct() { * * @since 1.0.0 * - * @global object $polylang The Polylang instance. * @param array $rules Rewrite rules. * @return array */ public function add_rewrite_rules( $rules ) { - global $polylang; $languages = pll_languages_list(); $newrules = array(); @@ -79,7 +66,7 @@ public function add_rewrite_rules( $rules ) { $account = get_post( $account_page_id ); foreach ( $languages as $language ) { - if ( pll_default_language() === $language && $polylang->options['hide_default'] ) { + if ( pll_default_language() === $language && PLL()->options['hide_default'] ) { continue; } $lang_post_id = pll_get_post( $account_page_id, $language ); @@ -88,7 +75,7 @@ public function add_rewrite_rules( $rules ) { if ( isset( $account->post_name ) && isset( $lang_post_obj->post_name ) ) { $lang_page_slug = $lang_post_obj->post_name; - if ( 1 === $polylang->options['force_lang'] ) { + if ( 1 === PLL()->options['force_lang'] ) { $newrules[ $language . '/' . $lang_page_slug . '/([^/]+)/?$' ] = 'index.php?page_id=' . $lang_post_id . '&um_tab=$matches[1]&lang=' . $language; } @@ -103,7 +90,7 @@ public function add_rewrite_rules( $rules ) { $user = get_post( $user_page_id ); foreach ( $languages as $language ) { - if ( pll_default_language() === $language && $polylang->options['hide_default'] ) { + if ( pll_default_language() === $language && PLL()->options['hide_default'] ) { continue; } $lang_post_id = pll_get_post( $user_page_id, $language ); @@ -112,7 +99,7 @@ public function add_rewrite_rules( $rules ) { if ( isset( $user->post_name ) && isset( $lang_post_obj->post_name ) ) { $lang_page_slug = $lang_post_obj->post_name; - if ( 1 === $polylang->options['force_lang'] ) { + if ( 1 === PLL()->options['force_lang'] ) { $newrules[ $language . '/' . $lang_page_slug . '/([^/]+)/?$' ] = 'index.php?page_id=' . $lang_post_id . '&um_user=$matches[1]&lang=' . $language; } @@ -121,16 +108,14 @@ public function add_rewrite_rules( $rules ) { } } - // update core pages. - self::update_core_pages(); - return array_merge( $newrules, $rules ); } /** * Filter the link in the language switcher. * - * @since 1.0.1 + * @since 1.0.1 + * @version 1.1.0 static method `update_core_pages` removed. * * @param string|null $url The link, null if no translation was found. * @param string $slug The language code. @@ -245,6 +230,25 @@ public function is_core_page( $is_core_page, $page ) { } + /** + * Filter account activation link. + * + * @hook um_activate_url + * @see um\core\Permalinks::activate_url() + * @since 1.1.0 + * + * @param string $url Account activation link. + * + * @return string Localized account activation link. + */ + public function localize_activate_url( $url ){ + if ( ! UM()->Polylang()->is_default() ) { + $url = add_query_arg( 'lang', UM()->Polylang()->get_current(), $url ); + } + return $url; + } + + /** * Filter core page URL. * diff --git a/includes/core/class-setup.php b/includes/core/class-setup.php new file mode 100644 index 0000000..60c8ec7 --- /dev/null +++ b/includes/core/class-setup.php @@ -0,0 +1,105 @@ + $post_id ) { + $cur_lang = PLL()->model->post->get_language( $post_id ); + if ( false === $cur_lang ) { + PLL()->model->post->set_language( $post_id, PLL()->pref_lang ); + } + + $translations = pll_get_post_translations( $post_id ); + $untranslated = array_diff( $languages, array_keys( $translations ) ); + + if ( $untranslated ) { + $postdata = get_post( $post_id, ARRAY_A ); + $postmeta = get_post_meta( $post_id ); + + foreach ( $untranslated as $lang ) { + $postarr = $postdata; + $postarr['ID'] = null; + $postarr['post_date'] = null; + $postarr['post_date_gmt'] = null; + $postarr['post_title'] = $postarr['post_title'] . " ($lang)"; + + // Polylang need the 'new_lang' parameter to set a proper language. + $_GET['new_lang'] = $lang; + $lang_post_id = wp_insert_post( $postarr ); + unset( $_GET['new_lang'] ); + + // Duplicate postmeta. + foreach ( $postmeta as $key => $value ) { + if ( '_um_core' === $key ) { + continue; + } + $meta_value = maybe_unserialize( $value[0] ); + update_post_meta( $lang_post_id, $key, $meta_value ); + } + update_post_meta( $lang_post_id, '_icl_lang_duplicate_of', $post_id ); + + $translations[ $lang ] = $lang_post_id; + do_action( 'um_polylang_create_posts', $lang_post_id, $post_id, $lang, $post_type ); + } + PLL()->model->post->save_translations( $post_id, $translations ); + } + + $posts_translations[ $post ] = $translations; + } + + return $posts_translations; + } + + + /** + * Updates core pages. + * Removes rewrite rules and then recreate rewrite rules. + * + * @since 1.1.0 + */ + public function refresh_rewrite_rules() { + require_once 'class-permalinks.php'; + UM()->classes['um_polylang_permalinks'] = new Permalinks(); + flush_rewrite_rules(); + } + + + /** + * Run on plugin activation. + */ + public function run() { + $this->refresh_rewrite_rules(); + } + +} diff --git a/includes/core/class-um-polylang.php b/includes/core/class-um-polylang.php index ff0f59f..ce5a002 100644 --- a/includes/core/class-um-polylang.php +++ b/includes/core/class-um-polylang.php @@ -42,12 +42,35 @@ public static function instance() { * Class UM_Polylang constructor. */ public function __construct() { - if ( $this->is_active() ) { + $this->mail(); + $this->permalinks(); + + if( UM()->is_ajax() ) { + + } elseif ( UM()->is_request( 'admin' ) ) { + $this->admin(); + } elseif ( UM()->is_request( 'frontend' ) ) { $this->fields(); $this->form(); - $this->mail(); - $this->permalinks(); } + + add_action( 'plugins_loaded', array( $this, 'textdomain' ), 9 ); + } + + + /** + * Subclass that extends wp-admin features. + * + * @since 1.1.0 + * + * @return um_ext\um_polylang\admin\Admin() + */ + public function admin() { + if ( empty( UM()->classes['um_polylang_admin'] ) ) { + require_once um_polylang_path . 'includes/admin/class-admin.php'; + UM()->classes['um_polylang_admin'] = new um_ext\um_polylang\admin\Admin(); + } + return UM()->classes['um_polylang_admin']; } @@ -58,6 +81,7 @@ public function __construct() { */ public function fields() { if ( empty( UM()->classes['um_polylang_fields'] ) ) { + require_once um_polylang_path . 'includes/core/class-fields.php'; UM()->classes['um_polylang_fields'] = new um_ext\um_polylang\core\Fields(); } return UM()->classes['um_polylang_fields']; @@ -71,6 +95,7 @@ public function fields() { */ public function form() { if ( empty( UM()->classes['um_polylang_form'] ) ) { + require_once um_polylang_path . 'includes/core/class-form.php'; UM()->classes['um_polylang_form'] = new um_ext\um_polylang\core\Form(); } return UM()->classes['um_polylang_form']; @@ -84,6 +109,7 @@ public function form() { */ public function mail() { if ( empty( UM()->classes['um_polylang_mail'] ) ) { + require_once um_polylang_path . 'includes/core/class-mail.php'; UM()->classes['um_polylang_mail'] = new um_ext\um_polylang\core\Mail(); } return UM()->classes['um_polylang_mail']; @@ -97,23 +123,48 @@ public function mail() { */ public function permalinks() { if ( empty( UM()->classes['um_polylang_permalinks'] ) ) { + require_once um_polylang_path . 'includes/core/class-permalinks.php'; UM()->classes['um_polylang_permalinks'] = new um_ext\um_polylang\core\Permalinks(); } return UM()->classes['um_polylang_permalinks']; } + /** + * Subclass that setup pages and forms. + * + * @since 1.1.0 + * + * @return um_ext\um_polylang\core\Setup() + */ + public function setup() { + if ( empty( UM()->classes['um_polylang_setup'] ) ) { + require_once um_polylang_path . 'includes/core/class-setup.php'; + UM()->classes['um_polylang_setup'] = new um_ext\um_polylang\core\Setup(); + } + return UM()->classes['um_polylang_setup']; + } + + + /** + * Loads a plugin's translated strings. + */ + public function textdomain() { + $locale = get_locale() ? get_locale() : 'en_US'; + load_textdomain( um_polylang_textdomain, WP_LANG_DIR . '/plugins/' . um_polylang_textdomain . '-' . $locale . '.mo' ); + load_plugin_textdomain( um_polylang_textdomain, false, dirname( um_polylang_plugin ) . '/languages/' ); + } + + /** * Returns the current language. * * @since 1.0.0 * - * @global object $polylang The Polylang instance. * @param string $field Optional, the language field to return (@see PLL_Language), defaults to `'slug'`. * @return string|int|bool|string[]|PLL_Language The requested field or object for the current language, `false` if the field isn't set. */ public function get_current( $field = 'slug' ) { - global $polylang; $lang = pll_current_language(); if ( isset( $_GET['lang'] ) ) { @@ -122,9 +173,9 @@ public function get_current( $field = 'slug' ) { if ( empty( $lang ) || 'all' === $lang ) { $lang = substr( get_locale(), 0, 2 ); } - $language = $polylang->model->get_language( $lang ); + $language = PLL()->model->get_language( $lang ); - return $language->get_prop( $field ); + return is_object( $language ) ? $language->get_prop( $field ) : $lang; } @@ -141,19 +192,28 @@ public function get_default( $field = 'slug' ) { } + /** + * Returns the list of available languages. + * + * @since 1.1.0 + * + * @return array + */ + public function get_languages_list() { + return pll_languages_list(); + } + + /** * Check if Polylang is active. * - * @since 1.0.0 + * @since 1.0.0 + * @version 1.1.0 Check for the PLL function. * * @return boolean */ public function is_active() { - if ( defined( 'POLYLANG_VERSION' ) ) { - global $polylang; - return isset( $polylang ) && is_object( $polylang ); - } - return false; + return defined( 'POLYLANG_VERSION' ) && function_exists( 'PLL' ); } diff --git a/languages/um-polylang-en_US.mo b/languages/um-polylang-en_US.mo new file mode 100644 index 0000000..b1cc1b4 Binary files /dev/null and b/languages/um-polylang-en_US.mo differ diff --git a/languages/um-polylang-en_US.po b/languages/um-polylang-en_US.po new file mode 100644 index 0000000..6335274 --- /dev/null +++ b/languages/um-polylang-en_US.po @@ -0,0 +1,88 @@ +msgid "" +msgstr "" +"Project-Id-Version: Ultimate Member - Polylang\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-12-03 23:01+0000\n" +"PO-Revision-Date: 2023-12-03 23:01+0000\n" +"Last-Translator: DeveloperA UltimateMember\n" +"Language-Team: English (United States)\n" +"Language: en_US\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Loco https://localise.biz/\n" +"X-Loco-Version: 2.6.6; wp-6.4.1\n" +"X-Domain: um-polylang" + +#. %s: Plugin name. +#: includes/admin/class-admin.php:134 +#, php-format +msgid "" +"%s needs to create required forms for every language to function correctly." +msgstr "" + +#. %s: Plugin name. +#: includes/admin/class-admin.php:203 +#, php-format +msgid "" +"%s needs to create required pages for every language to function correctly." +msgstr "" + +#: includes/admin/class-admin.php:140 +msgid "Create Forms" +msgstr "" + +#: includes/admin/class-admin.php:209 +msgid "Create Pages" +msgstr "" + +#: includes/admin/class-admin.php:240 +msgid "Forms have been duplicated successfully." +msgstr "" + +#. Author URI of the plugin +msgid "https://github.com/umdevelopera" +msgstr "" + +#. URI of the plugin +msgid "https://github.com/umdevelopera/um-polylang" +msgstr "" + +#. Description of the plugin +msgid "Integrates Ultimate Member with Polylang." +msgstr "" + +#: includes/admin/class-admin.php:141 includes/admin/class-admin.php:210 +msgid "No thanks" +msgstr "" + +#: includes/admin/class-admin.php:244 +msgid "Pages have been duplicated successfully." +msgstr "" + +#. %s - plugin name. +#: um-polylang.php:69 +#, php-format +msgid "" +"The %s extension requires the Polylang plugin to be " +"activated to work properly. You can download it here" +msgstr "" + +#. %s - plugin name. +#: um-polylang.php:60 +#, php-format +msgid "" +"The %s extension requires the Ultimate Member plugin to be " +"activated to work properly. You can download it here" +msgstr "" + +#. Name of the plugin +msgid "Ultimate Member - Polylang" +msgstr "" + +#. Author of the plugin +msgid "umdevelopera" +msgstr "" diff --git a/languages/um-polylang.pot b/languages/um-polylang.pot new file mode 100644 index 0000000..61b58e6 --- /dev/null +++ b/languages/um-polylang.pot @@ -0,0 +1,89 @@ +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Ultimate Member - Polylang\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-12-03 23:01+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: \n" +"Language: \n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Loco https://localise.biz/\n" +"X-Loco-Version: 2.6.6; wp-6.4.1\n" +"X-Domain: um-polylang" + +#. %s: Plugin name. +#: includes/admin/class-admin.php:134 +#, php-format +msgid "" +"%s needs to create required forms for every language to function correctly." +msgstr "" + +#. %s: Plugin name. +#: includes/admin/class-admin.php:203 +#, php-format +msgid "" +"%s needs to create required pages for every language to function correctly." +msgstr "" + +#: includes/admin/class-admin.php:140 +msgid "Create Forms" +msgstr "" + +#: includes/admin/class-admin.php:209 +msgid "Create Pages" +msgstr "" + +#: includes/admin/class-admin.php:240 +msgid "Forms have been duplicated successfully." +msgstr "" + +#. Author URI of the plugin +msgid "https://github.com/umdevelopera" +msgstr "" + +#. URI of the plugin +msgid "https://github.com/umdevelopera/um-polylang" +msgstr "" + +#. Description of the plugin +msgid "Integrates Ultimate Member with Polylang." +msgstr "" + +#: includes/admin/class-admin.php:141 includes/admin/class-admin.php:210 +msgid "No thanks" +msgstr "" + +#: includes/admin/class-admin.php:244 +msgid "Pages have been duplicated successfully." +msgstr "" + +#. %s - plugin name. +#: um-polylang.php:69 +#, php-format +msgid "" +"The %s extension requires the Polylang plugin to be " +"activated to work properly. You can download it here" +msgstr "" + +#. %s - plugin name. +#: um-polylang.php:60 +#, php-format +msgid "" +"The %s extension requires the Ultimate Member plugin to be " +"activated to work properly. You can download it here" +msgstr "" + +#. Name of the plugin +msgid "Ultimate Member - Polylang" +msgstr "" + +#. Author of the plugin +msgid "umdevelopera" +msgstr "" diff --git a/readme.txt b/readme.txt index b47fa26..7d250df 100644 --- a/readme.txt +++ b/readme.txt @@ -1,14 +1,16 @@ === Ultimate Member - Polylang === + Author: umdevelopera Author URI: https://github.com/umdevelopera Plugin URI: https://github.com/umdevelopera/um-polylang Tags: ultimate member, polylang, multilingual -Requires at least: 6.0 -Tested up to: 6.2.2 -Stable tag: 1.0.0 +Requires at least: 5.5 +Tested up to: 6.4.1 +Requires UM core at least: 2.6.8 +Tested UM core up to: 2.7.0 +Stable tag: 1.1.0 License: GNU Version 2 or Any Later Version License URI: http://www.gnu.org/licenses/gpl-3.0.txt -Requires UM core at least: 2.5.0 == Description == @@ -16,19 +18,32 @@ Integrates the "Ultimate Member" community plugin with the "Polylang" multilingu = Key Features = +* Localized permalinks for the Account and User (profile) pages. +* Ability to duplicate Ultimate Member forms for all languages in one click. +* Ability to duplicate Ultimate Member pages for all languages in one click. * Ability to translate email templates. * Ability to translate bio (description) field in profile. -* Proper permalinks for the Account and User (profile) pages. + += Documentation & Support = + +This is a free extension created for the community. The Ultimate Member team does not provide any support for this extension. Open new issue in the GitHub repository if you face a problem: https://github.com/umdevelopera/um-polylang/issues == Installation == +Download ZIP file from GitHub or Google Drive. You can find download links here: https://github.com/umdevelopera/um-polylang + You can install this plugin from the ZIP file as any other plugin. Follow this instruction: https://wordpress.org/support/article/managing-plugins/#upload-via-wordpress-admin -= Documentation & Support = +== Changelog == -This is a free extension created for the community. The Ultimate Member team does not provide any support for this extension. Open new issue in the GitHub repository if you face a problem: https://github.com/umdevelopera/um-polylang/issues += 1.1.0: December 4, 2023 = -== Changelog == +* Added: Polylang integration for Ultimate Member forms. +* Added: The "Create Forms" notice and button. +* Added: The "Create Pages" notice and button. +* Added: The `lang` parameter to the account activation link. +* Added: Translation template (.pot file). +* Fixed: Classes autoloader issue: Class "um_ext\um_polylang\core\Fields" not found. = 1.0.2: July 20, 2023 = diff --git a/um-polylang.php b/um-polylang.php index b8d7b82..b686361 100644 --- a/um-polylang.php +++ b/um-polylang.php @@ -1,14 +1,19 @@ run(); } } } } register_activation_hook( um_polylang_plugin, 'um_polylang_activation_hook' ); + // Check dependencies. if ( ! function_exists( 'um_polylang_check_dependencies' ) ) { function um_polylang_check_dependencies() { @@ -73,13 +71,8 @@ function () { ); } else { require_once 'includes/core/class-um-polylang.php'; - function um_polylang_init() { - if ( function_exists( 'UM' ) ) { - UM()->set_class( 'Polylang', true ); - } - } - add_action( 'plugins_loaded', 'um_polylang_init', 2, 1 ); + UM()->set_class( 'Polylang', true ); } } } -add_action( 'plugins_loaded', 'um_polylang_check_dependencies', -20 ); +add_action( 'plugins_loaded', 'um_polylang_check_dependencies', 2 );