/** * Hooks the WP registered_post_type action. * * @param string $post_type The post type which has just been registered. * @param object $args The arguments with which the post type was registered * @return void **/ public function registered_post_type($post_type, $args) { // Don't bother with non-public post_types for now // @FIXME: This may need to change for menus? if (false === $args->public) { return; } // Don't shadow shadow post types, it's going to get silly if (in_array($post_type, $this->post_types)) { return; } if ($this->no_recursion) { return; } $this->no_recursion = 'registered_post_type'; $langs = bbl_get_active_langs(); // Lose the default language as any existing post types are in that language unset($langs[bbl_get_default_lang_url_prefix()]); // $args is an object at this point, but register_post_type needs an array $args = get_object_vars($args); // @FIXME: Is it reckless to convert ALL object instances in $args to an array? foreach ($args as $key => &$arg) { if (is_object($arg)) { $arg = get_object_vars($arg); } // Don't set any args reserved for built-in post_types if ('_' == substr($key, 0, 1)) { unset($args[$key]); } } $features = $this->get_features_supported_by_post_type($post_type); $args['supports'] = array(); foreach ($features as $feature => $true) { $args['supports'][] = $feature; } // I am a little concerned that this argument may make things // brittle, e.g. the UI might stop showing up in the shadow // post type edit screens, p'raps. $args['show_ui'] = true; $slug = $args['rewrite']['slug'] ? $args['rewrite']['slug'] : $post_type; $archive_slug = false; if ($archive_slug = $args['has_archive']) { if (!is_string($args['has_archive'])) { $archive_slug = $slug; } } $current_lang_code = bbl_get_current_lang_code(); foreach ($langs as $lang) { $new_args = $args; // @FIXME: We are in danger of a post_type name being longer than 20 chars // I would prefer to keep the post_type human readable, as human devs and sysadmins always // end up needing to read this kind of thing. // @FIXME: Should I be sanitising these values? $new_post_type = strtolower("{$post_type}_{$lang->code}"); if (strlen($new_post_type) > 20) { trigger_error(sprintf(__('Warning: The translated name for the post type %s is longer than %d characters. This *will* cause problems.', 'babble'), esc_html($post_type), 20)); } if (false !== $args['rewrite']) { if (!is_array($new_args['rewrite'])) { $new_args['rewrite'] = array(); } $new_args['query_var'] = $new_args['rewrite']['slug'] = $this->get_slug_in_lang($slug, $lang, $args); $new_args['has_archive'] = $this->get_slug_in_lang($archive_slug, $lang); } $this->slugs_and_vars[$lang->code . '_' . $post_type] = array('query_var' => $new_args['query_var'], 'has_archive' => $new_args['has_archive']); // Don't let the translated post types show up in the search if their // language is not the current language. if ($lang->code != $current_lang_code) { $new_args['exclude_from_search'] = true; $new_args['capabilities']['create_posts'] = 'do_not_allow'; } $result = register_post_type($new_post_type, $new_args); if (is_wp_error($result)) { error_log("Error creating shadow post_type for {$new_post_type}: " . print_r($result, true)); } else { $this->post_types[$new_post_type] = $post_type; $this->lang_map[$new_post_type] = $lang->code; // @TODO: Refactor the $this::lang_map array so we can use this new structure instead if (!isset($this->lang_map2[$lang->code]) || !is_array($this->lang_map2[$lang->code])) { $this->lang_map2[$lang->code] = array(); } $this->lang_map2[$lang->code][$post_type] = $new_post_type; // This will not work until init has run at the early priority used // to register the post_translation taxonomy. However we catch all the // post_types registered before the hook runs, so we don't miss any // (take a look at where we register post_translation for more info). register_taxonomy_for_object_type('post_translation', $new_post_type); } } // Exclude the registered post type from search if it's language isn't // the current language. if ($current_lang_code != bbl_get_default_lang_code()) { $post_type_obj = get_post_type_object($post_type); $post_type_obj->exclude_from_search = true; } do_action('bbl_registered_shadow_post_types', $post_type); $this->no_recursion = false; }
/** * Hooks the WP parse_request action * * FIXME: Should I be extending and replacing the WP class? * * @param WP $wp The WP object, passed by reference (so no need to return) * @return void **/ public function parse_request_early(WP $wp) { // If this is the site root, redirect to default language homepage if (!$wp->request && !is_admin()) { remove_filter('home_url', array($this, 'home_url'), null, 2); wp_safe_redirect(home_url(bbl_get_default_lang_url_prefix())); exit; } // Otherwise, simply set the lang for this request if (!isset($this->content_lang)) { if (preg_match($this->lang_regex, $this->get_request_string(), $matches)) { $this->set_content_lang_from_prefix($matches[0]); } else { $this->set_content_lang_from_prefix(bbl_get_default_lang_url_prefix()); } } $wp->query_vars['lang'] = $this->content_lang; $wp->query_vars['lang_url_prefix'] = $this->url_prefix; }
/** * Hooks the WP registered_post_type action. * * @param string $post_type The post type which has just been registered. * @param object $args The arguments with which the post type was registered * @return void **/ public function registered_post_type($post_type, $args) { // Don't bother with non-public post_types for now // @FIXME: This may need to change for menus? if (false === $args->public) { return; } // Don't shadow shadow post types, it's going to get silly if (in_array($post_type, $this->post_types)) { return; } if ($this->no_recursion) { return; } $this->no_recursion = 'registered_post_type'; $langs = bbl_get_active_langs(); // Lose the default language as any existing post types are in that language unset($langs[bbl_get_default_lang_url_prefix()]); // $args is an object at this point, but register_post_type needs an array $args = get_object_vars($args); // @FIXME: Is it reckless to convert ALL object instances in $args to an array? foreach ($args as $key => &$arg) { if (is_object($arg)) { $arg = get_object_vars($arg); } // Don't set any args reserved for built-in post_types if ('_' == substr($key, 0, 1)) { unset($args[$key]); } } $features = $this->get_features_supported_by_post_type($post_type); $args['supports'] = array(); foreach ($features as $feature => $true) { $args['supports'][] = $feature; } // I am a little concerned that this argument may make things // brittle, e.g. the UI might stop showing up in the shadow // post type edit screens, p'raps. $args['show_ui'] = true; $slug = $args['rewrite']['slug'] ? $args['rewrite']['slug'] : $post_type; $archive_slug = false; if ($archive_slug = $args['has_archive']) { if (!is_string($args['has_archive'])) { $archive_slug = $slug; } } $current_lang_code = bbl_get_current_lang_code(); foreach ($langs as $lang) { $new_args = $args; $new_post_type = self::generate_shadow_post_type_name($post_type, $lang->code); if (false !== $args['rewrite']) { if (!is_array($new_args['rewrite'])) { $new_args['rewrite'] = array(); } $new_args['query_var'] = $new_args['rewrite']['slug'] = $this->get_slug_in_lang($slug, $lang, $args); $new_args['has_archive'] = $this->get_slug_in_lang($archive_slug, $lang); } $this->slugs_and_vars[$lang->code . '_' . $post_type] = array('query_var' => $new_args['query_var'], 'has_archive' => $new_args['has_archive']); // Don't let the translated post types show up in the search if their // language is not the current language. if ($lang->code != $current_lang_code) { $new_args['exclude_from_search'] = true; $new_args['capabilities']['create_posts'] = 'do_not_allow'; } $result = register_post_type($new_post_type, $new_args); if (is_wp_error($result)) { bbl_log("Error creating shadow post_type for {$new_post_type}: " . print_r($result, true), true); } else { $this->post_types[$new_post_type] = $post_type; $this->post_type_map[$new_post_type] = $lang->code; if (!isset($this->lang_map[$lang->code]) || !is_array($this->lang_map[$lang->code])) { $this->lang_map[$lang->code] = array(); } $this->lang_map[$lang->code][$post_type] = $new_post_type; // This will not work until init has run at the early priority used // to register the post_translation taxonomy. However we catch all the // post_types registered before the hook runs, so we don't miss any // (take a look at where we register post_translation for more info). register_taxonomy_for_object_type('post_translation', $new_post_type); } } // Exclude the registered post type from search if it's language isn't // the current language. if ($current_lang_code != bbl_get_default_lang_code()) { $post_type_obj = get_post_type_object($post_type); $post_type_obj->exclude_from_search = true; } do_action('bbl_registered_shadow_post_types', $post_type); $this->no_recursion = false; }
/** * Hooks the WP registered_taxonomy action * * @param string $taxonomy The name of the newly registered taxonomy * @param string|array $args The object_type(s) * @param array $args The args passed to register the taxonomy * @return void **/ public function registered_taxonomy($taxonomy, $object_type, $args) { if (in_array($taxonomy, $this->ignored_taxonomies())) { return; } if ($this->no_recursion) { return; } $this->no_recursion = true; if (!is_array($object_type)) { $object_type = array_unique((array) $object_type); } // Use the Babble term counting function, unless the taxonomy registrant // has defined their own – in which case we'll just have to hope against // hope that it's Babble aware :S // FIXME: Setting this in the following fashion seems hacky… I feel uncomfortable. if (empty($GLOBALS['wp_taxonomies'][$taxonomy]->update_count_callback)) { $GLOBALS['wp_taxonomies'][$taxonomy]->update_count_callback = array($this, 'update_post_term_count'); } // Untranslated taxonomies do not have shadow equivalents in each language, // but do apply to the bast post_type and all it's shadow post_types. if (!$this->is_taxonomy_translated($taxonomy)) { // Apply this taxonomy to all the shadow post types // of all of the base post_types it applies to. foreach ($object_type as $ot) { if (!($base_post_type = bbl_get_base_post_type($ot))) { continue; } $shadow_post_types = bbl_get_shadow_post_types($base_post_type); foreach ($shadow_post_types as $shadow_post_type) { register_taxonomy_for_object_type($taxonomy, $shadow_post_type); } } $this->no_recursion = false; return; } // @FIXME: Not sure this is the best way to specify languages $langs = bbl_get_active_langs(); // Lose the default language as any existing taxonomies are in that language unset($langs[bbl_get_default_lang_url_prefix()]); // @FIXME: Is it reckless to convert ALL object instances in $args to an array? foreach ($args as $key => &$arg) { if (is_object($arg)) { $arg = get_object_vars($arg); } // Don't set any args reserved for built-in post_types if ('_' == substr($key, 0, 1)) { unset($args[$key]); } } #$args[ 'rewrite' ] = false; unset($args['name']); unset($args['object_type']); $slug = $args['rewrite']['slug'] ? $args['rewrite']['slug'] : $taxonomy; foreach ($langs as $lang) { $new_args = $args; $new_object_type = array(); // N.B. Here we assume that the taxonomy is on a post type foreach ($object_type as $ot) { $new_object_type[] = bbl_get_post_type_in_lang($ot, $lang->code); } if (false !== $args['rewrite']) { if (!is_array($new_args['rewrite'])) { $new_args['rewrite'] = array(); } // Do I not need to add this query_var into the query_vars filter? It seems not. $new_args['query_var'] = $new_args['rewrite']['slug'] = $this->get_slug_in_lang($slug, $lang->code); } // @FIXME: Note currently we are in danger of a taxonomy name being longer than 32 chars // Perhaps we need to create some kind of map like (taxonomy) + (lang) => (shadow translated taxonomy) $new_taxonomy = strtolower("{$taxonomy}_{$lang->code}"); $this->taxonomies[$new_taxonomy] = $taxonomy; if (!isset($this->lang_map[$lang->code]) || !is_array($this->lang_map[$lang->code])) { $this->lang_map[$lang->code] = array(); } $this->lang_map[$lang->code][$taxonomy] = $new_taxonomy; register_taxonomy($new_taxonomy, $new_object_type, $new_args); } // bbl_stop_logging(); $this->no_recursion = false; }
/** * Hooks the WP parse_request action * * FIXME: Should I be extending and replacing the WP class? * * @param WP $wp The WP object, passed by reference (so no need to return) * @return void **/ public function parse_request_early(WP $wp) { // If this is the site root, redirect to default language homepage if (!$wp->request) { remove_filter('home_url', array($this, 'home_url'), null, 2); wp_redirect(home_url(bbl_get_default_lang_url_prefix())); exit; } // Otherwise, simply set the lang for this request $wp->query_vars['lang'] = $this->content_lang; $wp->query_vars['lang_url_prefix'] = $this->url_prefix; }