Forum Replies Created

Viewing 15 replies - 31 through 45 (of 51 total)
  • @chouby

    Could you explain why it is a problem ?

    I create my custom post types in init action hook as suggested by the Codex examples of register_post_type, but textdomains are not loaded yet at that point. I could modify those labels later, but that duplicates code and doesn’t make much sense.

    I can register them after wp hook, but then CPT rewrite rules would not be modified by Polylang as that is done in wp_loaded which comes before wp unless Polylang hooks onto registered_post_type.
    Another option for Polylang to get $qury_var['lang'] would be to hook onto parse_request but at that point $wp_query is not yet populated and hence there is no $wp_query -> queried_object.

    Please clarify, so somebody can answer your question:
    What is your other language?
    Do you use automatic excerpts and how do you generate them?

    You’re right, I just tested myself and it appears that Polylang is loading its front-end class Polylang_Core instead of Polylang_Admin because is_admin() returns false before user has logged in.

    Correct locale was loaded when I disabled Polylang by commenting out last two lines in polylang.php (which is the fastest way to do it without logging in).

    I suppose there should be another way to check if the back-end is loaded before user logs in.

    Edit: maybe Polylang can check $pagenow == 'wp-login.php' besindes is_admin() as it is WordPress global defined in wp-includes/vars.php and used in wp-settings.php.
    Edit #2: I just checked and the switch works. If you really need it and are ready to modify code of Polylang, just make changes in polylang.php around line 81 to 86:

    // separate admin and frontend
    	global $pagenow;
    	if (is_admin() || $pagenow == 'wp-login.php') {
    		require_once(PLL_INC.'/admin.php');
    		$polylang = new Polylang_Admin();
    	}

    I’m actually having another problem because Polylang delays textdomain loading until wp action which is too late as I need my custom post type labels in init hook.

    NOTE: If you create pages or posts with identical slugs and disable Polylang after that, only first matching post or page will be displayed in front-end. And this may not work for pages.

    EDIT: Currently there are problems querying right posts in front-end when using this code. I’ll post more code as soon as I get it fixed.

    It appears that Polylang is setting current language from current post or page in single view instead of getting it from query variable.

    This is because WordPress does not filter posts and pages by language when checking if the slug is unique.

    I had same problem and just finished code as a workaround for this. Until Chouby includes this in Polylang core you can use following code in your theme functions.php or create a plugin out of it:

    global $polylang;
    // Check if Polylang_Base exists and if $polylang is the right object
    if(is_admin() && class_exists('Polylang_Base') && $polylang instanceof Polylang_Base){
    
    	// The wp_unique_post_slug filter is applied only after WordPress checks if the slug is unique and adds suffix otherwise
    	// the function returns unique post slug within language
    	add_filter('wp_unique_post_slug', 'unique_slug_in_language', 10, 5);
    	function unique_slug_in_language($slug, $post_ID, $post_status, $post_type, $post_parent = 0){
    		global $polylang, $wpdb;
    
    		// Get language of a post
    		$lang = $polylang->get_post_language($post_ID);
    		// return the slug if Polylang does not return post language
    		if(empty($lang))
    			return $slug;
    
    		// Remove suffix if it was added
    		// this might remove any dash and number at the end of a slug
    		$new_slug = isset($_POST['new_slug'])? sanitize_title($_POST['new_slug']) : preg_replace('@-\d$@', '', $slug);
    
    		// Return slug if it was not changed
    		if($new_slug == $slug)
    			return $slug;
    
    		// prepare statements to filter by language
    		$join = $wpdb->prepare(" INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = ID");
    		$where_lang = $wpdb->prepare(" AND pll_tr.term_taxonomy_id = %d", $lang->term_id);
    
    		$hierarchical_post_types = get_post_types( array('hierarchical' => true) );
    
    		// Polylang does not translate attachements - skip if it is one
    		if ( 'attachment' == $post_type ) {
    			return $slug;
    
    		} elseif ( in_array( $post_type, $hierarchical_post_types ) ) {
    			// Page slugs must be unique within their own trees. Pages are in a separate
    			// namespace than posts so page slugs are allowed to overlap post slugs.
    			$check_sql = "SELECT post_name FROM $wpdb->posts
    			$join
    			WHERE post_name = %s AND post_type IN ( '" . implode( "', '", esc_sql( $hierarchical_post_types ) ) . "' ) AND ID != %d AND post_parent = %d
    			$where_lang
    			LIMIT 1";
    			$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $new_slug, $post_ID, $post_parent ) );
    			if(!$post_name_check)
    				return $new_slug;
    
    		} else {
    			// Post slugs must be unique across all posts.
    			$check_sql = "SELECT post_name FROM $wpdb->posts
    			$join
    			WHERE post_name = %s AND post_type = %s AND ID != %d
    			$where_lang
    			LIMIT 1";
    			$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $new_slug, $post_type, $post_ID ) );
    			if(!$post_name_check)
    				return $new_slug;
    		}
    		return $slug;
    	}
    
    }

    It is smart enough not to just strip the suffix added by WordPress. It really checks if there are no duplicates in post/page language and under same parent. Code is partially taken from wp-includes/post.php wp_unique_post_slug function with some stuff from Polylang core.php.

    Not pretty, but it works and I don’t know any better way to do this right now. Additions or suggestion are welcome.

    That is because wp-admin language settings are saved for logged-in user, but the user data is not loaded until you log in.
    However, if you have defined default language in wp-config.php, you should see your login screen in that language.

    Another thing is that textdomains of themes and plugins have to be loaded after init action hook (which is even after after_setup_theme hook) to be in language detected by Polylang.

    Thread Starter Andis

    (@andydegroo)

    CPT archive titles now work correctly in Polylang 0.8.

    Unfortunately there is another CPT related bug;
    CPT archive links are incorrect if $cpt->has_archive is string and differs from CPT name or slug.
    Actually, you just need to get the slug from $cpt->has_archive if it is a string;

    This makes things simpler in core.php @ 518:

    $cpt = get_post_type_object($qvars['post_type']);
    // we don't need to check if there is $cpt->rewrite['slug'] because WP always sets it
    // see /wp-includes/post.php in register_post_type() on line 995
    $cpt_slug = is_string($cpt->has_archive) ? $cpt->has_archive : $cpt->rewrite['slug'];
    $url = esc_url($base.$cpt_slug.'/');

    And, I believe, there could be other underwater stones hiding in $cpt->hierarchical. Haven’t seen any tho.
    I’m currently trying to create a structure of _different_ hierarchical post types and some CPT limitations can be seen already, but that’s mostly unrelated to Polylang.

    hide_empty in get_terms adds checking of count field in wp_term_taxonomy table and that is why Polylang was displaying the fill_languages option in settings tab.

    I’ve updated to 0.8 and all seems OK.
    …until I’ll find another edge case bug, which can be encountered only in very special conditions. ??

    I was moving code to production sandbox and tried to set default language for existing content in Polylang options screen.
    Got this:

    WordPress database error: [Duplicate entry '41-5' for key 1]
    INSERT INTO wp_dev_term_relationships (object_id, term_taxonomy_id) VALUES (41, 5),(33, 5),(28, 5),(26, 5),(2, 5),(1, 5),(23, 5),(13, 5),(6, 5),(9, 5),(24, 5)

    This is because get_terms('language', array('fields'=>'ids')) return an empty array every time. This in turn happens because, when you insert term relations manually, wp_term_taxonomy.count is not incremented.
    The get_terms query returns only non-empty terms:
    SELECT t.term_id, tt.parent, tt.count FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy IN ('language') AND tt.count > 0 ORDER BY t.name ASC

    Solution would be to add the hide_empty option to get_terms in Polylang_Admin::get_untranslated():

    get_terms('language', array('fields'=>'ids','hide_empty'=>0));

    and term count should also be updated after inserting relations to prevent further problems with get_terms:

    $post_count = count($untranslated['posts']); //Note: get_untranslated returns array instead of false - read below
    if($post_count && $lang->term_taxonomy_id){
    	$values = array();
    	foreach ($untranslated['posts'] as $post_id)
    		$values[] = $wpdb->prepare("(%d, %d)", $post_id, $lang->term_taxonomy_id);
    
    	$wpdb->query("INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id) VALUES " . implode(',', $values));
    	$wpdb->update($wpdb->term_taxonomy, array('count'=>$post_count), array( 'term_taxonomy_id' => $lang->term_taxonomy_id ));
    }

    Probably there is a better way to update term counts.

    Polylang_Admin::get_untranslated() should return an array of arrays instead of false:

    return empty($posts) && empty($terms) ? false : array('posts' => $posts, 'terms' => $terms);

    better cast them as arrays:

    return array('posts'=>(array)$posts, 'terms'=>(array)$terms);

    that way it can be passed directly to foreach without warnings like Invalid argument supplied for foreach() in ....

    EDIT: I made this change and realized that there should be more advanced check in admin-form.php so maybe in this case it is easier to check return values in admin.php.

    Downloaded 0.8dev7 and going over diff.
    In core.php on line 330, instead of

    unset($query->queried_object)

    it should be

    $query->queried_object = false

    because unset() will delete the property and create notice when accessed in WP core and maybe create even more issues.
    I’ll correct it in local copy, but you should also change it in your code.

    EDIT: Oh, excuse me. I was actually wrong about that unset(). In get_queried_object it actually checks it with isset.

    I have also partially translated Polylang to Latvian and as soon as I get to complete it, I’ll send you the .mo file.

    Those two notices I mentioned above are coming from filter hook option_page_for_posts.
    I think, Polylang_Core->translate_page() should return passed value if it equals zero because there is no post with ID 0. That is also the way filter functions work in WP.

    I highly recommend adding Xdebug to your development toolset, because oftentimes it can help to solve some obscure issues. To get better idea of what’s going on configure it to show function params in stack traces. That would be xdebug.collect_params = 4.

    I am ‘self made PHP developper’ so glad to learn more…

    Me too. I have a graphics design education and PHP is only part of my skill set. Nevertheless I have more than eight years of experience in web development and programming in general.

    Thread Starter Andis

    (@andydegroo)

    I agree that before and after options are not needed.

    I’ve implemented post content and title duplication on translation creation. I did it on default_content and default_title filter hooks just for my event CPT and only if $_GET['from_post'] is set.
    here’s the code:

    // copy post content and title when translating events with Polylang
    add_filter('default_content','copy_post_translation', 100, 2);
    add_filter('default_title','copy_post_translation', 100, 2);
    function copy_post_translation($content, $post){
    	$from_post = isset($_GET['from_post'])? (int)$_GET['from_post'] : false;
    	if($from_post && 'ily_event' == $post->post_type && $content == ''){
    		$from_post = get_post($from_post);
    		if($from_post)
    		switch(current_filter()){
    			case 'default_content':
    				$content = $from_post->post_content;
    				break;
    			case 'default_title':
    				$content = $from_post->post_title;
    				break;
    			default:
    				break;
    		}
    	}
    	return $content;
    }

    Note: ily_event is my CPT and it copies content if it is not set already, as other plugins or theme could have set default content or title.

    The permastruct is /%year%/%monthnum%/%postname%/
    option show_on_front => 'posts'
    polylang options when I get redirect loops:

    [browser] => 0
    [rewrite] => 1
    [hide_default] => 0
    [force_lang] => 0
    [default_lang] => lv
    [redirect_lang] => 1

    polylang options when it works as expected:

    [browser] => 0
    [rewrite] => 1
    [hide_default] => 1
    [force_lang] => 0
    [default_lang] => lv
    [redirect_lang] => 1

    It seems that hide_default and force_lang are somehow exclusive because if both are false I get redirect loops on front page. browser and redirect_lang is irrelevant here because changing those didn’t fix redirect problem.
    All redirects are to site root / and with status 302 if that is of any help.

    And I’m also getting PHP notices when opening non found pages/posts

    Trying to get property of non-object in [...]wp-includes/category-template.php on line 1082
    Trying to get property of non-object in [...]wp-content/plugins/polylang/include/base.php on line 121

    which must be because option page_for_posts is '0'. maybe you should check for such cases in Polylang_Core::translate_page() or get_post().

    Regarding your coding style – maybe you should not return false or null where object is expected or either check return values before using them. I know that it is easier and takes less code to do it like: $this->get_post_language($post_id)->term_id but it is harder to debug and maintain. And that return ''; in get_post is not nice. I is ok until you turn on WP_DEBUG and have error reporting set to E_ALL (which I always have on development sites).
    No flame intended – just trying to help. ??

    a bit off-topic:
    When I was starting my current project I thought I could go with WPML, as that is what the blog is using now. Then I discovered that WPML is not free anymore, so I looked for alternatives and found Polylang. It was looking promising until I encountered that bug with CPT and the other one with quick edit, but I decided to help out and maybe make it better. After all, that’s what opensource is about – making stuff better.

    @chouby Have you considered using WordPress plugin trac for bug reports? It’s a bit cluttered in reports section as there are many other devs using it, but it would be easier to track reports.

    I have updated to 0.8dev4.
    As for the CPT archive title issue: I still can’t get it to show up with wp_title() because get_queried_object() in post_type_archive_title() returns language taxonomy object instead of CPT object. I’ve been reading code of polylang and still can’t track down this bug.

    Another issue is redirect loop when opening home page without language slug. This doesn’t happen with language slug in url.
    After some testing and changing options I found out this happens only if hide_default ==0 and rewrite == 0.

    Strangely enough those notices in post_type_archive_title() are still coming in 0.8dev3.

Viewing 15 replies - 31 through 45 (of 51 total)