用 rst2wp 来写 WordPress

很久没有写 Blog 了,没想到一下子拉了这么长时间。 想想最初停止的原因,是因为在看到 reStructuredText 之后, 觉得用来写文章、文档或者 Blog 非常好,就想学着用用。 谁知 rst 太复杂了,光 说明文档 就那么长, 也没有完整的中文版,就想来翻译一下,翻译的结果还是用 rst 来写。 结果卡死在这里了,后来忙了就没有再继续了, Blog 也就没有再更新,翻译也没有进行完。

现在,随着一切在发展,似乎 WordPress 有些没落了, 原来的 rst 支持插件居然也几乎没有了。 大家都热衷于使用 Jekyll, Octopress, Pelican 类似的软件来生成静态 Blog, 摈弃了以前 PHP+Mysql 的动态网站方式, github 还提供配套的 托管服务 。 我不喜欢全静态化的实现方式,网站大了以后更新效率肯定会降低, 好在这些生成工具大多都支持 MarkdownreStructuredText , 继续使用 rst 来写 Blog 也不会太影响将来可能的迁移。

继续 Blog 吧,懒人又开始面临一个不是问题的问题:网络不好,连接速度慢, 直接登录 WordPress 后台写简直太痛苦了。 所以有一段时间我都是在本地编辑,然后粘贴到后台看效果。 这种方式在 rst 在线预览工具 的帮助下还算凑合 (原来有个 rst2a 也挺好用,但已经挂了很久了)。 看过一些 Blog 客户端软件,感觉大多仍然不理想,功能不足, WordPress 推荐工具 多半也不好用, 很多都很长时间没更新了。 于是,继续搜索,找到了现在用的 rst2wp

rst2wp 的工作方式是在本地用任何你喜欢的编辑器写 rst 文档, rst2wp 帮你转换成 html、预览或者上传到 WordPress 中。 rst 文件中可以指定 Category 和 Tag, 上传时会自动记录 Post Id 用于以后的编辑。 我 Fork 之后还增加了记录 date 和 slug 的功能。 一个比较完整的 rst 文档示例如下:

..  -*- mode: rst -*-
..  -*- coding: utf-8 -*-
 
:id: 6
:title: 用 rst2wp 来写 WordPress
:slug: 201211-test-rst2wp
:date: 2012-11-27 00:19:37
:publish: yes
:categories:
    - Blog
    - Tools
:tags:
    - blog
    - git
    - github
    - WordPress
    - RestructuredText
 
 
blah 测试 中文。
 
+---+---+---+
| a | b | c |
+===+===+===+
| 1 | 2 | 3 |
+---+---+---+

先用着吧,顺便熟悉 reStructuredText 的语法。

WordPress 烦人的 revision 和 auto-draft

revision 是早就有了,auto-draft 是最近才发现的,个人非常不喜欢这2个功能,偏偏 WordPress 还没有在后台中增加显式的关闭功能,所以更显得烦人。

revision 是你每保存一次 post 的时候,都把修改前的内容存成一个 revision,这样你就不用担心以前的版本找不到了。问题是,写 blog 又不是写代码,用得着这把牛刀么?就是写代码,也有不想保存的版本,基本上扔到 scm 里面就不会再看了呀。

禁用 revision 的方法,对目前的 WordPress 3.0 有效,在 wp-config.php 中添加:

define('WP_POST_REVISIONS', false);
define('AUTOSAVE_INTERVAL', 60000);

同时也禁止了自动保存,多手工保存吧,或者本地写好了再 post 。

auto-draft 是这样出现的,当你 new 一个 post 的时候,以前是第一次保存的时候生成 id,现在则是打开 new 页面的时候就生成了,体现在数据库中 wp_posts.post_statusauto-draft。这种没有内容先保存的方法一般是用来避免多人同时保存时的写入数据冲突,可一般的 blog 会频繁产生这种情况么?更糟糕的是,auto-draft 类型的post 无法在 Posts 管理中进行编辑,也就是说如果你打开了 new post 页面,输入了一些内容,然后没有保存或者发布就离开了这个页面,那么数据库中就多了一条 auto-draft “僵尸记录”,你再也找不到它了。

auto-draft 目前好像没有方法关闭,但可以从数据库中把他们更改为 draft,以后当草稿修改成新文章就是了:

mysql> SELECT DISTINCT post_status, COUNT(1) FROM wp_posts GROUP BY post_status;
mysql> UPDATE wp_posts SET post_status='draft' WHERE post_status='auto-draft';

最后,贡献一个 php 脚本,自动把 revision 和 auto-draft 都修改成草稿 draft,并且找出数据库中不连续的 post id,把他们也都存成草稿,这样可以保持 url 中 id 的连续性,似乎更加美观和整洁。未经严格测试,请参考使用:

HTTP–>HTTPS

我无法愤怒,因为不知道该生谁的气。

几天前,网站突然无法访问了,没有响应(不是reset),一开始还以为事网络的问题,后来发现不是,用其他国外主机作跳板可以正常访问,也就是说,在出国的网络出口被DROP了。

我和我们合租的邻居们不会有什么过激的言论,也没有什么PORN的内容,咋就这样了呢。没有客服,原因也没法找了,只能先恢复访问,向MT提交了support request,很快(33分钟后)就得到了的IP,应用在主机上,谁知才2天,又完蛋了。

现在要了第3个IP(这次的响应速度更快,12分钟),同时准备把所有http访问重定向到https访问,算是有些强制吧,弄了个脚本定时执行。没办法,没有别的招数,如果再被封,我也回天无术了。

使用https方式访问网站,速度上没有太大的影响(会有一点点的,服务端加密和客户端解密要耗时),关键事客户端会弹出一个非信任证书的提示,接受或者同意或者永久同意即可,FF3会出一个提示页,上面也有按钮可以添加证书为永久信任证书。如果我们每个域名都单独购买证书的话也不是不可以,不过费用不菲。

http到https的导向其实很容易,用rewrite:

RewriteCond %{HTTPS} !on [NC]
RewriteRule (.*) https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]

为了使用方便,专门搞了个小脚本,在每个网站的根下添加.htaccess文件,在所有子目录现有的.htaccess文件中添加/更新这段内容。

和wordpress配合使用的时候,遇到了一些麻烦,浪费了我2天2夜的时间,也许还浪费了1个IP,如果早弄好也许第2个IP就不会出事了。这个问题就是,rewrite后重定向到https又会被重定向回http,把rewriterule仔细得看过来看过去也没找到错误,后来发现问题在wordpress上,只要在设置中把2个网站地址更改为https开头就行了。原先的转向死循环就是因为rewriterule把http转向到了https,然后wordpress发现访问地址和网站地址不一样,又给转向回了http。

如果无法进入wordpress的管理界面,也可以直接更改数据库,表wp_options中,option_name为siteurl和home这两项,option_id分别是1和46。

再次赞 (MT)的服务,鄙视国内的网络侦探。

参考

好像其他人也有类似遭遇

Update @ 2008-06-26

取消了强制https,原因一来感觉https消耗的资源和影响的速度比预想中的要多,二来强制也只是相对的,有点知识的就能够绕开,三来没有证书(即使购买了证书也不可能所有域名合用),麻烦多多,FF里有吓人的警告,IE下要狂点确认,很多工具也不支持https,四来取消了强制并不代表https不可用,革命靠自觉,感觉有危险的时候用户自己就知道用https了。

升级WP旧模板,让它支持Widgets

正如大家所见,我使用的WordPress模板已经是很旧很旧的了,是以前在WordPress 1.5还是1.0系列的默认模板之上,简单修改而来的。没有选用三栏布局,因为我喜欢用稍微大一点的字体,三栏布局对我来说侧边栏东西太多,加上文章长了以后侧边栏的下面空白很大。不过旧模板自然也就没有Widgets:

No Sidebars Defined

You are seeing this message because the theme you are currently using isn’t widget-aware, meaning that it has no sidebars that you are able to change. For information on making your theme widget-aware, please follow these instructions.

刚开始我还能忍受,Sidebar上没有的东西俺自己手工加上,不过用上Simple Tags插件之后,感叹到了插件和Tags的强大,Relate Post很方便,可Relate Tags就是出不来,探查一番,原因应该就是我的模板不支持Widgets。所以忍不住了,模板可以不变样,但不能不升级,我就动手把它改成支持Widgets的吧。

刚才的提示中已经给出了修改指引的链接,首先把模板中的Sidebar改成ul形式的,Theme Editor -> Sidebar (sidebar.php),第一行的ul换成div即可:

<ul id="sidebar">
......中间的很多内容
</ul>

看了一下,对外观没有太大影响,css应该是用id来引用的,不过还是需要调整一点css:

/* 启用Widgets后Sidebar样式有些变化,在这里修正 */
#sidebar {list-style: none;}
#sidebar li ul li:before {
    content: "\00BB \0020";
}
#sidebar li ul li {
    margin-bottom: 5px;
}

然后还是修改Sidebar模板文件,加入是否有动态Sidebar的检查、如果有就调入的PHP代码:

<ul id="sidebar">
<?php if ( !function_exists('dynamic_sidebar')
    || !dynamic_sidebar() ) : ?>
......中间的很多内容
<?php endif; ?>
</ul>

代码一共就3行,前面加2行,后面加一行,就是个简单的判断而已。别着急,现在还没有完成,还有最后一步。

在模板目录下,比如我的就是wp-content/themes/fwolfs-blog这个目录,创建一个新文件functions.php,内容就4行:

<?php
if ( function_exists('register_sidebar') )
    register_sidebar();
?>

好了,现在再刷新Design -> Widgets页面,就有内容了,我的旧模板现在也支持Widgets了。

同样的,Design -> Theme Editor页面中也会多一项可编辑内容:

Theme Functions (functions.php)

PS1: 如果要添加多个Sidebar,需要模板的支持,也就是模板中制定需要几个Sidebar,在Design中就能管理几个(register_sidebars(n),n就是Sidebar数量)。

PS2: 如果想在Widgets的Text里面内嵌php代码,比如设定只有首页才显示BlogRoll,那么需要安装PHP Code Widget插件,并使用PHP Code代码块。直接在原来的Text中写php代码的话,会原封不动的被当成php代码输出,昏死。

PS3: 一切都折腾好了,Relate Tags功能还是得手工添加php代码块到Widgets中:

<?php
if (is_tag()) {
    st_related_tags();
    st_remove_related_tags();
}
?>

WordPress升级后分类乱码的原因及解决

另外一个网站WordPress很久没有升级了,主要是嫌网站太慢,ssh上去操作麻烦,加上主人也很少更新。不过当WordPress Automatic upgrade出现之后这一切都简单多了我只要在页面上点点鼠标就能升级了,顺便还能把WP的文件和数据库打包下载到本地。同时,WP的新版2.5还支持插件的自动升级,以后无论是升级WP还是升级插件,基本上就不用ssh了。

WordPress Automatic upgrade的安装和WP的升级基本顺利,不过中间执行完upgrade.php升级数据库后,返回wpau有一个错误,没什么提示信息,直接retry后说升级不成功,清除结果再次运行就没问题了。

升级成功之后,blog标题成了??问号,我知道这是字符集的问题,看了看wp-include/wp-db.php中已经可以自动识别字符集(原来都是自己hack这个文件),就在wp-config.php中添加了两句配置:

define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');

乱码问题解决。以为这就没什么事,又分类的名称怎么都成了“??”了,到分类管理里面一看还是问号,编辑修改成中文保存后依然是问号,如果改成英文的就没事了,其它的内容比如文章什么的中文都正常,怎么回事呢?

左思右想,觉得还是和升级时候的那个错误有关,我是从比较旧版本的WP升级过来的,以前是通过hack wp-include/wp-db.php文件设置数据库用utf8编码连接,升级过程中这个文件被新版文件覆盖了,而wp-config.php中添加相应设置之前有一个空档,而升级数据库恰恰是在这个空档时进行的。WP 2.3添加了tag功能,后来查看分类的数据表发现分类和tag是保存在一起的,所以可以确认这些被修改了的数据表在创建时,程序并不是使用utf8编码连接的数据库服务器,而是默认的latin1_swedish_ci字符集。在这样字符集的数据表中,自然是无法保存中文的,所以原来的中文、新输入的中文就都变成了问号。

解决方法有些麻烦,因为没有用phpMyAdmin,都是直接编辑好sql命令在mysql中执行的,好在涉及到的表不多:

  • wp_term_relationships
  • wp_term_taxonomy
  • wp_terms
  • wpau_active_plugins_info
  • wpau_upgrade_log

修改表的字符集语法如下:

ALTER TABLE [table_name]  DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

这还没完,还得把每个表中的字符型字段的编码转换过来,这个就略微多一点了:

# 查看表中各列的详细情况,包括字符集:
show full columns from wp_term_relationships;

# 更改列的字符集或类型、长度
alter table  wp_term_taxonomy change taxonomy taxonomy varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table  wp_term_taxonomy change description description longtext CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;

alter table  wp_terms change name name varchar(55) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table  wp_terms change slug slug varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;

alter table  wpau_active_plugins_info change plugin_name plugin_name varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table  wpau_active_plugins_info change plugin_status plugin_status varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;

alter table wpau_upgrade_log change task_name task_name varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table wpau_upgrade_log change task_status task_status varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table wpau_upgrade_log change task_description task_description varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table wpau_upgrade_log change task_log task_log text CHARACTER SET utf8 COLLATE utf8_general_ci NULL;

其实wpau的两个表不用改的,老外设计的程序一般不会写中文进去,改过来只是好看一些。

另外WP 2.5把slug弄没了很不舒服,虽然现在我只用id作permanent link,但还是原意有个整齐一点的slug更好看,所以用上了slugshow插件,希望WP啥时候把那个貌似智能其实很傻的功能改过来。

Update @ 2008-04-05

差点忘记了还有一个css裸奔节,顺便贴一下我blog首页穿衣服和不穿衣服的样子,首先是穿衣服的:

Free Image Hosting at www.ImageShack.us

然后是不穿衣服的:

Free Image Hosting at www.ImageShack.us

我的脱衣脚本还是很好用的嘛。

WordPress升级到2.3.1

以前用的是2.2版本,现在最新版是2.3.1,我看重的主要改进是添加了tag的支持,就升过来了。

升级过程非常简单,下载包,解压,覆盖,然后执行一下wp-admin/upgrade.php就可以了。

忘记了WordPress从哪个版本开始支持Widgets功能的,可我用的这个模板是从1.5版本的默认主题,一路改过来的,虽然没有动大手术,琐碎的修改还是有一些的。对于我这个懒人来说,重新套模板然后更改显然是不划算的,虽然后来学聪明了,有些修改作成了插件,剩下的好像也不少,所以尽可能的在旧模板的基础上更改。

Widgets好像就是个可高度自定义的sidebar,在我现在的模板中,打开Widgets页面总是提示“No Sidebars Defined”,不支持,好在我的要求也不高,咱自己动手,丰衣足食。

WordPress的wp-includes/widgets.php这个文件,是Widgets的主要实现代码,所以修改主要是参照了这个文件的内容。好了,开始编辑现在这个旧模板的sidebar文件。

首先,要把存档archive改成下拉列表框,月份多了实在看着不舒服,widgets.php中有这么一段:

function wp_widget_archives($args) {
    extract($args);
    $options = get_option('widget_archives');
    $c = $options['count'] ? '1' : '0';
    $d = $options['dropdown'] ? '1' : '0';
    $title = empty($options['title']) ? __('Archives') : $options['title'];

    echo $before_widget;
    echo $before_title . $title . $after_title;

    if($d) {
?>
        <select name="archive-dropdown" onchange='document.location.href=this.options[this.selectedIndex].value;'> <option value=""><?php echo attribute_escape(__('Select Month')); ?></option> <?php wp_get_archives("type=monthly&format=option&show_post_count=$c"); ?> </select>

可以看出,内置的wp_get_archives函数的参数,原来只有type=monthly,现在多了format=optionshow_post_count=$c,前者应该代表是否下拉列表框形式显示,值的定义为$options['dropdown'];后者是是否显示本月文章计数,值的定义为$options['count'],并且都是用1代表真,0代表假,所以修改就简单了,把原来的:

<?php wp_get_archives('type=monthly'); ?>

更改为:

        <select name="archive-dropdown" onchange='document.location.href=this.options[this.selectedIndex].value;'> <option value=""><?php echo attribute_escape(__('Select Month')); ?></option> <?php wp_get_archives("type=monthly&format=option&show_post_count=1"); ?> </select>

就行了。

然后,把archive月份存档和category分类列表的位置互换,分类列表放在上面,直接调整代码顺序即可,同时给分类列表也加上分类计数的显示:

            <li><h2>Categories</h2>
                <ul>
                <?php wp_list_cats('sort_column=name&show_count=1'); ?>
                </ul>
            </li>

最后,添加Tag Cloud,没有这个升级就白作了,参照widgets.php中的:

function wp_widget_tag_cloud($args) {
    extract($args);
    $options = get_option('widget_tag_cloud');
    $title = empty($options['title']) ? __('Tags') : $options['title'];

    echo $before_widget;
    echo $before_title . $title . $after_title;
    wp_tag_cloud();
    echo $after_widget;
}

没什么太复杂的,直接调用wp_tag_cloud()函数,连参数都没有,最终代码为:

            <li><h2>Tags Cloud</h2>
                <ul>
                <?php wp_tag_cloud(); ?>
                </ul>
            </li>

这样就大功告成了,虽然模板不支持Widgets,侧边栏倒也符合我的基本使用需要了。

参考