个人感觉osc的博客不是很好用,主要是编辑器不是很符合我的习惯,允许上传图片图片太小,而且不少人有自己的博客,只是想给osc上做个文章的备份。 于是我决定写一个插件,实现以下功能:先在Wordpress写好文章,然后在发布文章时自动同步到osc的博客,并且发布一条动弹(可选)。有两种方式:一种是用模拟登录,另一种是使用osc 的open api。模拟登录最大的问题是不稳定,保不准osc哪天改版,模拟登录又要重写,维护非常麻烦. open api 相对而言比较稳定和简单,并且有 详细的文档:但缺点是:
- 调用次数的限制,未经审核的应用2000次(每日?);
- 是未经审核的应用refresh token 时有些问题,需要私信给osc相关人员申请,详情请见: OSC 的open API在刷新token时是不是有问题
- 我详细阅读了open api以后发现跟博客相关的,只有发布接口,并没有编辑,删除的接口,也就是说这个api不是完整的,希望osc的相关工作人员之后能完善一下。
把需求和步骤想清楚了,做起来就不会觉得太复杂了,我分为四个部分:
- 向osc申请一个应用:http://www.oschina.net/openapi/client (略)
- 插件设置页面,比如设置应用id,secret,同步的相关选项,如是否发布到动弹,允许文章前置/后置的插入相关内容等
- osc open api oauth授权,保存用户access token,refresh token等。
- 使用api同步文章到osc,主要调用osc博客接口和动弹接口
首先写插件的基本框架, 我们使用面向对象的写法。
<?php
/*
Plugin Name: OscPress
Plugin URI: https://www.cellmean.com/oscpress
Description: 将Wordprss站点更新文章时, 将内容同步到osc博客和动弹
Version: 1.0
Author: Falcon
Author URI: https://www.cellmean.com
*/
$oscPress = new OscPress();
class OscPress{
/**
* 初始化
*/
public function __construct(){
$this->api_site = 'https://www.oschina.net'; // osc api的基本前缀
$this->dir = __DIR__; // 当前插件的物理地址
$this->state = __CLASS__ . '_state'; // 用于oauth 授权的安全鉴权的参数
$this->callback_url = add_query_arg('callback', 'oscpress', site_url());
}
}
注意:这里的注释部分不要省略,否则wordpress无法识别和发现我们的插件。 我们先完成菜单的设置,先提供appid和appsecret的设置项,使用 wordpress内置的 settings api完成,当然也可以自己使用常规的表单完成,不过要注意安全相关的内容,比如csrf. 代码完成后如下:
<?php
/*
Plugin Name: OscPress
Plugin URI: https://www.cellmean.com/oscpress
Description: Wordprss站点更新文章时, 将内容自动发布到osc博客和动弹
Version: 1.0
Author: Falcon
Author URI: https://www.cellmean.com
*/
$oscPress = new OscPress();
class OscPress{
/**
* 初始化
*/
public function __construct(){
$this->api_site = 'https://www.oschina.net'; // osc api的基本前缀
$this->dir = __DIR__; // 当前插件的物理地址
$this->state = __CLASS__ . '_state'; // 用于oauth 授权的安全鉴权的参数
$this->callback_url = add_query_arg('callback', 'oscpress', site_url());
add_action( 'admin_menu', array( $this,'admin_menu'));
add_action( 'admin_init', array($this,'admin_init') );
}
public function admin_menu() {
add_options_page('OscPress','OscPress','manage_options',"oscpress_admin_settings",array($this,'admin_setting'));
// 添加设置菜单的另一种写法
// add_submenu_page('options-general.php', 'OscPress','OscPress', 10, __FILE__, array($this,'admin_setting'));
}
public function admin_init() {
register_setting( 'oscpress_settings_group', 'oscpress_settings',array($this,'sanitize_callback') );
/*
This creates a “section” of settings.
The first argument is simply a unique id for the section.
The second argument is the title or name of the section (to be output on the page).
The third is a function callback to display the guts of the section itself.
The fourth is a page name. This needs to match the text we gave to the do_settings_sections function call.
*/
add_settings_section('oscpress_settings', 'OscPress设置', array($this,'settings_section_text'), 'oscpress');
/*
The first argument is simply a unique id for the field.
The second is a title for the field.
The third is a function callback, to display the input box.
The fourth is the page name that this is attached to (same as the do_settings_sections function call).
The fifth is the id of the settings section that this goes into (same as the first argument to add_settings_section).
第六个参数是自定义传入回调函数的参数,数组类型
*/
add_settings_field('appid', '应用ID', array($this,'input_text'), 'oscpress', 'oscpress_settings',array(
"field" =>"appid", "label"=>"应用ID","placeholder"=>"请输入应用ID"
));
add_settings_field('appsecret', '应用私钥', array($this,'input_text'), 'oscpress', 'oscpress_settings',array(
"field" =>"appsecret", "label"=>"应用私钥","placeholder"=>"请输入应用私钥"
));
}
public function input_text($arr){
$settings = (array) get_option( 'oscpress_settings' );
$field = $arr['field'];
$value = esc_attr( $settings[$field] );
echo "<label class=\"oscpress_settings\" for=\"{$arr['field']}\"><input type='text' id='{$arr['field']}' name='oscpress_settings[$field]' value='$value' placeholder=\"{$arr['placeholder']}\" /></label>";
}
/**
* 验证和洁净化函数
*/
public function sanitize_callback($inputs){
return $inputs;
}
public function settings_section_text(){
echo "<hr/>";
echo "<em>请填写app id及私钥</em>";
}
public function admin_setting(){
?>
<div class="wrap">
<form action="options.php" method="POST">
<?php settings_fields('oscpress_settings_group'); ?>
<?php do_settings_sections('oscpress'); ?>
<?php submit_button(); ?>
</form>
</div>
<?php
}
}
好了,这就是设置页的基本内容. 我们简单说一下Wordpress的这套setting api吧,其中 register_setting 是注册一组选项。 第一个参数是 oscpress_settings_group ,这个是分组的名称,要跟settings_fields('oscpress_settings_group'); 的参数一致,第二个参数是 oscpress_settings ,即存储在options表里的meta_name,我们可以通过 get_option( 'oscpress_settings' ) 获取设置的内容。如果在设置页提交了表单,这个值是一个关联数组。 register_setting 的第三个参数,是对设置页表单字段进行验证和洁净化的函数,在这里即 sanitize_callback方法,这个函数接收一个参数,就是表单post过来的数组,可以理解为$_POST,比如说我们需要验证appid字段必须为20个字符,可以这样写
public function sanitize_callback($inputs){
if( strlen($inputs['appid']) !== 20 ) {
add_settings_error('oscpress_settings', 'oscpress_failed', "应用ID必须为20位", 'error');
$settings = (array) get_option( 'oscpress_settings' );
$inputs['appid'] = isset($settings['appid']) ? $settings['appid'] : "";
}
return $inputs;
}
如果填写错误,会出现一条错误提示: 其他的api函数如:add_settings_section,add_settings_field,do_settings_sections可参考注释和gist: https://gist.github.com/annalinneajohansson/5290405 接下来我们会讲一下获取osc oauth授权。