wordpress自定义url路由规则 — WordPress 路由浅析

本文将阐述WordPress (WordPress Router)如何解析请求URL以及根据URL来决定显示 什么内容或者做什么。不同于其他框架比如 Drupal 或者 Kohana ,你基本上只需要定义一些”URL-pattern” -> “Function call”的映射,在 WordPress 中这整个过程复杂的多同时缺少灵活性。所幸的是,有一款优秀的插件 – WP Router ,它可以帮你简化这一过程。 但是,不用插件,让我们看看 WordPress 能做些什么。

Module “Except”

我们来做一个测试模块 – “Except”,通过完成该模块来讲解 WordPress 的URL路由原理。默认情况下,当你访问以下URL时http://wp.example.com/category/ABCDE/ ,你将会看到该分类下的所有文章。而这个模块要达到的效果是,当访问如下的URL时 http://wp.example.com/except/category/ABCDE/ ,显示除了分类”ABCDE”下的所有文章。

你可以从 这里 下载最终完成的模块然后照着例子学习。或者你可以跟着我学习如何一步一步的完成这个模块。

首先,让我们在WordPress站点键入一些URL。就拿Groupon Blog来举个栗子:

https://blog.groupon.com/category/cities/ — 有效,可以访问。

https://blog.groupon.com/except/category/cities/ — Page Not Found。 意料之中,WordPress不知道你想要干什么。

步骤 0: 整体框架

从一个默认的模板来构建模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Plugin Name: Except
Plugin URI: http://ruslanbes.com/projects/except
Description: Make urls like http://wp.example.com/except/category/ABCDE/ display all posts except from category ABCDE
Version: 2013.03.26
Author: Ruslan Bes < me@ruslanbes.com >
Author URI: http://ruslanbes.com/devblog
*/
define('EXCEPT_PATH', dirname(__FILE__) .'/');
class Except {
}
$Except = new Except();

这里只定义了3件事:

  1. 一个常量EXCEPT_PATH – 定义了模块的根路径,方便引用模块里的其他文件(虽然此处没有用到该常量,但是作为一个插件作者,这个很有用)。
  2. 一个类 – Except
  3. 一个类的实例对象 $Except

步骤 1: 注册钩子(Hook)

第一件事就是告诉WordPress当模块第一次被激活时,WordPress 应该添加新的重写规则到默认序列并且刷新它。 为了优雅干净,当模块被停用时,应该删除这些规则。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
Plugin Name: Except
Plugin URI: http://ruslanbes.com/projects/except
Description: Make urls like http://wp.example.com/except/category/ABCDE/ display all posts except from category ABCDE
Version: 2013.03.26
Author: Ruslan Bes < me@ruslanbes.com >
Author URI: http://ruslanbes.com/devblog
*/
define('EXCEPT_PATH', dirname(__FILE__) .'/');
class Except {
  function __construct() {
      register_activation_hook( __FILE__, array($this, 'activate') );
      register_deactivation_hook( __FILE__, array($this, 'deactivate') );
  }
  function activate() {
    add_action( 'generate_rewrite_rules', array($this, 'add_rewrite_rules') );
    global $wp_rewrite; $wp_rewrite->flush_rules(); // force call to generate_rewrite_rules()
  }
  function deactivate() {
    global $wp_rewrite; $wp_rewrite->flush_rules();
  }
  function add_rewrite_rules(){
    // ???
  }
}
$Except = new Except();

我们先把关键函数add_rewrite_rules()留空,因为我要先解释一些东西。

WordPress重写规则是如何工作的

要想知道答案,我们必须知道什么是重写规则?它们从哪来?为什么要钩进去(hook into)?

首先,关于什么是“重写规则”,他们是一个类似下面的数组:

array = 
  category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$: string = index.php?category_name=$matches[1]&feed=$matches[2]
  category/(.+?)/(feed|rdf|rss|rss2|atom)/?$: string = index.php?category_name=$matches[1]&feed=$matches[2]
  category/(.+?)/page/?([0-9]{1,})/?$: string = index.php?category_name=$matches[1]&paged=$matches[2]
  category/(.+?)/?$: string = index.php?category_name=$matches[1]
  tag/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$: string = index.php?tag=$matches[1]&feed=$matches[2]
  tag/([^/]+)/(feed|rdf|rss|rss2|atom)/?$: string = index.php?tag=$matches[1]&feed=$matches[2]
  tag/([^/]+)/page/?([0-9]{1,})/?$: string = index.php?tag=$matches[1]&paged=$matches[2]
  tag/([^/]+)/?$: string = index.php?tag=$matches[1]
  ...

这个数组存储在数据库表wp_options,option_name为rewrite_rules的数据行里。 在调用方法WP_Rewrite::wp_rewrite_rules()时加载进了WordPress。从上面的例子中你也许发现了,rewrite_rules包含了将地址栏里的URL转换成通常的GET字符串的指令。它必须是人类可读的URL,也就是说,当两个不同的人分别访问http://wp.example.com/category/carolhttp://wp.example.com/index.php?category_name=carol时,必须指向同一个页面。这就解释了为什么我们如此关心它 — 因为我们想要一个简短漂亮的URL。这同样回答了为什么它要存在数据库里而不是在每个页面加载时生成它 — 因为通常它不会改变。

步骤 2: 创建我们自己的规则

现在,我们知道了在add_rewrite_rules()方法里该加些什么内容了。我们可能需要这样的规则:

array = 
  except/category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$: string = index.php?except_category_name=$matches[1]&feed=$matches[2]
  except/category/(.+?)/(feed|rdf|rss|rss2|atom)/?$: string = index.php?except_category_name=$matches[1]&feed=$matches[2]
  except/category/(.+?)/page/?([0-9]{1,})/?$: string = index.php?except_category_name=$matches[1]&paged=$matches[2]
  except/category/(.+?)/?$: string = index.php?except_category_name=$matches[1]

试着加一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/*
Plugin Name: Except
Plugin URI: http://ruslanbes.com/projects/except
Description: Make urls like http://wp.example.com/except/category/ABCDE/ display all posts except from category ABCDE
Version: 2013.03.26
Author: Ruslan Bes < me@ruslanbes.com >
Author URI: http://ruslanbes.com/devblog
*/
define('EXCEPT_PATH', dirname(__FILE__) .'/');
class Except {
  function __construct() {
      register_activation_hook( __FILE__, array($this, 'activate') );
      register_deactivation_hook( __FILE__, array($this, 'deactivate') );
  }
  function activate() {
    add_action( 'generate_rewrite_rules', array($this, 'add_rewrite_rules') );
    global $wp_rewrite; $wp_rewrite->flush_rules(); // force call to generate_rewrite_rules()
  }
  function deactivate() {
    global $wp_rewrite; $wp_rewrite->flush_rules();
  }
  function add_rewrite_rules($wp_rewrite){
    $rules = array(
      'except/category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$'  => 'index.php?except_category_name=$matches[1]&feed=$matches[2]',
      'except/category/(.+?)/(feed|rdf|rss|rss2|atom)/?$'       => 'index.php?except_category_name=$matches[1]&feed=$matches[2]',
      'except/category/(.+?)/page/?([0-9]{1,})/?$'              => 'index.php?except_category_name=$matches[1]&paged=$matches[2]',
      'except/category/(.+?)/?$'                                => 'index.php?except_category_name=$matches[1]',
      );
    $wp_rewrite->rules = $rules + (array)$wp_rewrite->rules;
  }
}
$Except = new Except();

不错,现在启用模块,尝试访问如下的地址 http://wp.example.com/except/category/enter_some_gibberish_here/. 不同于404页面,你将会看到你网站的主页。这好多了。WordPress知道这个URL是有效的,但还不知道该怎么去处理请求,所以显示了所有文章。

步骤 3: 过滤文章

现在,我们需要插入到 WordPress 查询(query)来过滤文章。幸运的是有一个绝好的地方 — pre_get_posts 钩子。 我们来试一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
Plugin Name: Except
Plugin URI: http://ruslanbes.com/projects/except
Description: Make urls like http://wp.example.com/except/category/ABCDE/ display all posts except from category ABCDE
Version: 2013.03.26
Author: Ruslan Bes < me@ruslanbes.com >
Author URI: http://ruslanbes.com/devblog
*/
define('EXCEPT_PATH', dirname(__FILE__) .'/');
class Except {
  function __construct() {
      register_activation_hook( __FILE__, array($this, 'activate') );
      register_deactivation_hook( __FILE__, array($this, 'deactivate') );
      add_action( 'pre_get_posts', array($this, 'pre_get_posts') );
  }
  function activate() {
    add_action( 'generate_rewrite_rules', array($this, 'add_rewrite_rules') );
    global $wp_rewrite; $wp_rewrite->flush_rules(); // force call to generate_rewrite_rules()
  }
  function deactivate() {
    global $wp_rewrite; $wp_rewrite->flush_rules();
  }
  function add_rewrite_rules($wp_rewrite){
    $rules = array(
      'except/category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$'  => 'index.php?except_category_name=$matches[1]&feed=$matches[2]',
      'except/category/(.+?)/(feed|rdf|rss|rss2|atom)/?$'       => 'index.php?except_category_name=$matches[1]&feed=$matches[2]',
      'except/category/(.+?)/page/?([0-9]{1,})/?$'              => 'index.php?except_category_name=$matches[1]&paged=$matches[2]',
      'except/category/(.+?)/?$'                                => 'index.php?except_category_name=$matches[1]',
      );
    $wp_rewrite->rules = $rules + (array)$wp_rewrite->rules;
  }
  function pre_get_posts( $query ) {
      if ( ! is_admin() && $query->is_main_query() && $query->get( 'except_category_name' ) ) { // check if user asked for a non-admin page and that query contains except_category_name var
          $category = get_category_by_slug( $query->get( 'except_category_name' ) ); // get the category object
          $query->set( 'cat', '-' . $category->term_id ); // set the condition - everything except that category
          $query->is_home = FALSE; // Tell WordPress we are not at home page
      }
  }
}
$Except = new Except();

试着输入一些真实的分类名称 http://wp.example.com/except/category/news/

噢!似乎没有效。

这是为什么呢?

问题在于$query->get( ‘except_category_name’ )。WordPress的确把你的请求转换成了index.php?except_category_name=news,但是它并没有把值从查询字符串(query string)中提取出来。它只提取你明确要求的变量。这可以说是整个过程中最愚蠢的事。很显然,如果定义了一个重写规则some_var = some_value,那么我肯定是要获取some_value。不然我定义他干啥?我不知道为什么WordPress的开发者决定用其他方法,为什么要增加额外的步骤使事情变复杂。

(译者注)个人不同的看法:作者此处是从$query对象里来获取except_category_name的值的,但是默认的,WordPress只会将预留的querystring关键变量加载到$query里,列表如下Query Vars,而自定义的变量是无法从$query里获取到值的,因此需要手动注册该变量。如果不注册的话,可以从$_GET全局数组获取到值。

步骤 4: 遗漏的步骤 – Query Var

好了,我们可以再来抱怨,但工作终归是工作,我们必须完成它。我们需要更新的数组名叫$public_query_vars

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*
Plugin Name: Except
Plugin URI: http://ruslanbes.com/projects/except
Description: Make urls like http://wp.example.com/except/category/ABCDE/ display all posts except from category ABCDE
Version: 2013.03.26
Author: Ruslan Bes < me@ruslanbes.com >
Author URI: http://ruslanbes.com/devblog
*/
define('EXCEPT_PATH', dirname(__FILE__) .'/');
class Except {
  function __construct() {
      register_activation_hook( __FILE__, array($this, 'activate') );
      register_deactivation_hook( __FILE__, array($this, 'deactivate') );
      add_action( 'pre_get_posts', array($this, 'pre_get_posts') );
      add_filter( 'query_vars', array($this, 'query_vars') );
  }
  function activate() {
    add_action( 'generate_rewrite_rules', array($this, 'add_rewrite_rules') );
    global $wp_rewrite; $wp_rewrite->flush_rules(); // force call to generate_rewrite_rules()
  }
  function deactivate() {
    global $wp_rewrite; $wp_rewrite->flush_rules();
  }
  function add_rewrite_rules($wp_rewrite){
    $rules = array(
      'except/category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$'  => 'index.php?except_category_name=$matches[1]&feed=$matches[2]',
      'except/category/(.+?)/(feed|rdf|rss|rss2|atom)/?$'       => 'index.php?except_category_name=$matches[1]&feed=$matches[2]',
      'except/category/(.+?)/page/?([0-9]{1,})/?$'              => 'index.php?except_category_name=$matches[1]&paged=$matches[2]',
      'except/category/(.+?)/?$'                                => 'index.php?except_category_name=$matches[1]',
      );
    $wp_rewrite->rules = $rules + (array)$wp_rewrite->rules;
  }
  function pre_get_posts( $query ) {
      if ( ! is_admin() && $query->is_main_query() && $query->get( 'except_category_name' ) ) { // check if user asked for a non-admin page and that query contains except_category_name var
          $category = get_category_by_slug( $query->get( 'except_category_name' ) ); // get the category object
          $query->set( 'cat', '-' . $category->term_id ); // set the condition - everything except that category
          $query->is_home = FALSE; // Tell WordPress we are not at home page
      }
  }
  function query_vars($public_query_vars){
    array_push($public_query_vars, 'except_category_name');
    return $public_query_vars;
  }
}
$Except = new Except();

现在,你可以看到它把分类下的文章过滤掉了。但这还没有结束。

步骤 5: 还没完?开玩笑吧

老实说,在我们定义重写规则的那一步中,有点小问题。为了方便描述,想象一下这个场景:你有一个 Except_Category 模块,同时你还有另外一个模块 – Except_Tag ,功能一样,不过对象是标签而不是分类。现在你一个一个的启用他们,那么将会发现下面的事情

20131011000202_90002

第一个启用的模块的规则没有被保存,为什么呢?原因就是当你启用 Except_Tag 模块时,它销毁了$rewrite_rules数组,然后触发动作(action)generate_rewrite_rules。当这个动作被触发时,它发现了模块 Except_Tag 里的hook但是忽略了 Except_Category 里的,因为我们把add_action(‘generate_rewrite_rules’, … )放错了地方。幸运的是如果我们重新思考一下何时添加重写规则,我们便可以轻松的修复它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/*
Plugin Name: Except
Plugin URI: http://ruslanbes.com/projects/except
Description: Make urls like http://wp.example.com/except/category/ABCDE/ display all posts except from category ABCDE
Version: 2013.03.26
Author: Ruslan Bes < me@ruslanbes.com >
Author URI: http://ruslanbes.com/devblog
*/
define('EXCEPT_PATH', dirname(__FILE__) .'/');
class Except {
  function __construct() {
      register_activation_hook( __FILE__, array($this, 'activate') );
      register_deactivation_hook( __FILE__, array($this, 'deactivate') );
      add_action( 'generate_rewrite_rules', array($this, 'add_rewrite_rules') );
      add_action( 'pre_get_posts', array($this, 'pre_get_posts') );
      add_filter( 'query_vars', array($this, 'query_vars') );
  }
  function activate() {
    global $wp_rewrite; $wp_rewrite->flush_rules(); // force call to generate_rewrite_rules()
  }
  function deactivate() {
    remove_action( 'generate_rewrite_rules', array($this, 'add_rewrite_rules') );
    global $wp_rewrite; $wp_rewrite->flush_rules();
  }
  function add_rewrite_rules($wp_rewrite){
    $rules = array(
      'except/category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$'  => 'index.php?except_category_name=$matches[1]&feed=$matches[2]',
      'except/category/(.+?)/(feed|rdf|rss|rss2|atom)/?$'       => 'index.php?except_category_name=$matches[1]&feed=$matches[2]',
      'except/category/(.+?)/page/?([0-9]{1,})/?$'              => 'index.php?except_category_name=$matches[1]&paged=$matches[2]',
      'except/category/(.+?)/?$'                                => 'index.php?except_category_name=$matches[1]',
      );
    $wp_rewrite->rules = $rules + (array)$wp_rewrite->rules;
  }
  function pre_get_posts( $query ) {
      if ( ! is_admin() && $query->is_main_query() && $query->get( 'except_category_name' ) ) { // check if user asked for a non-admin page and that query contains except_category_name var
          $category = get_category_by_slug( $query->get( 'except_category_name' ) ); // get the category object
          $query->set( 'cat', '-' . $category->term_id ); // set the condition - everything except that category
          $query->is_home = FALSE; // Tell WordPress we are not at home page
      }
  }
  function query_vars($public_query_vars){
    array_push($public_query_vars, 'except_category_name');
    return $public_query_vars;
  }
}
$Except = new Except();

现在,所有准备都已就绪。一旦我们启用模块,重写规则就会生成,当然,停用模块时,规则也会被立即删除。

PS:function pre_get_posts( $query ) {

      if ( ! is_admin() && $query->is_main_query() && $query->get( 'except_category_name' ) ) { // check if user asked for a non-admin page and that query contains except_category_name var
          $category = get_category_by_slug( $query->get( 'except_category_name' ) ); // get the category object
          $query->set( 'cat', '-' . $category->term_id ); // set the condition - everything except that category
          $query->is_home = FALSE; // Tell WordPress we are not at home page
      }
  }
这个函数 中$query->set( 'cat', '-' . $category->term_id );可以有对各条件,对应的是sql语句中的  where。可以删改此语句在前台中输出:print_r($wp_query);查看

就这么多。如果你需要代码,你可以从 这里 获取。

发布在Wordpress, 主题, 二次开发, 插件 | 发表评论

查看wordpress当前页面执行SQL语句

wordpress查看当前页面执行的sql语句:$wp_query;可以用print_r()输出,如果为空,可以先 global $wp_query;

发布在Wordpress, 主题, 二次开发, 插件 | 发表评论

zonda 响应多用途 WordPress主题

02_preview.__large_preview

Zonda 响应多用途 WordPress主题

Zonda WordPress主题,是一款企业、作品展示、购物商城模版。特点:响应式布局和Retina 支持,黑白2个版本,宽和窄2个版本,Mega 菜单,Visual Composer 拖拽页面搭建,10+自定义页眉,自定义顶部栏,WooCommerce 2.1+支持,石砌作品和博客布局,导入和导出支持,多个高级幻灯片,自定义页面模版,无限侧边栏,无限颜色,高级主题选项面板,SEO,许多简码,自定 义CSS 和Javascripts支持,提供演示数据和说明文档等。

Zonda WordPress主题演示地址:

演示地址

Zonda WordPress主题演示地址:

下载地址   提取码:otpn

需要调试的朋友联系QQ:245887385

发布在主题 | 发表评论

Roundcube 简单插件开发教程

插件对于Roundcube是非常是用的一个功能。 他们虽然不是软件的核心部分,但却可以独立的安装并启用. Roundcube自带了一些插件, 并且有非常多的第三方插件提供下载.
下载并安装插件

先下载插件,并解压至网站根目录/plugins下,但是做完这些插件还并不能工作,想要插件工作,还需要启用插件,需要打开config/main.inc.php,找到$rcmail_config['plugins'] = array();在数组中填写插件名称就完成插件安装。

如:等等安装的插件为 additional_message_headers:只要$rcmail_config['plugins'] = array(‘additional_message_headers’, ‘archive’);

如果需要关闭插件,只要把插件名称从数组中移除即可

下面介绍一下插件的目录结构,如果你的插件名称为:fancy_emoticons,那么你的目录结构最简单的只需要一下几个就可以了:

plugins/
fancy_emoticons/
fancy_emoticons.php

然后只要编辑fancy_emoticons.php就可以了,编辑fancy_emoticons.php,首先新建一个跟插件名称一样的一个类,并且必须是继承rcube_plugin,如下:

/**
* Fancy Emoticons
*
* Sample plugin to replace emoticons in plain text message body with real icons
*
* @version 1.0
* @author Thomas Bruederli
* @url http://roundcube.net/plugins/fancy_emoticons
*/
class fancy_emoticons extends rcube_plugin
{
public $task = ‘mail’;
private $map;

function init()
{
$this->add_hook(‘message_part_after’, array($this, ‘replace’));

$this->map = array(
‘:)’  => html::img(array(‘src’ => $this->urlbase.’media/smile.gif’, ‘alt’ => ‘:)’)),
‘:-)’ => html::img(array(‘src’ => $this->urlbase.’media/smile.gif’, ‘alt’ => ‘:-)’)),
‘:(‘  => html::img(array(‘src’ => $this->urlbase.’media/cry.gif’, ‘alt’ => ‘:(‘)),
‘:-(‘ => html::img(array(‘src’ => $this->urlbase.’media/cry.gif’, ‘alt’ => ‘:-(‘)),
);
}

function replace($args)
{
if ($args['type'] == ‘plain’)
return array(‘body’ => strtr($args['body'], $this->map));

return null;
}
}

完成以上代码一个基本的插件就完成了

发布在Roundcube, 二次开发, 插件 | 已有标签 , | 发表评论

[免费] WordPress 防注册垃圾账号外挂 – Pie Register

Pie Register是一个防止注册垃圾账号的非常有效的插件,他会在会员注册成功之后自动发送邮件大注册邮箱,并且要求会员在规定时间之内完成验证,如果在规定时间内没完成验证的话,Pie Register会自动删除掉该账号。废话不多说,下面来看看他的强大功能吧!!

首先下载Pie Register(下载),安装并启用之后,在菜单栏中会看到如下图:

1

1、Form Editor

这个菜单主要是设置注册页面字段的

2、General Settings

这个菜单是比较重要的,这里面可以自定义登录页面、注册页面、忘记密码页面、个人资料页面、登录后跳转页面…  最重要的是会自动发送激活邮件注册邮箱,并且可以设置疑惑链接有效期,如下如:2
3、Payment Gateway

支付选项,目前只支持Paypal
4、Admin Notifications

会员注册后自动发送邮件(含激活链接)
5、User Notifications

定义邮件发送条件
6、Export/Import


7、Invitation Codes


8、Help

PS:楼主所使用的Pie Register版本为 2.0.7,其他版本设置选项可能略有不同,如有疑问请咨询楼主,QQ:245887385(免费喔)

发布在Wordpress, 插件 | 已有标签 , | 发表评论

利用Advanced Custom Fields + qTranslate实现wordpress自定义字段多语言

要实wordpress自定义字段多语言,首先要准备3个插件:1、Advanced Custom Fields(点此下载);2、qTranslate(点此下载);3、Advanced Custom Fields: qTranslate(点此下载);将此三个插件上传到插件目录并启用。

1

首先点箭头所指的语言开启网站所需要的语言,然后点击“字段”     “新建”如图:

2

出现新建字段页面,如下图:

3

再点击 添加字段,出现添加字段页面,如下图:

4

在字段类型下拉宽中选择qTranslate下面的内容点保存就可以了

 

PS:下载qTranslate时要注意wordpress与qTranslate之间版本的对应关系,不对应的话,会出现qTranslate不兼容的情况,查看对应关系表,请点击:http://www.qianqin.de/qtranslate/download/

发布在Wordpress, 二次开发 | 已有标签 , , , | 发表评论

TB Mozanis 自适应购物商城 Drupal 7 主题

TB Mozanis 自适应购物商城 Drupal 7 主题

TB Mozanis Drupal 7 主题,一个自适应购物商城 Drupal 7 主题。The responsive ecommerce Drupal theme supports Drupal Commerce module and along with other significant modules: Superfish, Views Slideshow, ShareThis and Taxonomy menu. Come with 4 colors of choice, responsive design, 14 supported regions and neat typography, TB Mozanis is well-equipped with all the features of an ecommerce theme.

TB Mozanis Drupal 7 主题特点:

  • Shopping cart
  • Responsive design
  • Quicktabs
  • custom 404
  • Quickstart package

TB Mozanis Drupal 7 主题演示地址:

http://demo.themebrain.com/tb_mozanis/

TB-Mozanis-540x252

有需要的朋友可以联系我,QQ:245887385

发布在Drupal, 主题 | 已有标签 , , | 3 个回复或互链