Symfony 模板系统

Template的逻辑命名和Controller的类似,模板的逻辑名称遵循这样的约定:

BundleName:ControllerName:TemplateName

一般会被映射会这样的物理地址:

  1. app/Resources/{BundleName}/views/ControllerName/TemplateName
  2. {path/to/BundleName/}Resources/views/ControllerName/TemplateName

当第1个地址找不到对应的模板时,会继续查找第2个位置的模板。

Template Services

Symfony模板系统的核心是模板引擎(服务),

从控制器渲染模板:

1
return $this->render('article/index.html.twig');

与直接使用服务是等价的:

1
2
3
4
use Symfony\Component\HttpFoundation\Response;
$engine=$this->container->get('templating');
$content=$engine->render('article/index.html.twig');
$return $response=new Response($content);

Symfony的模板引擎可以在app/config/config.yml中配置:

1
2
3
framework: 
#...
templating: { engines: ['twig']}

Twig模板

Twig模板的语法和Django模板语法非常相似。Twig提供了三种语法:

  1. says sth

    1
    {{ ... }}
  2. does sth

    1
    2
    // does sth
    {% ... %}
  3. comment sth

    1
    2

    {# ... #}

Twig链接:

1
2
3
<a href="{{ path(routeName,context) }} " > home </a>
<img src="{{ assets(images/logo.png) }}"/>
<link href="{{ assets(css/blog.css) }}" rel='stylesheet' type='text/css' />

Twig filters:

1
{{ title|upper }}

Twig模板嵌入

为了代码复用,Twig提供了include:

1
{% include() %}

Twig模板继承与重载:

1
2
3
4
5
6
{% extends 'baseTemplateName' %}

{% block XX %}
{{ parent() }}
{# overwrite here #}
{% endblock %}

一种常用的模板继承是三层方案。

  1. 为整个网站创建基础模板app/Resources/views/base.html.twig
  2. 为某一类特定功能创建模板spec/layout.html.twig(继承自第1层模板)
  3. 为每一个单独的页面创建模板 (继承自第2层模板)

Twig模板嵌入其他控制器

此外,还可以嵌入其他控制器的渲染结果

1
{{ render(Controller("LogicalContrllerName",context)) }}

配合hinclude.js,还可以实现异步加载:

1
2
{{ render_hinclude(controller('...')) }}
{{ render_hinclude(url('...')) }}

Twig Template转义

twig系统自带转义,如需原始输出,可以利用raw 过滤函数

1
{{ article|raw  }}

PHP模板,可以使用

1
<?php echo $view->escape($name)?>

进行转义。

Twig Macro

Twig Macro是非常强大的HTML代码复用手段,它的功能非常类似于C语言的宏:

1
2
3
{% macro input(name, value = "", type = "text", size = 20) %}
<input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />
{% endmacro %}

Twig Macro可以在其他单独的文件中定义,然后导入到当前的模板文件中:

1
2
3
4
5
6
7
{# 导入整个宏定义文件 #}
{% import "forms.html" as forms %}
{{ forms.input('username') }}

{# 从宏文件中导入某个单独的Macro #}
{% from 'forms.html' import input as input_field %}
{{ input_field('username') }}

Twig Use Statement

Twig的模板继承只支持单继承,Twig还提供了use以帮助我们实现更大程度的代码复用。

use语句告诉Twig去把在某个文件中定义的block块导入到当前模板中。

1
{% use "blocks.html" %}

这一功能类似于对于Macro的import语句,但是use只对block块有效,而且,想use的模板必须满足

  1. 不extends其他模板。
  2. 不定义宏
  3. body为空

和针对Macros的import类似,use也支持了导入一部分代码段的功能,同时还提供别名机制来避免命名冲突:

1
2
3
4
5
6
7
{% extends "base.html" %}

{% use "blocks.html" with sidebar as base_sidebar, title as base_title %}

{% block sidebar %}{% endblock %}
{% block title %}{% endblock %}
{% block content %}{% endblock %}

Template的全局变量

不管是Twig模板,还是纯PHP模板,Symfony都为之提供了一个变量app

  • app.security #deprecated since 2.6
  • app.user
  • app.request
  • app.session
  • app.environment
  • app.debug

WordPress 前台基础架构分析之二:查询篇

WordPress查询过程

WordPress查询过程也即wp()函数的调用过程, 该函数定义于wp-includes/functions.php文件中:

1
2
3
4
5
6
7
8
9
//wp-includes/functions.php

function wp( $query_vars = '' ) {
global $wp, $wp_query, $wp_the_query;
$wp->main( $query_vars );

if ( !isset($wp_the_query) )
$wp_the_query = $wp_query;
}

这里涉及到三个全局类对象,$wp,$wp_query,$wp_the_query,均定义于wp-settings.php中,其中:

  1. $wp则是的WP类(文件wp-includes/class-wp.php)的实例,表示当前请求的WordPress博客环境信息
  2. $wp_the_querywp_queryWP_Query类(文件wp-includes/class-wp.php)实例,用于查询(其实是后者是对前者的引用)

WP

$wp有如下关键的属性和方法

  • 属性
    • $query_vars$query_string: 如m,p,posts,w,cat,s,exact,page,more,orderby,tag等等
    • $request : Permalink或者request URI
    • $matched_rule$matched_query : 重写匹配到的请求
  • 方法
    • main($query_vars=''): 设置所有的变量到该环境类对象,该方法实际上只是调用这些方法
      • init(); #初始化
      • parse_request($query_args); #解析请求
      • send_headers(); #发送响应头
      • query_posts(); #执行查询
      • handle_404(); #处理404
      • register_globals(); #注册全局变量

最值得关注的是这个$wp->query_posts()方法,其实调用的是在文件settings.php中定义的全局对象$wp_the_query进行调用

1
2
3
4
5
public function query_posts() {
global $wp_the_query;
$this->build_query_string();
$wp_the_query->query($this->query_vars); #调用WP_Query类对象的查询方法
}

WP_Query

WP_Query的作用

除了直接使用$wpdb调用相关的模型层方法,WordPress针对自身的数据库schema和常用功能设计了WP_Query类,该类位于WPINC/query.php文件中。

该类的构造器接受一个query_string的查询字符串或者对应的数组作为参数,返回一个WP_Query类对象,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$posts=new WP_Query(array(
'showposts'=>10,
'offset'=>0,
'category'=>0,
'orderby'=>'post_date',
'order'=>'desc',
'include'=>'',
'exclude'=>'',
'meta_key'=>'',
'meta_value'=>'',
'post_type'=>'post',
'suppress_filters'=>true,
'post_status'=>'publish'
));

当这个$wp_query对象执行查询后,一系列相应的属性会被重新设置。根据这些属性值,Loop过程会加载不同的模板。

比如,如果$wp_query->is_search()属性值被设置为真,WordPress会使用search.php模板(如果有的话)。

WP_Query的属性和方法

该类提供了一系列初始的属性和方法:

  • 属性
    • $query #保存了wp_parse_args($queryString)的返回值;
    • $query_vars #$query的关联数组
    • $queried_object #保存了请求的category,author,post 或page的信息
    • $queried_object_id
    • posts #get_posts()返回值,表示请求的posts
    • post_count #get_posts()返回的posts的数量
    • current_post #用于迭代,将要被显示的post的index
    • post #用于迭代,当前被显示的post
    • is_xxx #query flags 属性
  • 方法
    • init() #初始化并设置默认值
    • parse_query() #解析query string或者相应数组,并设置query type booleans
    • parse_query_vars() #这个函数只是重新调用parse_query()
    • get_posts() #从数据库中获取请求的posts,并生成$posts$post_count
    • query() #调用parse_query()get_posts()
    • rewind_posts() #rewind
    • have_posts() #是否有posts
    • next_post() #在$posts中迭代倒下一个位置,递增$current_post,设置$post
    • the_post() #迭代到下一个位置,并且设置全局$global变量
    • get_queried_object()
    • get_queried_object_id()
    • get()
    • set()
    • is_xxx()

值得注意的是,query()方法是这里的核心方法,它负责两大业务:

  1. 是解析查询参数(并设置相应的属性值)
  2. 是根据解析参数值进行数据库查询(并设置相应属性)

实际上只是调用:

  1. parse_query()
  2. get_posts()

当执行完查询之后,常用的可用属性包括:

  • order
  • orderby #author|date|title|modified|menu_order|parent|ID|rand|meta_value| none
  • cat,tag
  • category_name
  • categroy__and,tag__and #数组
  • category__in,tag__in #数组
  • category__not_in
  • tag_slug__and
  • tag_slug__in
  • showposts
  • p
  • name
  • page_id
  • pagename
  • post__in
  • post__not_in
  • post__type
  • post_status
  • author
  • author_name
  • hour
  • minute
  • second
  • day
  • monthnum
  • year
  • w
  • paged
  • offset
  • meta_key
  • meta_compare

WordPress 前台基础架构分析之四:总览

核心函数基本构成

WordPress核心文件包含了绝大部分WordPress流行函数,均位于wp-includes/文件夹下。

  • functions.php # main API
  • options.php # Options API
  • plugin.php # Plugin API
  • User.php # User API
  • Post.php # Post API
  • Taxnonmy.php # Taxnonmy API
  • formatting.php # Formatting Functions
  • pluggable.php # 可覆盖的API
  • ..,

这些众多的文件定义了众多API,常见的有:

  • Plugin API
  • Widgets API
  • Shortcode API
  • HTTP API # 发送HTTP请求
  • Settings API
  • Options API
  • Dashboard Widgets API
  • Rewrite API

再看Loop时的全局变量

前文已经说到,WordPress的博客功能其实就是再做三件事:

  1. 加载必要的文件
  2. 根据条件查询数据库,然后保存到全局对象或者全局对象中。
  3. 根据查询后的结果,选择加载合适的模板。

Loop时设置的关键的全局变量有:

  • Post Dtata : $post
  • Author Data : $autordata
  • User Data : $current_user
  • Environment Data: 环境变量
    • 客户端:$is_IE,$is_iphone,$is_mobile,…
    • 服务端: $is_apache,$is_IIS

WordPress定义的Template Tag 会根据全局变量的不同,给出相应的值(或者默认值)。

因此,应该优先调用Template Tag而非使用全局对象或者变量。

WordPress Ajax机理分析

后台Ajax源码分析

WordPress Ajax功能的后台相关核心文件为wp-admin/admin-ajax.php

文件wp-admin/admin-ajax.php首先会加载一些基础文件:

  • wp-load.php文件、
  • wp-admin/includes/admin.php文件
  • wp-admin/includes/ajax-actions.php文件

其次wp-admin/admin-ajax.php进入钩子注册阶段:

  • 预定义一系列核心actions名称用于Ajax操作,如fetch-list,delete-post,add-meta,dashboard-widgets,etc.如果客户端传递来的action参数(get或者post传递)在预定义的actions之中,则将客户端传来的action参数中的-转换为_后,冠以wp_ajax_前缀添加到action钩子中。
  • 预定义并注册心跳包钩子wp_ajax_nopriv_heartbeat
  • 除了这些内置的action之外,还可以自定义其他action。当然,自定义的action钩子通常在其他地方注册过了(此处不应再次注册)。

核心代码为:

1
2
3
4
5
6
7
8
9
10
// wp-admin/admin-ajax.php 文件
###@:注册核心ajax钩子
if ( ! empty( $_GET['action'] ) && in_array( $_GET['action'], $core_actions_get ) )
add_action( 'wp_ajax_' . $_GET['action'], 'wp_ajax_' . str_replace( '-', '_', $_GET['action'] ), 1 );

if ( ! empty( $_POST['action'] ) && in_array( $_POST['action'], $core_actions_post ) )
add_action( 'wp_ajax_' . $_POST['action'], 'wp_ajax_' . str_replace( '-', '_', $_POST['action'] ), 1 );

### 注册心跳包
add_action( 'wp_ajax_nopriv_heartbeat', 'wp_ajax_nopriv_heartbeat', 1 );

最后进入触发钩子阶段,如果当前用户处于未登陆状态,触发钩子wp_ajax_nopriv_,反之,则触发wp_ajax_钩子。

1
2
3
4
5
6
7
8
9
10

// wp-admin/admin-ajax.php 文件

###@:调用钩子
if ( is_user_logged_in() ) {
do_action( 'wp_ajax_' . $_REQUEST['action'] );
} else {
do_action( 'wp_ajax_nopriv_' . $_REQUEST['action'] );
}
die('0');

注册自定义的Ajax钩子

从以上的wp-admin/admin-ajax.php源码分析可以得知,WordPress的Ajax响应动作是通过钩子实现的,显然用于Ajax响应的callable对象必须提前册成钩子才能被触发。对于内置的核心Ajax动作或者心跳包,WordPress已经替我们写好了相关代码,但是对于自定义的Ajax响应,还需我们自己注册钩子。引自wordPress.org的一个例子:

1
2
3
4
5
6
7
8
9

add_action( 'wp_ajax_my_action', 'my_action_callback' );
function my_action_callback() {
global $wpdb; // this is how you get access to the database
$whatever = intval( $_POST['whatever'] );
$whatever += 10;
echo $whatever;
wp_die(); // this is required to terminate immediately and return a proper response
}

前台调用接口

注册好钩子之后,即可在前端对wp-admin/admin-ajax.php发起Ajax请求了。引自wordPress.org的一个例子:

1
2
3
4
5
6
7
8
9
10
11

jQuery(document).ready(function($) {
var data = {
'action': 'my_action',
'whatever': ajax_object.we_value // We pass php values differently!
};
// We can also pass the url value separately from ajaxurl for front end AJAX implementations
jQuery.post(ajax_object.ajax_url, data, function(response) {
alert('Got this from the server: ' + response);
});
});

WordPress Model Layer

WordPress虽说并不和现代的MVC模式一致,但是也有独立的数据库操作层。

全局对象$wpdb

有一个全局对象$wpdb 作为WPINC/wp-db.php中的wpdb类实例对象。该类是
WordPress Database Access Abstraction

可以用其他的类替换之。

Adding Data

利用$wpdb->insert()方法,此方法接受三个参赛:

  1. 表名
  2. 数组,字段的名和值对组成的数组
  3. 数组,可选的格式
1
2
3
4
5
6
7
8
9
$wpdb->insert(
$wpdb->posts,
array(
'post_title'=>'xx',
'post_content'=>'xx',
'post_type'=>'xx',
),
array("%s",%s","%s")
);

update

利用$wpdb->update()方法,此方法接受5个参数:

  1. 表名
  2. 新记录的数组表示,由各字段的名/值对组成的数组
  3. where条件数组
  4. 数组,每个元素表示新记录中的值的格式
  5. 数组,表示where条件数组的格式
1
2
3
4
5
6
7
8
9
10
11
12
13
$wpdb->update(
$wpdb->posts,
array(
'post_title'=>'new',
'post_content'=>'new',
'post_type'=>'new',
),
array(
'ID'=>$post_id,
),
array("%s","%s"),
array("%s")
);

Delete

$wpdb->delte()方法可以用来删除行记录。 原型为

1
public function delete( $table, $where, $where_format = null )

例如:

1
$wpdb->delete( 'table', array( 'ID' => 1 ), array( '%d' ) );

Retrieving

获取单个值

1
2
3
$post_id=$wpdb->get_var(
"select ID from ".$wpdb->posts." where post_author=1 limit 1"
);

获取一列值

1
2
3
4
$wpdb->get_col(
"select ID from ".$wpdb->posts." where post_author=1 ",
ARRAY_A # NULL|ARRAY_A|ARRAY_N,默认为object格式的返回值,
);

获取一行值

1
2
3
4
$wpdb->get_row(
"select * from ".$wpdb->users." where ID=43;",
ARRAY_N #NULL|ARRAY_A|ARRAY_N
);

获取完整的数据集

1
2
3
4
$wpdb->get_results(
"select * from ".$wpdb->users.a",
ARRAY_N #NULL|ARRAY_A|ARRAY_N
);

执行查询

1
$wpdb->query(string SqlString);

SQL 注入与防御

WordPress 使用$wpdb->prepare()防御SQL注入。此方法使用PHP printf()函数的语法为字段进行代换,
如同printf()那样,这里的占位符也可以使用排序索引。

1
2
3
4
$sanitized_sql=$wpdb->prepare(
"'insert into my_plugin_table set field1=%1$d,$field2=$2$s,$field=%3$s,32',32,'Barzell','Washington,DC'"
);
$wpdb->query($sanitized_sql);

WordPress Template Layer 1

如基础架构中所述,WP的模板加载是通过wp-includes/template-load.php文件来完成的,根据模板等级结构,优先选择级别较低的模板。

在WordPress中,任意一个没有找到对应的模板文件的请求都会被index.php模板处理。

模板文件碎片

为了最大限度上复用模板,WordPress提供了以下默认的模板文件碎片

  • header.php #get_header()
  • sidebar.php #get_sidebar()
  • footer.php #get_footer()
  • comments.php #comments_template(),wp_list_comments()
  • search.php

模板函数和钩子

以下三个钩子包装函数应该在每一套主题中设置:

  • wp_head() #在header.php模板的关闭之前布置钩子
  • wp_footer() #在footer.php模板的关闭之前布置钩子
  • comment_form() #在comments.php模板的关闭之前布置钩子

template tags的原理及其依赖

所谓templte tags,其实就是一些为模板编写的简单PHP函数,定义于

  • wp-includes/
    • template.php
    • category-template.php
    • post-template.php
    • general-template.php

等之类的文件中。这些template tags为定制模板提供了极大的方便:

  • bloginfo() #常用于header、footer中,提供基本信息,如字符集、样式文件路径、模板URL等等

由于查询、渲染是个多步过程,一些template tags的使用是有条件的。例如,可以在Loop中使用的template tags:

  • the_title()
  • the_permalink()
  • the_author()
  • the_author_post_link()
  • the_date()
  • the_time()
  • the_excerpt()
  • the_content()
  • the_category()
  • the_tags()

这些template tags 依赖于the_post()函数在Loop的顶部执行后生成的$post对象,因此这些template tags不可在Loop外使用。

如果想使用类似的功能,可以一个定制的Loop,还可以使用以$postid为参数的get系列 template tag

  • get_the_title($postid)
  • get_the_permalink($postid)
  • get_the_category($postid)
  • get_the_tags($postid)
  • get_post($postid)

get_post()返回$post对象,该对象的属性:

  • post_exerpt
  • post_content

引入JavaScript和CSS

直接在模板中硬编码引入JavaScript容易造成冗余及依赖问题,WordPress提供了以下两个函数确保JavaScript按合适的顺序加载。

  • wp_enqueue_script()
  • wp_print_scripts()

可以在 functions.php 中创建一个函数来负责处理主题中的所有JavaScript脚本

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

function theme_javascript(){
wp_enqueque_script(
'jquery-corners',
'http://example.com/jquery-corners.js',
array('jquery')
);
}


function theme_print_scripts(){

$js=<<<EndOfString
<script type='text/javascript'>
jQuery.noConflict();
jQuery(document).ready(function(){
//...
});
</script>

}


add_action('wp_head','theme_print_scripts');
add_action('wp_enqueue_script','theme_javascript');

WordPress Plugin Administration Screens

菜单页面函数概要

与后台管理菜单相关的函数如下:

通用菜单页面管理函数

  • Menu Pages
    • add_menu_page() # Add a top level menu page
    • remove_menu_page() # Remove a top level menu page
    • add_object_page() # Add a top level menu page at the ‘object’ level
    • add_utility_page() # Add a top level menu page at the ‘utility’ level
  • SubMenu Pages
    • add_submenu_page() # Add a submenu page.
    • remove_submenu_page() # Remove a submenu page

其中,
add_object_page :在object级别增加一个顶级菜单。新菜单会出现在Posts, Media, Links, Pages 和Comments组中。
add_utility_page :在utility级别增加一个顶级菜单。新菜单会出现在Appearance, Plugins, Users, Tools 和Settings组中。

原型为:

1
2
3
4
5
6
7
//三个增加顶级菜单的函数
add_menu_page ( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position );
add_object_page ( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url );
add_utility_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url );

//移除菜单的函数
remove_menu_page( $menu_slug )

除了增加顶级菜单,还增加/移除子菜单:

1
2
3
4
//增加子菜单管理页面
add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function );
//移除子菜单管理页面
remove_submenu_page( $menu_slug, $submenu_slug );

为简化调用,除了直接调用add_submenu_page()外,WordPress还提供了以下函数:

  • add_dashboad_page() # Add submenu page to the Dashboard menu
  • add_posts_page() # Add submenu page to the Comments menu
  • add_media_page() # Add submenu page to the Comments menu
  • add_comments_page() # Add submenu page to the Comments menu
  • add_theme_page() # Add submenu page to the Appearance menu
  • add_plugins_page() # Add submenu page to the Plugins menu
  • add_users_page() # Add submenu page to the Users or Profile menu
  • add_management_page() # Add submenu page to the Tools menu
  • add_options_page() # Add submenu page to the Settings menu.

这些函数可以方便地在相应内置的顶级菜单下添加子菜单页面。如add_options_page()原型为:

1
add_options_page( $page_title, $menu_title, $capability, $menu_slug, $function);

可以在设置菜单下添加相应的子菜单页面。

钩子

根据WordPress官方文档的描述,要创建一个菜单页面,必须要做三件事:

  1. 创建一个用于创建menu的函数。
  2. 创建当这个菜单被点击时的输出(类似菜单被点击时的回调函数)。
  3. 把这个menu创建函数注册到动作型钩子admin_menu上。

对于PHP5.3以上的版本,使用匿名函数可以更清除的表示菜单页面的概念:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

add_action( 'admin_menu', 'my_plugin_menu' );

function my_plugin_menu() {

//在Options下添加子菜单
add_options_page(
'My Plugin Options', // page title
'My Plugin', // menu title
'manage_options', // capability
'my-unique-identifier', // menu slug
function(){ // 当菜单被点击后,调用此函数,输出内容将作为管理界面的右部子界面
if ( !current_user_can( 'manage_options' ) ) {
wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
}
echo '<div class="wrap">';
echo '<p>Here is where the form would go if I actually had options.</p>';
echo '</div>';
}
);

//...

}

WordPress Custom Post Type

WordPress自带了5种Post Type:

  1. Post
  2. Page
  3. Attachment
  4. Revision
  5. Nav Menus

对于一个基本的博客,这些类型足以应付大多数需求。但是当情况复杂后,就需要定制自己的Post Type了。

Custom Post Type

定制的Post Type可能是任何东西,不仅仅是面向公众的内容碎片。比如,可以定制自己的Post Type来跟踪程序中错误。

WordPress提供的Custom Post Type功能使得WP的Post足以模拟任何实体——“The only limitation is your imagination”。

注册定制的Post Type

注册新的Post Type类型可以用以下函数实现:

1
2

register_post_type($post_type,$args_array);

一般都在init时进行注册:

1
2
3
4
5
6
7
8
9
add_action('init',function(){
register_post_type(
'mytesttype',
array(
'labels' => array( 'name' => 'MyTester' ),
'public' => true,
)
);
});

定制Post Type参数

函数register_post_type()的第二个参数提供了众多定制Post Type的选项:

  • public # 前台是否公众可见?默认为false
  • show_ui # 是否创建默认UI?默认为public定义的值
  • publicy_queryable # 前台公共可查?默认为public定义的值
  • exclude_from_search # 从搜索结果中排除?默认为public定义的值
  • show_in_nav_menus # nav menu可见?默认为public定义的值
  • supports # 哪些meta boxes?
    • title
    • editor
    • author
    • thumbnail
    • excerpt
    • comments
    • trackbacks
    • custom-fields
    • page-attributes
    • revision
    • post-formats
  • labels # array,用于各种情况下显示的标签
  • hierarchial # 默认为false
  • has_archive
  • can_export # 可导出?默认为true
  • taxonomies # array
  • menu_position # 默认在评论菜单之后
  • menu_icon # 图标
  • show_in_menu # 是否在admin menu中显示
  • show_in_admin_bar # 是否在admin bar中显示
  • capability_type #
  • capability # an array of custom capabilities ( 改、删、阅、发布)
  • query_var # 查询变量
  • rewrite # 创建permalink

其中,labels 接受一个数组,用于各种情况下,需要显示的标签

  • name # 通用名,常为复数
  • singular_name # 单数形式
  • add_new # Add New submenu item
  • add_new_item # 列表页新建一个Post
  • edit_item
  • new_item
  • view_item
  • all_items
  • menu_name
  • name_admin_bar
  • search_items
  • not_found
  • not_found_in_trash
  • parent_item_colon

Post Type 相关的常用函数

  • get_post_types($args,$output,$operator) # 获取指定条件下的Post Types
  • get_post_type($post) # 获取指定post的Post Type
  • post_type_exists($post_type) # 是否存在指定类型的Post Type
  • add_post_type_support($post_type,$sups) # 增加support
  • remove_post_type_support($post_type,$sups) # 增加support
  • set_post_type($postid,$post_type) # 设置Post Type类型
  • is_post_type_hierarchical('super_duper') # 是否是有等级的

WordPress 前台基础架构分析之一:基本流程

基本流程代码分析

WordPress并没有统一的入口,比如

  • wp-login.php #用于登录
  • wp-admin/index.php #用于后台管理
  • index.php #前台博客功能入口

这里要分析的是WordPress的前台功能基础架构。

前台入口的基本逻辑

前台入口文件index.php非常简单,所做的只是转而去加载WordPress博客头wp-blog-header.php文件。

1
2
3
4
//index.php

/** Loads the WordPress Environment and Template */
require( dirname( __FILE__ ) . '/wp-blog-header.php' );

而这wp-blog-header.php文件所做的事儿则是WordPress博客功能的核心:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

if ( !isset($wp_did_header) ) {
$wp_did_header = true;


#加载所有的必需文件
require_once( dirname(__FILE__) . '/wp-load.php' );


#执行WordPress的查询过程,设置相应全局变量
wp();


#利用模板加载器加载相应的模板
require_once( ABSPATH . WPINC . '/template-loader.php' );
}

综上所述,WordPress博客功能便是做这三件事:

  1. 加载必要的基础文件
  2. 执行查询并设置一些列全局变量,
  3. 加载特定的模板模板输出响应。