model->is_translated_post_type( 'acf-field-group' ) ) { // Use a non-default priority to avoid changes in cache key due to undesired hooks order change. add_filter( 'acf/get_cache_key', array( $this, 'filter_cache_key' ), 50, 2 ); add_filter( 'acf/rest/get_fields', array( $this, 'fix_rest_get_fields' ), 10, 2 ); } add_filter( 'acf/get_taxonomies', array( $this, 'get_taxonomies' ) ); add_action( 'add_meta_boxes_acf-field-group', array( $this, 'remove_sync' ) ); add_action( 'add_meta_boxes_acf-field-group', array( $this, 'duplicate_field_group' ) ); add_filter( 'acf/duplicate_field/type=clone', array( $this, 'duplicate_clone_field' ) ); add_filter( 'acf/location/rule_match/page_type', array( $this, 'rule_match_page_type' ), 20, 3 ); // After ACF. add_filter( 'pll_get_post_types', array( $this, 'get_post_types' ), 10, 2 ); add_filter( 'pll_bulk_translate_post_types', array( $this, 'bulk_translate_post_types' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); add_action( 'wp_ajax_acf_post_lang_choice', array( $this, 'acf_post_lang_choice' ) ); $this->sync_metas = new PLL_ACF_Sync_Metas(); $this->auto_translate = new PLL_ACF_Auto_Translate(); } /** * Adds the current language in the cache key to make sure that filtered queries * are not cached for only one language. * * @since 3.2 * * @param string $key Cache key. * @param string $original Original unfiltered cache key. * @return string */ public function filter_cache_key( $key, $original ) { $lang = pll_current_language(); if ( $lang && 'acf_get_field_group_posts' === $original ) { $key .= ':lang=' . $lang; } return $key; } /** * Works around a bug in ACF_Rest_Api::get_fields() which unlike get_field_objects() * returns fields which may not belong to the requested object ID. * * @since 3.3.1 * * @param array $fields An array of ACF fields. * @param array $resource Contextual information about the current resource request. * @return array */ public function fix_rest_get_fields( $fields, $resource ) { $field_object_ids = wp_list_pluck( get_field_objects( $resource['id'] ), 'ID' ); $fields = array_filter( $fields, function ( $field ) use ( $field_object_ids ) { return in_array( $field['ID'], $field_object_ids ); } ); return $fields; } /** * Prevents ACF to display our private taxonomies. * * @since 2.8 * * @param string[] $taxonomies Taxonomy names. * @return string[] */ public function get_taxonomies( $taxonomies ) { return array_diff( $taxonomies, get_taxonomies( array( '_pll' => true ) ) ); } /** * Deactivates the synchronization for ACF field groups. * * @since 2.1 * * @return void */ public function remove_sync() { foreach ( pll_languages_list() as $lang ) { remove_action( "pll_before_post_translation_{$lang}", array( PLL()->sync_post->buttons[ $lang ], 'add_icon' ) ); } } /** * Duplicates the field group if content duplication is activated. * * @since 2.3 * * @param WP_Post $post Current post object. * @return void */ public function duplicate_field_group( $post ) { if ( PLL()->model->is_translated_post_type( 'acf-field-group' ) && 'post-new.php' === $GLOBALS['pagenow'] && isset( $_GET['from_post'], $_GET['new_lang'] ) ) { // Capability check already done in post-new.php. check_admin_referer( 'new-post-translation' ); $duplicate_options = get_user_meta( get_current_user_id(), 'pll_duplicate_content', true ); $active = ! empty( $duplicate_options ) && ! empty( $duplicate_options['acf-field-group'] ); if ( $active ) { acf_duplicate_field_group( (int) $_GET['from_post'], $post->ID ); } } } /** * Recursively searches a field by its name in an array of fields. * * @since 2.3 * * @param string $name Field name. * @param array $fields An array of fields. * @return string Field key, empty string if not found. */ protected function search_field_by_name( $name, $fields ) { foreach ( $fields as $field ) { if ( $name === $field['name'] ) { return $field['key']; } elseif ( ! empty( $field['sub_fields'] ) && $key = $this->search_field_by_name( $name, $field['sub_fields'] ) ) { return $key; } elseif ( ! empty( $field['layouts'] ) ) { foreach ( $field['layouts'] as $layout ) { if ( ! empty( $layout['sub_fields'] ) && $key = $this->search_field_by_name( $name, $layout['sub_fields'] ) ) { return $key; } } } } return ''; } /** * Translates a clone field when creating a new field group translation. * * @since 2.3 * * @param array $field ACF Custom field. * @return array */ public function duplicate_clone_field( $field ) { if ( PLL()->model->is_translated_post_type( 'acf-field-group' ) && ! empty( $field['clone'] ) && 'post-new.php' === $GLOBALS['pagenow'] && isset( $_GET['from_post'], $_GET['new_lang'] ) ) { check_admin_referer( 'new-post-translation' ); foreach ( $field['clone'] as $k => $selector ) { if ( acf_is_field_group_key( $selector ) ) { // Can't use acf_get_field_group() as it is filtered by language. $posts = get_posts( array( 'post_type' => 'acf-field-group', 'post_status' => array( 'publish', 'acf-disabled', 'trash' ), 'name' => $selector, 'update_post_meta_cache' => false, 'lang' => '', ) ); if ( ! empty( $posts ) && $tr_id = pll_get_post( $posts[0]->ID, sanitize_key( $_GET['new_lang'] ) ) ) { $tr_group = acf_get_field_group( $tr_id ); $field['clone'][ $k ] = $tr_group['key']; } } elseif ( acf_is_field_key( $selector ) ) { $_field = acf_get_field( $selector ); $ancestors = get_post_ancestors( $_field['ID'] ); $group_id = end( $ancestors ); if ( $tr_id = pll_get_post( $group_id, sanitize_key( $_GET['new_lang'] ) ) ) { $tr_fields = acf_get_fields( $tr_id ); if ( $key = $this->search_field_by_name( $_field['name'], $tr_fields ) ) { $field['clone'][ $k ] = $key; } } } } } return $field; } /** * Allows page on front and page for posts translations to match the corresponding page type. * * @since 2.0 * * @param bool $match Whether a location matches the rule. * @param array $rule Field group location rule. * @param array $screen Information on the current location. * @return bool */ public function rule_match_page_type( $match, $rule, $screen ) { if ( ! empty( $screen['post_id'] ) ) { $post = get_post( $screen['post_id'] ); if ( 'front_page' === $rule['value'] && $front_page = (int) get_option( 'page_on_front' ) ) { $translations = pll_get_post_translations( $front_page ); if ( '==' === $rule['operator'] ) { $match = in_array( $post->ID, $translations ); } elseif ( '!=' === $rule['operator'] ) { $match = ! in_array( $post->ID, $translations ); } } elseif ( 'posts_page' === $rule['value'] && $posts_page = (int) get_option( 'page_for_posts' ) ) { $translations = pll_get_post_translations( $posts_page ); if ( '==' === $rule['operator'] ) { $match = in_array( $post->ID, $translations ); } elseif ( '!=' === $rule['operator'] ) { $match = ! in_array( $post->ID, $translations ); } } } return $match; } /** * Add the Field Groups post type to the list of translatable post types. * * @since 2.0 * * @param string[] $post_types List of post types. * @param bool $is_settings True when displaying the list of custom post types in Polylang settings. * @return string[] */ public function get_post_types( $post_types, $is_settings ) { if ( $is_settings ) { $post_types['acf-field-group'] = 'acf-field-group'; } return $post_types; } /** * Remove the Field Groups post type from the bulk translate action. * * @since 2.8.4 * * @param string[] $types List of post type names for which Polylang manages the bulk translate. * @return string[] */ public function bulk_translate_post_types( $types ) { return array_diff( $types, array( 'acf-field-group' ) ); } /** * Enqueues javascript to react to a language change in the post metabox. * * @since 2.0 * * @return void */ public function admin_enqueue_scripts() { global $pagenow, $typenow; if ( in_array( $pagenow, array( 'post.php', 'post-new.php' ) ) && ! in_array( $typenow, array( 'acf-field-group', 'attachment' ) ) && PLL()->model->is_translated_post_type( $typenow ) ) { $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; wp_enqueue_script( 'pll_acf', plugins_url( '/js/build/acf' . $suffix . '.js', POLYLANG_ROOT_FILE ), array( 'acf-input' ), POLYLANG_VERSION ); } } /** * Ajax response for changing the language in the post metabox * * @since 2.0 * * @return void */ public function acf_post_lang_choice() { check_ajax_referer( 'pll_language', '_pll_nonce' ); if ( isset( $_POST['fields'] ) ) { $x = new WP_Ajax_Response(); foreach ( array_map( 'sanitize_key', $_POST['fields'] ) as $field ) { ob_start(); acf_render_field_wrap( acf_get_field( $field ), 'div', 'label' ); $x->Add( array( 'what' => str_replace( '_', '-', $field ), 'data' => ob_get_contents() ) ); ob_end_clean(); } $x->send(); } } }