/** * Get a link to trash a particular post. * * @param int $post_id The ID of the post to trash * @param string $action The action for this link * @return string A Nonced action URL **/ protected function get_action_link($obj_id, $action, $anchor = null) { $args = array('btgt_action' => $action, 'obj_id' => $obj_id, 'lang' => bbl_get_default_lang_code()); if (!is_null($anchor)) { $args['anchor'] = $anchor; } $args = array_map('rawurlencode', $args); return wp_nonce_url(add_query_arg($args), "btgt_{$action}_{$obj_id}"); }
/** * Checks whether either the provided language code, * if provided, or the current language code are * the default language. * * i.e. is this language the default language * * n.b. the current language could have been switched * using bbl_switch_to_lang * * @param string $lang_code The language code to check (optional) * @return bool True if the default language **/ function bbl_is_default_lang($lang_code = null) { if (is_null($lang_code)) { $lang = bbl_get_current_lang(); } else { if (is_string($lang_code)) { // In case someone passes a lang object $lang = bbl_get_lang($lang_code); } } return bbl_get_default_lang_code() == $lang->code; }
/** * Resync all (synced) post meta data from the post in * the default language to this post. * * @param $int The post ID to sync TO * @return void **/ function sync_post_meta($post_id) { if ($this->no_meta_recursion) { return; } $this->no_meta_recursion = 'updated_post_meta'; // First delete all the synced meta from this post $current_metas = (array) get_post_meta($post_id); foreach ($current_metas as $current_meta_key => &$current_meta_values) { // Some metadata shouldn't be synced, this filter allows a dev to return // false if the particular meta_key is one which shouldn't be synced. // If you find a core meta_key which is currently synced and should NOT be, // please submit a patch to the sync_meta_key method on this class. Thanks. if (apply_filters('bbl_sync_meta_key', true, $current_meta_key)) { delete_post_meta($post_id, $current_meta_key); } } // Now add meta in again from the origin post $origin_post = bbl_get_post_in_lang($post_id, bbl_get_default_lang_code()); $metas = get_post_meta($origin_post->ID); if (!$metas) { return; } foreach ($metas as $meta_key => &$meta_value) { // Some metadata shouldn't be synced if (!apply_filters('bbl_sync_meta_key', true, $meta_key)) { continue; } // The meta could be an array stored in a single postmeta row or an // array of values from multiple rows; work out which we have. $val_multi = get_post_meta($origin_post->ID, $meta_key); foreach ($val_multi as &$val_single) { add_post_meta($post_id, $meta_key, $val_single); } } $this->no_meta_recursion = false; }
/** * Add a link to a taxonomy archive. * * @param object $lang A Babble language object for this link * @return void **/ protected function add_taxonomy_archive_link($lang) { $classes = array(); $queried_object = get_queried_object(); if (!bbl_is_translated_taxonomy($queried_object->taxonomy)) { $this->add_arbitrary_link($lang); return; } elseif (isset($this->translations[$lang->code]->term_id)) { // Translation exists bbl_switch_to_lang($lang->code); $href = get_term_link($this->translations[$lang->code], bbl_get_base_taxonomy($queried_object->taxonomy)); bbl_restore_lang(); $title = sprintf(__('Switch to %s', 'babble'), $lang->display_name); $classes[] = 'bbl-existing'; $classes[] = 'bbl-existing-term'; } else { // Translation does not exist // Generate a URL to create the translation $default_term = $this->translations[bbl_get_default_lang_code()]; $href = bbl_get_new_term_translation_url($default_term->term_id, $lang->code, $default_term->taxonomy); $title = sprintf(__('Create for %s', 'babble'), $lang->display_name); $classes[] = 'bbl-add'; $classes[] = 'bbl-add-term'; } $href = apply_filters('bbl_switch_taxonomy_archive_link', $href, $lang, $this->translations); $classes[] = "bbl-lang-{$lang->code} bbl-lang-{$lang->url_prefix}"; $classes[] = 'bbl-lang'; $classes[] = 'bbl-term'; if ($lang == bbl_get_current_lang_code()) { $classes[] = 'bbl-active'; } $this->links[$lang->code] = array('classes' => $classes, 'href' => $href, 'id' => $lang->url_prefix, 'meta' => array('class' => strtolower(join(' ', array_unique($classes)))), 'title' => $title, 'lang' => $lang); }
?> </span><br /> <a href="<?php echo esc_url(add_query_arg(array('lang' => bbl_get_post_lang_code($post->ID)), get_edit_post_link($post->ID))); ?> ">edit</a> | <a href="<?php echo esc_url($this->get_action_link($post->ID, 'delete_post', "tg-{$term->term_id}")); ?> ">delete</a> | <a href="<?php echo esc_url($this->get_action_link($post->ID, 'trash_post', "tg-{$term->term_id}")); ?> ">trash</a> | <?php if (bbl_get_default_lang_code() == bbl_get_post_lang_code($post->ID)) { ?> <a href="<?php echo esc_url($this->get_action_link($post->ID, 'delete_from_groups', "tg-{$term->term_id}")); ?> ">remove from group</a> <?php } ?> </th> <td class="manage-column column-type"><?php echo esc_html($post->post_type); ?> </td> <td class="manage-column column-status"><?php echo esc_html($post->post_status);
/** * Create some translation jobs. * * @param int $post_id The ID of the post to create translation jobs for * @param array $lang_codes The language codes to create translation jobs of this post for * @return array An array of Translation Job post IDs **/ public function create_post_jobs($post_id, array $lang_codes) { $post = get_post($post_id); // @TODO Validate that the $post is in the default language, otherwise fail $jobs = array(); foreach ($lang_codes as $lang_code) { if (bbl_get_default_lang_code() == $lang_code) { continue; } if (apply_filters('bbl_create_empty_translation', false, $post)) { wp_schedule_single_event(time(), 'babble_create_empty_translation', array(array('post_id' => $post->ID))); } $this->no_recursion = true; $job = wp_insert_post(array('post_type' => 'bbl_job', 'post_status' => 'new', 'post_author' => get_current_user_id(), 'post_title' => get_the_title($post))); $this->no_recursion = false; // @TODO If a translation already exists, populate the translation job with the translation $jobs[] = $job; add_post_meta($job, 'bbl_job_post', "{$post->post_type}|{$post->ID}", true); wp_set_object_terms($job, $lang_code, 'bbl_job_language'); foreach ($this->get_post_terms_to_translate($post, $lang_code) as $taxo => $terms) { foreach ($terms as $term_id => $term) { add_post_meta($job, 'bbl_job_term', "{$taxo}|{$term_id}", false); } } foreach ($this->get_post_meta_to_translate($post, $lang_code) as $key => $field) { add_post_meta($job, 'bbl_job_meta', $key, false); } } $this->clean_object_jobs_cache($post->ID, 'post', $post->post_type); return $jobs; }
/** * Hooks the WP locale filter to switch locales whenever we gosh darned want. * * @param string $locale The locale * @return string The locale **/ public function set_locale($locale) { // Deal with the special case of wp-comments-post.php if (false !== stristr($_SERVER['REQUEST_URI'], 'wp-comments-post.php')) { // @TODO we should be able to hook into an action here (pre_comment_post) rather than looking at the URL. if ($comment_post_ID = isset($_POST['comment_post_ID']) ? (int) $_POST['comment_post_ID'] : false) { if (!isset($this->content_lang)) { $this->set_content_lang(bbl_get_post_lang_code($comment_post_ID)); } return $this->content_lang; } } if (is_admin()) { if (isset($this->interface_lang)) { return $this->interface_lang; } } else { if (isset($this->content_lang)) { return $this->content_lang; } } // $current_user = wp_get_current_user(); if ($lang = $this->get_cookie_interface_lang()) { $this->set_interface_lang($lang); } // $current_user = wp_get_current_user(); if ($lang = $this->get_cookie_content_lang()) { $this->set_content_lang($lang); } $active_langs = bbl_get_active_langs(); $active_lang_codes = wp_list_pluck($active_langs, 'code'); $active_lang_prefixes = wp_list_pluck($active_langs, 'url_prefix'); if (is_admin()) { if (isset($_POST['interface_lang'])) { $lang = $_POST['interface_lang']; if (!in_array($lang, $active_lang_codes, true)) { $lang = bbl_get_default_lang_code(); } $this->set_interface_lang($lang); } if (isset($_GET['lang'])) { $lang = $_GET['lang']; if (!in_array($lang, $active_lang_codes, true)) { $lang = bbl_get_default_lang_code(); } $this->set_content_lang($lang); } } else { // Front end if (preg_match($this->lang_regex, $this->get_request_string(), $matches)) { if (in_array($matches[0], $active_lang_prefixes, true)) { $this->set_content_lang_from_prefix($matches[0]); } } } if (!isset($this->content_lang) || !$this->content_lang) { $this->set_content_lang(bbl_get_default_lang_code()); } if (!isset($this->interface_lang) || !$this->interface_lang) { $this->set_interface_lang(bbl_get_default_lang_code()); } if (is_admin()) { return $this->interface_lang; } else { return $this->content_lang; } }
/** * Checks for the relevant POSTed field, then * resyncs the terms. * * @param int $post_id The ID of the WP post * @param object $post The WP Post object * @return void **/ protected function maybe_resync_terms($post_id, $post) { // Check that the fields were included on the screen, we // can do this by checking for the presence of the nonce. $nonce = isset($_POST['_bbl_metabox_resync']) ? $_POST['_bbl_metabox_resync'] : false; if (!in_array($post->post_status, array('draft', 'publish'))) { return; } if (!$nonce) { return; } $posted_id = isset($_POST['post_ID']) ? $_POST['post_ID'] : 0; if ($posted_id != $post_id) { return; } // While we're at it, let's check the nonce check_admin_referer("bbl_resync_translation-{$post_id}", '_bbl_metabox_resync'); if ($this->no_recursion) { return; } $this->no_recursion = true; $taxonomies = get_object_taxonomies($post->post_type); $origin_post = bbl_get_post_in_lang($post_id, bbl_get_default_lang_code()); // First dissociate all the terms from synced taxonomies from this post wp_delete_object_term_relationships($post_id, $taxonomies); // Now associate terms from synced taxonomies in from the origin post foreach ($taxonomies as $taxonomy) { $origin_taxonomy = $taxonomy; if ($this->is_taxonomy_translated($taxonomy)) { $origin_taxonomy = bbl_get_taxonomy_in_lang($taxonomy, bbl_get_default_lang_code()); } $term_ids = wp_get_object_terms($origin_post->ID, $origin_taxonomy, array('fields' => 'ids')); $term_ids = array_map('absint', $term_ids); $result = wp_set_object_terms($post_id, $term_ids, $taxonomy); if (is_wp_error($result, true)) { throw new exception("Problem syncing terms: " . print_r($terms, true), " Error: " . print_r($result, true)); } } }
/** * Hooks the WP locale filter to switch locales whenever we gosh darned want. * * @param string $locale The locale * @return string The locale **/ public function set_locale($locale) { // Deal with the special case of wp-comments-post.php if (false !== stristr($_SERVER['REQUEST_URI'], 'wp-comments-post.php')) { // @TODO we should be able to hook into an action here (pre_comment_post) rather than looking at the URL. if ($comment_post_ID = isset($_POST['comment_post_ID']) ? (int) $_POST['comment_post_ID'] : false) { if (!isset($this->content_lang)) { $this->set_content_lang(bbl_get_post_lang_code($comment_post_ID)); } return $this->content_lang; } } if (is_admin()) { if (isset($this->interface_lang)) { return $this->interface_lang; } } else { if (isset($this->content_lang)) { return $this->content_lang; } } // $current_user = wp_get_current_user(); if ($lang = $this->get_cookie_interface_lang()) { $this->set_interface_lang($lang); } // $current_user = wp_get_current_user(); if ($lang = $this->get_cookie_content_lang()) { $this->set_content_lang($lang); } if (is_admin()) { // @FIXME: At this point a mischievous XSS "attack" could set a user's admin area language for them if (isset($_POST['interface_lang'])) { $this->set_interface_lang($_POST['interface_lang']); } // @FIXME: At this point a mischievous XSS "attack" could set a user's content language for them if (isset($_GET['lang'])) { $this->set_content_lang($_GET['lang']); } } else { // Front end // @FIXME: Should probably check the available languages here if (preg_match($this->lang_regex, $this->get_request_string(), $matches)) { $this->set_content_lang_from_prefix($matches[0]); } } if (!isset($this->content_lang) || !$this->content_lang) { $this->set_content_lang(bbl_get_default_lang_code()); } if (!isset($this->interface_lang) || !$this->interface_lang) { $this->set_interface_lang(bbl_get_default_lang_code()); } if (is_admin()) { return $this->interface_lang; } else { return $this->content_lang; } }
/** * Will update term count based on object types of the current * taxonomy. Will only count the post(s) in the default language. * * Private function for the default callback for post_tag and category * taxonomies. * * @param array $terms List of Term taxonomy IDs * @param object $taxonomy Current taxonomy object of terms */ function update_post_term_count($terms, $taxonomy) { global $wpdb; $object_types = (array) $taxonomy->object_type; foreach ($object_types as &$object_type) { list($object_type) = explode(':', $object_type); // Babble specific code, to only count in primary language $object_type = bbl_get_post_type_in_lang($object_type, bbl_get_default_lang_code()); } $object_types = array_unique($object_types); if (false !== ($check_attachments = array_search('attachment', $object_types))) { unset($object_types[$check_attachments]); $check_attachments = true; } if ($object_types) { $object_types = esc_sql(array_filter($object_types, 'post_type_exists')); } foreach ((array) $terms as $term) { $count = 0; // Attachments can be 'inherit' status, we need to base count off the parent's status if so if ($check_attachments) { $count += (int) $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$wpdb->term_relationships}, {$wpdb->posts} p1 WHERE p1.ID = {$wpdb->term_relationships}.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM {$wpdb->posts} WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term)); } if ($object_types) { $count += (int) $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$wpdb->term_relationships}, {$wpdb->posts} WHERE {$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id AND post_status = 'publish' AND post_type IN ('" . implode("', '", $object_types) . "') AND term_taxonomy_id = %d", $term)); } do_action('edit_term_taxonomy', $term, $taxonomy); $wpdb->update($wpdb->term_taxonomy, compact('count'), array('term_taxonomy_id' => $term)); do_action('edited_term_taxonomy', $term, $taxonomy); } }