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.
