Support » Plugin: Polylang » Image Captions – Simple Solution

  • If you want to have different image captions for each language, but don’t need to have your database cluttered with duplicate posts and taxonomy relationships for each attachment, i found a simple way that works just fine.

    Also, when you activate media translations in a existing site, all gallery images disappear from posts which are not in the same language. And you need to create new galleries, with the duplicated attachments (even though the image file is not duplicated). This is very difficult to manage.

    This solution can be added to a theme “functions.php” and allows to edit the gallery captions right from the “Edit Gallery” screen (also from the Media Library). Please note that it only deals with the caption. Attachment Title, Alternate text and Description was left untranslated, because only Captions affect the galleries in the different languages, in my case.

    Maybe Chouby considers this in future Polylang versions, as the “Media Translation” option is far from perfect, compared to the rest of Polylang which works just great.

    if(is_admin()) {
    
    	/*
    	 * This filters enables us to add captions for each existing language to the attachment edit screens
    	 */
    	function my_theme_attachment_fields_to_edit( $form_fields, $post ) {
    		if( !defined('POLYLANG_VERSION') ) { return $form_fields; }
    		global $langs;
    
    		$langs = (empty($langs)) ? pll_languages_list() : $langs;
    		foreach ($langs as $lang) {
    			$key = 'caption_'.$lang;
    			$form_fields[$key] = array(
    					'value' => get_post_meta( $post->ID, $key, true ),
    					'label' => __( 'Caption' ).'-'.$lang,
    					'input' => 'textarea'
    			);
    		}
    		return $form_fields;
    	}
    	add_filter( 'attachment_fields_to_edit', 'my_theme_attachment_fields_to_edit', 10, 2 );
    
    	/*
    	 * In WordPress 4.1, image captions can be changed in two ways: either from Ajax requests (Media Library and Post Galleries)
    	 * or from the edit post (when editing more details from the Media Library). Basically we need to check the action and
    	 * the presence of the $_POST arguments and act accordingly
    	 * 1) $_POST['action'] = 'save-attachment',
    	 *		and only if !empty($_POST['changes']['caption']) && !empty($_POS['post_id'])
    	 *		if($_POS['post_id']) not set (when editing image from Media Library), then we
    	 *    don't know the language and don't to nothing.
    	 *    If $_POS['post_id'] is set (when editing images from a post),
    	 *    then we get the langguage from the post, and update
    	 *    the corresponding caption in the postmeta table.
    	 * 2) $_POST['action'] == 'save-attachment-compat' OR $_POST['action'] == 'editpost'),
    	 *    in which case the captions in the various languages set in the
    	 *    'attachment_fields_to_edit' filter are sent, and can be updated.
    	 */
      function my_theme_wp_insert_attachment_data($data, $postarr) {
    		if( !defined('POLYLANG_VERSION') ) { return $data; }
    
        if( !empty($_POST['changes']['caption']) && !empty($_POST['post_id']) ) {
          $lang = pll_get_post_language($_POST['post_id']);
          $key = 'caption_'.$lang;
          update_post_meta($postarr['ID'], $key, $_POST['changes']['caption']);
    			//keep the default legend if working in an alternate language
          if($lang != pll_default_language()) {
            unset($data['post_excerpt']);
          }
        }
        elseif( isset($_POST['action']) && ($_POST['action'] == 'save-attachment-compat' || $_POST['action'] == 'editpost')  ) {
          $langs = pll_languages_list();
          foreach ($langs as $lang) {
            $key = 'caption_'.$lang;
            if(isset($_POST['attachments'][$postarr['ID']][$key])) {
              update_post_meta($postarr['ID'], $key, $_POST['attachments'][$postarr['ID']][$key]);
            }
          }
        }
        return $data;
    	}
    	add_filter( 'wp_insert_attachment_data', 'my_theme_wp_insert_attachment_data', 10, 2 );
    
    } // END if(is_admin()) {
    
    /*
     * we only want the filters to be active while running the gallery/attachment queries
     */
    function my_theme_post_gallery($output) {
    	if( !defined('POLYLANG_VERSION') ) { return $output; }
    	global $post;
    	if(is_object($post) ) {
    		$GLOBALS['pll_gallery'] = true;
    	}
    	return $output;
    }
    add_filter( 'post_gallery', 'my_theme_post_gallery', 10, 1);
    
    /*
     * By default, filters are suppressed for queries which are not the main query, so we need to activate them for the gallery/attachment queries
     */
    function my_theme_pre_get_posts($query) {
    	if( !defined('POLYLANG_VERSION') ) { return $str; }
    	global $post;
    	if( is_admin() && $_POST['action'] == 'query-attachments' ) {
    		$query->set('suppress_filters', false );
    		$query->pll_gallery_post_id = $_POST['post_id'];
    	}
    	if( is_object($post) && isset($GLOBALS['pll_gallery']) ) {
    		$query->set('suppress_filters', false );
    		$query->pll_gallery_post_id = $post->ID;
    	}
    }
    add_action('pre_get_posts','my_theme_pre_get_posts');
    
    /*
     * Here we substitute the default caption (post_excerpt) with the correct value from postmeta table, if it's not null or empty:
     * the FIELDS part
     */
    function my_theme_posts_field($str, $query) {
    	if( !defined('POLYLANG_VERSION') ) { return $str; }
    	if( isset($query->pll_gallery_post_id) ) {
    		global $wpdb;
    		//$lang = pll_get_post_language($post->ID);
    		$str .= ", IFNULL(pm.meta_value, $wpdb->posts.post_excerpt) AS post_excerpt";
    	}
      return $str;
    }
    add_filter('posts_fields', 'my_theme_posts_field', 10, 2);
    
    /*
     * Here we substitute the default caption (post_excerpt) with the correct value from postmeta table, if it's not null or empty:
     * the JOIN part
     */
    function my_theme_posts_join($str, $query) {
    	if( !defined('POLYLANG_VERSION') ) { return $str; }
    	global $wpdb;
    	if( isset($query->pll_gallery_post_id) ) {
    		$lang = pll_get_post_language($query->pll_gallery_post_id);
    		$str .= " LEFT JOIN $wpdb->postmeta AS pm ON ($wpdb->posts.ID = pm.post_id && pm.meta_key = 'caption_".$lang."')";
    	}
      return $str;
    }
    add_filter('posts_join', 'my_theme_posts_join', 10, 2);
    
    /*
     * This deactivates the filters, after the correct caption for galleries is shown, so other WP_Queries can run normal.
     */
    function my_theme_posts_request( $str, $query ) {
    	if( !defined('POLYLANG_VERSION') ) { return $str; }
    	if( isset($query->pll_gallery_post_id) ) {
    		$query->set('suppress_filters', true );
    		unset($query->pll_gallery_post_id, $GLOBALS['pll_gallery']);
    	}
      return $str;
    }
    add_filter( 'posts_request', 'my_theme_posts_request', 10, 2 );

    https://wordpress.org/plugins/polylang/

Viewing 5 replies - 1 through 5 (of 5 total)
  • Plugin Author Chouby

    (@chouby)

    Hi!

    Thanks for sharing. It may help other users.
    Just a quick fix as I got a notice when testing it. You should replace

    if( is_admin() && $_POST['action'] == 'query-attachments' ) {

    by

    if( is_admin() && isset($_POST['action']) && $_POST['action'] == 'query-attachments' ) {

    Also, when you activate media translations in a existing site, all gallery images disappear from posts which are not in the same language

    I must admit that the option was meant to be activated at the beginning of the life of a website.

    At the moment, I don’t plan to add this to Polylang as other users may need to translate the title, the description and other contents too. But I am glad you shared! And I agree that I should think on how to improve the workflow to translate media.

    I really like Polylang, but the way images are handled is really not best practice!

    As long as you don’t have text in images that should be translated, why using multiple images in the media library, when you just need to change the caption or the title? Imagine this with 5 or more languages, this means there will be 5 times the same image visible for just the caption… very uncomfortable!

    So I also prefer Gonçalo Peres method.

    I was just wondering if this could be done with titles too? Cause my Nivo Slider from Visual Composer uses only titles.. and I dont wanna core hack this 🙁

    how to get the output?

    No one answer my question.
    How to get the output? I use post_excerpt and nothing happens. it’s still use the default value.

    Hi Gonçalo & Chouby,

    Outstanding! Works great. But… How can the same be done for Title, ALT Text and Description?

    Can you point me in the right direction? I see caption is simple ‘caption’. Is that true for Title, ALT Text and Description?

    Can I just replicate this code three more times for each field?

    Thanks
    David

Viewing 5 replies - 1 through 5 (of 5 total)
  • The topic ‘Image Captions – Simple Solution’ is closed to new replies.