Wordpress add_rewrite_tag(),add_rewrite_rule()和post_link()

时间:2013-12-24 03:34:58

标签: php wordpress

我正在尝试执行以下操作:

重写我的WordPress安装的URL结构,以便在那里添加语言字段。例如。 http://www.mydomain.com/lang/

我想从/ lang /获取输入并使用它来显示相应的内容。例如。如果lang是'en',我将使用英语自定义字段并以英语显示主题。

这是我到目前为止所做的:

<?php
 function add_directory_rewrite() {
    global $wp_rewrite;
    add_rewrite_tag('%lang%', '(.+)');
    add_rewrite_rule('^/(.+)/', 'index.php?p=$matches[1]&lang=$matches[2]', 'top');
    add_permastruct('lang', '%lang%');

   }
    add_action( 'init', 'add_directory_rewrite' );
?>

这就像获取语言一样,但我面临的问题是现在the_permalink()有“/%lang%/”,其中/ en /应该是/ fr /或/ de /或任何语言。要添加更多详细信息,我的永久链接结构是/%lang%/%category%/%postname%/并且假设我有一个名为food的类别和一个标题为chicken的帖子,the_permalink将生成http://www.mydomain.com/%lang%/food/chicken/

知道我做错了什么吗?欢呼声。

3 个答案:

答案 0 :(得分:7)

您还需要添加一个函数,该函数将包含包含错误的'/%lang%/'段的永久链接,并将其替换为该帖子的相应默认语言。通常,您可以通过'pre_post_link'过滤器或'post_link'过滤器执行此操作。如果您使用前者,您将从头开始创建固定链接(完全自定义URL,不使用核心WP提供的任何内容)。如果使用后者,则可以在 WP完成它的魔法之后,但在网站上使用它之前过滤永久链接。这是一个例子:

function lou_rewrite_lang_in_permalink($permalink, $post, $leavename) {
  // find the default post language via a function you have created to 
  // determine the default language url. this could be based on the current
  // language the user has selected on the frontend, or based on the current
  // url, or based on the post itself. it is up to you
  $default_post_language = get_default_post_lang($post);

  // once you have the default language, it is a simple search and replace
  return str_replace('%lang%', $lang, $permalink);
}
add_filter('post_link', 'lou_rewrite_lang_in_permalink', 11, 3);

你没有提到它,所以我愿意。使用您原来的独奏功能,如果它是独立的话,你就会很难。原因是,虽然你已告诉重写者存在一个新的网址段,但你没有告诉WordPress将其视为网址参数。因此,即使你有一些花哨的代码来重写url并告诉WordPress花哨的lang param,WordPress也不知道它应该寻找它,因此忽略它。你需要添加这样的东西来纠正它:

function lou_add_lang_query_var($vars) {
  // tell WP to expect the lang query_var, which you can then later use
  $vars[] = 'lang';

  // return the new list of query vars, which includes our lang param
  return array_unique($vars);
}
add_filter('query_vars', 'lou_add_lang_query_var', 10, 1);

这将告诉WP()类它需要接受'lang'而不是仅仅跳过它。然后你可以做这样的事情来弄清楚当前页面是以它的语言发送的:

function lou_somefunction() {
  // do stuff
  ...

  // access the $wp object
  global $wp;

  // determine the language from the query_vars of the current page
  $lang = $wp->query_var['lang'];

  // do other stuff with $lang
  ...
}

希望这有帮助。

修改

首先,我想说,这是一个绝对的讽刺,语言网址不是WordPress本身支持的。我诚实地从不需要做到这一点,但我的大多数客户都不是国际公司,有国际需求。我将以代码形式向WordPress提交一些内容以便在以后的版本中解决此问题,但截至目前,您将需要一个类似于我在下面创建的插件。

所以我做了很多调查才能做到这一点。在与提问者进行简短对话后,如果发现我的解决方案不完整。当然,我开始挖掘。看起来应该是一个平庸的任务,结果证明是一个非常平庸的任务。简短的版本是,WordPress根本不希望您在每个网址的网址的中间或开头插入网址的额外部分。只需使用上面的代码,您就可以轻松地使用帖子网址进行此操作,但除此之外(页面,附件,作者页面等等)您必须做一些特别的事情。您还可以将部件添加到URL的末尾(端点),但即使这样也很复杂。

我在过去和现在都广泛使用过WordPress重写器,并且我拥有关于该主题的专业知识。尽管如此,我仍然需要4-5个小时才能编写一些内容,允许您在所有网址前加上语言指示符,然后可以用它来确定页面应显示的语言,而不管页面类型如何。有一个问题,我认为是可以接受的。您必须知道并准确指定要支持的语言前缀。对于任何想要使用它的人来说,我都不认为这是一个问题,但不过,这只是一种限制,仅仅是因为重写引擎的工作方式。

最后,这是一个可以用来完成此任务的插件。我在一个准确的WP安装上工作,主题为WooTheme。如果您安装了其他第三方插件,则可能不会对所有网址都有效,具体取决于他们添加重写规则的方式。在短期内,我可能会将其转换为WP的插件,然后在Wordpress.org上进行,但至少还需要几天时间。这是插件形式的代码的工作原型。在你的插件文件夹中创建一个新目录(比如/ wp-content / plugins / lou-lang),然后将这段代码粘贴到该文件夹​​中的php文件中(比如/ wp-content / plugins / lou-lang / lou -lang.php)。然后通过管理信息中心激活插件,该信息中心将标记为“Loushou语言网址”。

CODE:

<?php (__FILE__ == $_SERVER['SCRIPT_FILENAME']) ? die(header('Location: /')) : null;
/**
 * Plugin Name: Loushou Language URLs
 * Plugin URI:  http://quadshot.com/
 * Description: Adding the ability to have language support in your frontend urls.
 * Version:     0.1-beta
 * Author:      Loushou
 * Author URI:  http://quadshot.com/
 */

class lou_rewrite_takeover {
  protected static $add_rules = array();

  public static function pre_init() {
    // debug
    add_action('admin_footer-options-permalink.php', array(__CLASS__, 'qsart_rewrite_debug'));

    // add rw tag
    add_action('init', array(__CLASS__, 'add_directory_rewrite'));

    // rw rule adds
    add_filter(is_admin() ? 'setup_theme' : 'do_parse_request', array(__CLASS__, 'do_parse_request'), 0);
    add_filter('post_rewrite_rules', array(__CLASS__, 'post_rewrite_rules'));
    add_filter('date_rewrite_rules', array(__CLASS__, 'date_rewrite_rules'));
    add_filter('root_rewrite_rules', array(__CLASS__, 'root_rewrite_rules'));
    add_filter('comments_rewrite_rules', array(__CLASS__, 'comments_rewrite_rules'));
    add_filter('search_rewrite_rules', array(__CLASS__, 'search_rewrite_rules'));
    add_filter('author_rewrite_rules', array(__CLASS__, 'author_rewrite_rules'));
    add_filter('page_rewrite_rules', array(__CLASS__, 'page_rewrite_rules'));
    add_filter('rewrite_rules_array', array(__CLASS__, 'final_rules_correction'), PHP_INT_MAX, 1);

    // query vars
    add_filter('query_vars', array(__CLASS__, 'add_lang_query_var'), 10, 1);
    add_filter('request', array(__CLASS__, 'default_language'), 9);

    // fix permalinks
    $link_filters_needing_rewrite = array(
      'post_link',
      'post_type_link',
      'page_link',
      'attachment_link',
      'search_link',
      'post_type_archive_link',
      'year_link',
      'month_link',
      'day_link',
      'feed_link',
      'author_link',
      'term_link',
      'category_feed_link',
      'term_feed_link',
      'taxonomy_feed_link',
      'author_feed_link',
      'search_feed_link',
      'post_type_archive_feed_link',
    );
    add_filter('pre_post_link', array(__CLASS__, 'change_permalink_structure'), 10, 3);
    foreach ($link_filters_needing_rewrite as $link_filter)
      add_filter($link_filter, array(__CLASS__, 'rewrite_lang_in_permalink'), 11, 3);
  }

  public static function do_parse_request($cur) {
    self::get_page_permastruct();
    self::get_author_permastruct();
    self::correct_extras();
    return $cur;
  }

  public static function get_supported_langs() {
    return apply_filters('lou-get-supported-languages', array(
      'en',
    ));
  }

  public static function add_directory_rewrite() {
    global $wp_rewrite;
    $supported_languages = self::get_supported_langs();
    add_rewrite_tag('%lang%', '('.implode('|', $supported_languages).')');
  }

  public static function unleadingslashit($str) {
    return ltrim($str, '/');
  }

  public static function final_rules_correction($rules) {
    global $wp_rewrite;

    $new_rules = array();
    $supported_languages = self::get_supported_langs();
    $find = implode('|', $supported_languages);
    $find_find = '#(?<!\()('.preg_quote($find, '#').')#';
    $preg_node = str_replace('%%%', '(\d+)', preg_quote($wp_rewrite->preg_index('%%%'), '#'));

    foreach ($rules as $k => $v) {
      if (preg_match($find_find, $k)) {
        $nk = preg_replace($find_find, '('.$find.')', $k);
        $parts = explode('?', $v);
        $index = array_shift($parts);
        $pv = implode('?', $parts);
        $pv = preg_replace_callback('#'.$preg_node.'#', function ($matches) use ($wp_rewrite) {
          return $wp_rewrite->preg_index($matches[1]+1);
        }, $pv);
        $nv = $index.'?lang='.$wp_rewrite->preg_index(1).(!empty($pv) ? '&'.$pv : '');
        $new_rules[$nk] = $nv;
      } else {
        $new_rules[$k] = $v;
      }
    }

    return $new_rules;
  }

  public static function change_permalink_structure($struct) {
    $struct = self::unleadingslashit($struct);
    $struct = preg_replace('#^%lang%/?#', '', $struct);
    return '/%lang%/'.$struct;
  }

  public static function extras_rewrite_rules($rules, $struct) {
    global $wp_rewrite;

    if ( is_array( $struct ) ) {
      if ( count( $struct ) == 2 )
        $new_rules = $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($struct[0]), $struct[1] );
      else
        $new_rules = $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($struct['struct']), $struct['ep_mask'], $struct['paged'], $struct['feed'], $struct['forcomments'], $struct['walk_dirs'], $struct['endpoints'] );
    } else {
      $new_rules = $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($struct) );
    }

    return $new_rules + $rules;
  }

  public static function post_rewrite_rules($rules) {
    global $wp_rewrite;

    // hack to add code for extras type urls (usually created by other plugins)
    $func = array(__CLASS__, 'extras_rewrite_rules');
    foreach ($wp_rewrite->extra_permastructs as $type => $struct) {
      $filter = ($type == 'post_tag' ? 'tag' : $type).'_rewrite_rules';
      add_filter($filter, function ($rules) use ($struct, $func) { return call_user_func_array($func, array($rules, $struct)); });
    }

    return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->permalink_structure), EP_PERMALINK ) + $rules;
  }

  public static function date_rewrite_rules($rules) {
    global $wp_rewrite;
    return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->get_date_permastruct()), EP_DATE) + $rules;
  }

  public static function root_rewrite_rules($rules) {
    global $wp_rewrite;
    return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->get_date_permastruct()), EP_DATE) + $rules;
  }

  public static function comments_rewrite_rules($rules) {
    global $wp_rewrite;
    return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->root . $wp_rewrite->comments_base), EP_COMMENTS, false, true, true, false) + $rules;
  }

  public static function search_rewrite_rules($rules) {
    global $wp_rewrite;
    return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->get_search_permastruct()), EP_SEARCH) + $rules;
  }

  public static function author_rewrite_rules($rules) {
    global $wp_rewrite;
    return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->get_author_permastruct()), EP_AUTHORS) + $rules;
  }

  public static function page_rewrite_rules($rules) {
    global $wp_rewrite;
    $page_structure = self::get_page_permastruct();
    return $wp_rewrite->generate_rewrite_rules( $page_structure, EP_PAGES, true, true, false, false ) + $rules;
  }

  protected static function get_page_permastruct() {
    global $wp_rewrite;

    if (empty($wp_rewrite->permalink_structure)) {
      $wp_rewrite->page_structure = '';
      return false;
    }

    $wp_rewrite->page_structure = self::change_permalink_structure($wp_rewrite->root . '%pagename%');

    return $wp_rewrite->page_structure;
  }

  protected static function get_author_permastruct() {
    global $wp_rewrite;

    if ( empty($wp_rewrite->permalink_structure) ) {
      $wp_rewrite->author_structure = '';
      return false;
    }

    $wp_rewrite->author_structure = self::change_permalink_structure($wp_rewrite->front . $wp_rewrite->author_base . '/%author%');

    return $wp_rewrite->author_structure;
  }

  protected static function correct_extras() {
    global $wp_rewrite;

    foreach ($wp_rewrite->extra_permastructs as $k => $v)
      $wp_rewrite->extra_permastructs[$k]['struct'] = self::change_permalink_structure($v['struct']);
  }

  public static function get_default_post_lang($post) {
    return ( $lang = get_query_var('lang') ) ? $lang : 'en';
  }

  public static function rewrite_lang_in_permalink($permalink, $post=0, $leavename=false) {
    // find the default post language via a function you have created to 
    // determine the default language url. this could be based on the current
    // language the user has selected on the frontend, or based on the current
    // url, or based on the post itself. it is up to you
    $lang = self::get_default_post_lang($post);

    // once you have the default language, it is a simple search and replace
    return str_replace('%lang%', $lang, $permalink);
  }

  public static function add_lang_query_var($vars) {
    // tell WP to expect the lang query_var, which you can then later use
    $vars[] = 'lang';

    // return the new list of query vars, which includes our lang param
    return array_unique($vars);
  }

  public static function default_language($vars) {
    if (array_diff( array_keys($vars), array('preview', 'page', 'paged', 'cpage') ))
      $vars['lang'] = !empty($vars['lang']) ? $vars['lang'] : 'en';
    return $vars;
  }

  public static function qsart_rewrite_debug() {
    if (isset($_COOKIE['rwdebug']) && $_COOKIE['rwdebug'] == 1) {
      global $wp_rewrite;
      echo '<pre style="background-color:#ffffff; font-size:10px;">';
      print_r($wp_rewrite->rules);
      echo '</pre>';
    }
  }
}

if (defined('ABSPATH') && function_exists('add_action')) {
  lou_rewrite_takeover::pre_init();
}

默认情况下,此插件支持的唯一语言代码为'en'。显然你需要的不仅仅是那个。因此,一旦安装了插件,就可以在<theme>/functions.php文件中添加一些看起来像这样的代码,以添加剩余部分。

function more_languages($list) {
  $my_languages = array(
    'de', 'zh', 'bg', 'fr'
  );
  return array_unique($list + $my_languages);
}
add_filter('lou-get-supported-languages', 'more_languages', 10, 1);

一旦你 安装了插件并定义了自定义语言,那么你就有了最后一步。你必须保存永久链接。要从管理员执行此操作,请转到:设置 - &gt;永久链接 - &gt;保存更改(按钮)。毕竟,你应该好好去!

希望这对某人有所帮助,希望我能阻止一些时间在wp.org上解决这个问题。

答案 1 :(得分:2)

我偶然发现了这篇文章,同时寻找在网址路径前放置语言标签的解决方案。虽然wp_rewrite解决方案非常可靠,但它并不适合我的目的(例如,默认语言没有前面的语言标记等)。

所以我仔细看了一下qTranslate-plugin,之后我发现它使用了一个非常简单和优雅的解决方案:

基本上它做了两件事:

  1. (显然)它会更改所有Wordpress生成的链接(例如post_link,post_type_link,page_link等),以在网址中包含正确的语言标记。

  2. 而不是操纵复杂的重写规则让wordpress接受并正确处理语言标记,它只是挂钩&#34; plugins_loaded&#34; (在Wordpress尝试解析请求之前)并通过清除语言标记来操作$_SERVER['REQUEST_URI']。 所以,如果你是致电 www.example.com/en/myurlpath 仅限Wordpress&#34;看到&#34; www.example.com/myurlpath 。 在操纵之前$_SERVER['REQUEST_URI'] = "/en/myurlpath"。 操纵后$_SERVER['REQUEST_URI'] = "/myurlpath"

  3. 这是你唯一的工作&#34;是在Wordpress解析它们之前清理任何URL。

答案 2 :(得分:2)

这个问题很老但是......我正在为多语言网站开发一个轻量级的解决方案,我遇到了同样的问题。使用内置的WordPress功能没有简单的方法。然而(如user1254824所述)有一个很容易实现它的技巧。

您可以拦截$_SERVER['REQUEST_URI']全局var,解压缩/ lang / part并在WordPress解析之前将其删除。 WordPress将为您提供常规页面,但现在您已在var。

中使用了lang参数
function localization_uri_process() {

  global $lang; // then you can access $lang value in your theme's files

  if( preg_match("%\A/([a-z]{2})/%", $_SERVER['REQUEST_URI'], $matches) ){
    $lang = $matches[1];
    $_SERVER['REQUEST_URI'] = preg_replace("%\A/[a-z]{2}/%", '/', $_SERVER['REQUEST_URI'] );
  }
  else
    $lang = 'en'; // your default language
}
add_action( 'plugins_loaded', 'localization_uri_process' );

然后,您还可以使用过滤器自动重写所有链接。

PS:代码需要在插件中。它不会在你的模板php文件中工作。