欢迎来到THBWiki!
如果您是第一次来到这里,请点击右上角注册一个帐户
有任何意见、建议、求助、反馈都可以在
讨论板
提出
THBWiki以专业性和准确性为目标,如果你发现了任何确定的错误或疏漏,可在登录后直接进行改正
查看“帮助:编写扩展”的源代码
←
帮助:编写扩展
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
少女
您没有权限编辑
帮助
命名空间内的页面。
您可以查看和复制此页面的源代码。
{{帮助头部}} {{帮助页面导航}} 本页面用于记录部分编写扩展时会用到的功能接口、需要注意的事项,扩展的修改记录可以参看[[帮助:扩展修改记录]]。 == 理论 == === 缓存机制 === 根据我的观测和猜测,MW的缓存机制很复杂,光是我能明显区分的层次就有4个,可能还有更多的层次实现着各种各样奇葩的功能。 * '''源代码''',就是WikiCode,最原始的状态,在任何一个词条按右上的“编辑”就能浏览得到。 * '''一级缓存''',此层次只会在词条本身有改动或嵌入的模板有改动的时候刷新,虽然不清楚具体储存了什么,但如果不刷新此层次有部分应该已经改变了的东西仍然会停留在旧的状态。 * '''二级缓存''',储存和[[特殊:展开模板]]差不多的文字,所有可以展开的都展开了,只剩少量MW基本语法(比如[[]] == == * # :),可以通过action=purge刷新。如果没有打开FileCache,或者是不能使用FileCache的情况,一般页面会从这个缓存开始,通过简单处理、寻找链接判断红蓝,整理出HTML显示。 * '''FileCache''',为非登录用户储存整理后的纯HTML,侧边栏,顶部底部都会被缓存,极节省时间。 == 功能接口实作 == === 全域函数 === ==== wfMessage ==== 通过Message名称获取[[#Message|Message]]物件 <syntaxhighlight lang="php" highlight=""> wfMessage( 'xxx-msg' ); </syntaxhighlight> ==== wfEscapeWikiText ==== 转义所有特殊字符,用以在HTML中显示,是强化版的htmlspecialchars <syntaxhighlight lang="php" highlight=""> wfEscapeWikiText( $text ); </syntaxhighlight> 最最最最大的问题是他没有反函数,所以在很多情况下都带来很多麻烦。 ==== wfSetVar ==== 特殊的设变量方法,会把$variable的值换成$value,然后传回$variable原本的值,当$force是true的时候即使$value是null也会强制设定$variable <syntaxhighlight lang="php" highlight=""> wfSetVar( $variable, $value ); wfSetVar( $variable, $value, $force ); </syntaxhighlight> ==== wfSuppressWarnings ==== 强制禁止输出警告,用true来复原 <syntaxhighlight lang="php" highlight=""> wfSuppressWarnings(); wfSuppressWarnings(true); </syntaxhighlight> ==== wfGetDB ==== 获取[[#DatabaseBase|DatabaseBase]]物件 <syntaxhighlight lang="php" highlight=""> wfGetDB(DB_MASTER); wfGetDB(DB_SLAVE); </syntaxhighlight> DB_MASTER用于写,DB_SLAVE用于读。 ==== ==== <syntaxhighlight lang="php" highlight=""> </syntaxhighlight> === 类 === ==== Title ==== * Title::newFromDBkey,用DBkey来生产Title,DBkey就是把空格转为_,包含命名空间的页面标题。 <syntaxhighlight lang="php" highlight=""> $title = Title::newFromDBkey( $key ); </syntaxhighlight> * Title::newFromText,用纯文字来生产Title,是最常用的一个,还可以强制设定命名空间。 <syntaxhighlight lang="php" highlight=""> $title = Title::newFromText( $text, NS_MAIN ); </syntaxhighlight> * Title::newFromID,用页面ID来生产Title,是最准确的一个,而且在提交表格时比起传送标题文字,传送数字更简单。 <syntaxhighlight lang="php" highlight=""> $title = Title::newFromID( $id ); </syntaxhighlight> * Title::newFromIDs,用多个页面ID来生产多个Title,输入输出都是array。 * Title::newFromRow,用sql结果行来生产Title,有时候需要做query,顺便连结获取结果词条的所有资料,就省下再用newFromID获取Title资料的功夫了,不过获取的资料不能有缺漏。需要的列有:page_namespace、page_title、page_id、page_len、page_is_redirect、和page_latest,page_lang和page_content_model可有可无。 <syntaxhighlight lang="php" highlight=""> $title = Title::newFromRow( $row ); </syntaxhighlight> * Title::makeTitle,最一般的方法,页面名称和命名空间分开两个参数传入,可以更严格地限制Title的命名空间。 <syntaxhighlight lang="php" highlight=""> $title = Title::makeTitle( $ns, $title, $fragment, $interwiki ); </syntaxhighlight> * Title::makeTitleSafe,和Title::makeTitle差不多,只不过强化了安全性,适合对用户输入操作。 <syntaxhighlight lang="php" highlight=""> $title = Title::makeTitleSafe( $ns, $title, $fragment, $interwiki ); </syntaxhighlight> * Title::newMainPage,获取主页的Title,一般没什么用。 * Title::compare,比较两个Title,用于usort排序Title。 <syntaxhighlight lang="php" highlight=""> Title::compare( $a, $b ); </syntaxhighlight> * getText,获取标题文字,用空格,无命名空间 * getPartialURL,获取URL编码后的标题,无命名空间 * getDBkey,获取DBkey,用_,有命名空间 * getNamespace,获取命名空间的数字 * getNsText,获取命名空间的文字 * getSubjectNsText,获取命名空间的文字,如果是讨论页获取讨论内容的命名空间 * getTalkNsText,获取对应讨论页的命名空间 * getPrefixedDBkey,获取标题文字,用_,有命名空间 * getPrefixedText,获取标题文字,用空格,有命名空间 * getFullText,获取标题文字,用空格,有命名空间,再加上#和段落 * getRootText,获取根页面标题文字,用空格,无命名空间 * getRootTitle,获取根页面Title * getBaseText,获取上一级页面标题文字,用空格,无命名空间 * getBaseTitle,获取上一级页面Title * getSubpageText,获取子页面标题文字,用空格,无命名空间,比如User:Foo/Bar/Baz返回Baz * getSubpage,获取指定子页面Title <syntaxhighlight lang="php" highlight=""> Title::newFromText('User:Foo/Bar/Baz')->getSubpage("Asdf"); // 返回标题是 User:Foo/Bar/Baz/Asdf 的Title </syntaxhighlight> * getPrefixedURL,获取URL编码后的标题,有命名空间 * getFullURL,获取完整网址,可以加上query <syntaxhighlight lang="php" highlight=""> $title->getFullURL( $query ); </syntaxhighlight> * getLocalURL,获取内链网址,不包含域名,可以加上query <syntaxhighlight lang="php" highlight=""> $title->getFullURL( $query ); </syntaxhighlight> * getEditURL,获取编辑页面的链接 * getArticleID,获取页面ID * getLatestRevID,获取当前版本ID * isSpecialPage,是否特殊页面 * isMainPage,是否主页 * isSubpage,是否子页面 * isRedirect,是否重定向页 * isNewPage,是否新页面 * exists,页面是否存在 * inNamespace,是否位于此命名空间 <syntaxhighlight lang="php" highlight=""> $title->inNamespace( $ns ); </syntaxhighlight> * inNamespace,是否位于其中一个命名空间 <syntaxhighlight lang="php" highlight=""> $title->inNamespace( $ns1, $ns2, $ns3 ); $title->inNamespace( array( $ns1, $ns2, $ns3 ) ); </syntaxhighlight> * getSubpages,获取子页面,返回Title组成的array <syntaxhighlight lang="php" highlight=""> $title->getSubpages( $limit ); </syntaxhighlight> 可以设定$limit限制最大获取的子页面数,不设定或者设为-1代表不限制。 * getParentCategories,获取页面所属的分类,返回分类名是key的array <syntaxhighlight lang="php" highlight=""> $title->getParentCategories(); // 会返回 array( '分类:XXX' => '词条名', '分类:YYY' => '词条名', '分类:ZZZ' => '词条名' )格式的array,有点坑 </syntaxhighlight> * getRedirectsHere,获取重定向到此页面的页面,返回Title组成的array <syntaxhighlight lang="php" highlight=""> $title->getRedirectsHere( $ns ); </syntaxhighlight> 设定$ns可以限制返回的页面的命名空间 ==== Message ==== 用来获取Message的类,Message可以由扩展的i18n json、php及MediaWiki命名空间的词条定义。 * exists,辨别该Message是否存在。 * text、plain、escape、parse、parseAsBlock,以各种形式输出Message的内容,实际上都是几下要输出的类型然后丢给__toString的,一般情况什么都不写自动__toString也是不会出问题的。text返回把{{}}都展开了的文字;plain返回源码;escape返回HTML转义了的text;parse返回所有wiki代码都展开了的纯html;parseAsBlock返回带框的parse。 * inLanguage,设定语言 <syntaxhighlight lang="php" highlight=""> wfMessage( 'msg-name-xxx' )->inLanguage( 'en' )->text(); // 把输出的语言转为en </syntaxhighlight> * inContentLanguage,设定语言为当前语言,如果没有操作过inLanguage的话这个是完全不会用到的。 <syntaxhighlight lang="php" highlight=""> wfMessage( 'msg-name-xxx' )->inContentLanguage()->text(); // 把输出的语言转为en </syntaxhighlight> * numParams,为Message添加参数,会顺序把Message里面的$1$2$n替换成那些参数。 <syntaxhighlight lang="php" highlight=""> wfMessage( 'msg-name-xxx' )->numParams( '1', '2' ); // 较常用的比如 wfMessage( 'parentheses' )->numParams( '括号内容' )->text(); // 会输出:(括号内容) 实际用什么类型的括号受到选用的语言影响,比如en的话就是() wfMessage( 'quotation-marks' )->numParams( '引号内容' )->text(); // 会输出:“括号内容” 实际用什么类型的引号受到选用的语言影响,比如en的话就是"" </syntaxhighlight> 其他常用的有: *semicolon-separator,分号(排比分隔符)";" *comma-separator,逗号(并列分隔符)"、" *colon-separator,冒号":" *pipe-separator,竖杠" | " *word-separator,字词分隔符(中文里并没有)"" *parentheses,括号"($1)" *quotation-marks,引号"“$1”" *imgmultipageprev,上一页"← 上一页" *imgmultipagenext,下一页"下一页 →" === 全域变量 === ===== wgExtensionCredits ===== 定义扩展信息列表,用来在[[特殊:版本信息]]中显示 <syntaxhighlight lang="php" highlight=""> define( 'XXX_VERSION', '1.0.0' ); $wgExtensionCredits['parserhook'][] = array( 'path' => __FILE__, 'name' => 'ExtensionName', 'version' => XXX_VERSION, 'author' => array( 'XXX' ), 'url' => 'http://thwiki.cc/', 'descriptionmsg' => 'extensionname-desc', ); </syntaxhighlight> 一般都是parserhook或者other。 ===== wgAutoloadClasses ===== 定义autoload对照表,简单地 <syntaxhighlight lang="php" highlight=""> $wgAutoloadClasses['ClassNameXXX'] = __DIR__ . '/ClassNameXXX.php'; </syntaxhighlight> 就行了,用autoload而不是require或include能节省很多服务器资源。 ===== wgMessagesDirs ===== 定义扩展Messages所在的文件夹,对于所有扩展都是一个写法,适用使用i18n json的情况 <syntaxhighlight lang="php" highlight=""> $wgMessagesDirs['ExtensionNameXXX'] = __DIR__ . '/i18n'; </syntaxhighlight> 自MW1.21起扩展所有Messages都应该写在i18n json里。 ===== wgExtensionMessagesFiles ===== 然而wgMessagesDirs只能定义Message,不能用来定义magic和alias,所以还需要用这个定义扩展magic和alias所在的文件 <syntaxhighlight lang="php" highlight=""> $wgExtensionMessagesFiles['ExtensionNameXXXMagic'] = __DIR__ . '/ExtensionNameXXX.magic.php'; </syntaxhighlight> ===== wgSpecialPages ===== 定义特殊页面列表及定义特殊页面所用的类,需要增加特殊页面的时候需要 <syntaxhighlight lang="php" highlight=""> $wgSpecialPages['SpecialPageNameXXX'] = 'SpecialPageClassNameXXX'; </syntaxhighlight> 同时也需要加到autoload里面。 ===== wgSpecialPageGroups ===== 定义各个特殊页面的分组 <syntaxhighlight lang="php" highlight=""> $wgSpecialPageGroups['SpecialPageNameXXX'] = 'pagetools'; </syntaxhighlight> 差不多都是pagetools或parserhook。 ===== wgJobClasses ===== 定义Job列表及定义Job所用的类 <syntaxhighlight lang="php" highlight=""> $wgJobClasses['JobNameXXX'] = 'JobClassNameXXX'; </syntaxhighlight> 同时也需要加到autoload里面。 ===== wgAPIModules ===== 定义api模组列表及定义api模组所用的类 <syntaxhighlight lang="php" highlight=""> $wgAPIModules['APIModulesNameXXX'] = 'APIModulesClassNameXXX'; </syntaxhighlight> 当链接到api.php?action=APIModulesNameXXX的时候就会调用APIModulesClassNameXXX处理请求。 ===== wgResourceModules ===== 定义js/css模组列表 <syntaxhighlight lang="php" highlight=""> $wgResourceModules['ext.ModulesXXX'] = array( 'localBasePath' => __DIR__, 'remoteExtPath' => 'ExtensionNameXXX', 'scripts' => array( 'ExtensionNameXXX.js' ), 'styles' => array( 'ExtensionNameXXX.css' ), ); </syntaxhighlight> 其他还可以定义messages,一个包含着模组需要用到的Message的名称的array,在js里可以用 <syntaxhighlight lang="javascript" highlight=""> mw.message( 'MessageNameXXX' ).plain(); mw.message.apply( 'MessageNameXXX', ['aaa','bbb'] ).plain(); </syntaxhighlight> 简单地调用在服务器端里定义了的Message。<br /> 以及dependency,一个包含着模组需要用到的模组的名称的array,系统会确保在dependency都加载好了的时候才加载你的模组。 ===== ===== <syntaxhighlight lang="php" highlight=""> </syntaxhighlight> === Hook === ===== GetPreferences ===== 当用户进入到[[特殊:参数设置]]时会就调用,用来增加可以设定的项目。 <syntaxhighlight lang="php" highlight=""> function onGetPreferences ( User $user, array &$preferences ) { $preferences['prefs-name-xxx'] = array( 'type' => 'toggle', 'label-message' => 'prefs-name-xxx-msg', 'section' => 'editing/advancedediting', ); return true; } </syntaxhighlight> 可以通过[[#User|$user]]获取个别用户的详细资讯,不过多数用不着。<br /> $preferences是一个定义了一大堆设定项的阵列,prefs-name-xxx就是把此设定储存到数据库时使用的key,必须确保不会重复。 ===== AdminLinks ===== AdminLinks用的Hook,用来增加管理员链接页面的内容 <syntaxhighlight lang="php" highlight=""> function onAdminLinks ( &$tree ) { $section = $tree->getSection( wfMessage( 'adminlinks_general' )->text() ); if ( is_null( $section ) ) return true; $row = $section->getRow( 'main' ); $row->addItem( ALItem::newFromExternalLink( 'http://thwiki.cc/', '首页' ) ); return true; } </syntaxhighlight> ===== OutputPageParserOutput ===== 在一级缓存之后,二级缓存之前,要对页面内容作出更改时用的 <syntaxhighlight lang="php" highlight=""> function onOutputPageParserOutput ( OutputPage &$page, ParserOutput $output ) { $id = $page->getTitle()->getArticleID(); $output->setText( '<div>ID of this page is ' . $id . '</div>' . $output->getText() ); return true; } </syntaxhighlight> [[#ParserOutput|$output]]不是传参考的所以改了也没用,不过即使只有[[#OutputPage|$page]]也能做足够多的操作了。 ===== BeforePageDisplay ===== 在二级缓存之后,filecache之前,要对页面内容作出更改时用的,多数用于增加js <syntaxhighlight lang="php" highlight=""> function onBeforePageDisplay ( OutputPage &$out, Skin &$sk ) { $out->setPageTitle( 'XXX' ); $out->addModules( 'ext.ModulesXXX' ); return true; } </syntaxhighlight> [[#OutputPage|$out]]可以做很多种操作,就是不能简单地更改页面内容。 ===== SkinTemplateNavigation ===== 用于在页面顶部导航栏(阅读 编辑 查看历史)内增加内容。 <syntaxhighlight lang="php" highlight=""> function onSkinTemplateNavigation ( SkinTemplate &$sktemplate, array &$links ) { $links['views']['actionnamexxx'] = array( 'class' => false, 'text' => wfMessage( 'actionnamexxx-msg' )->text(), 'href' => $sktemplate->getTitle()->getLocalURL( array( 'action' => 'edit', 'actionnamexxx' => '1' ) ) ); return true; } </syntaxhighlight> class设为false或是空字串的话该导航项就会在页面过窄的时候自动隐藏,节省空间。设为selected的话就会变成当前显示的那项,不过也需要手动把原本显示的项设为空。 ===== ParserFirstCallInit ===== 写ParserHook最重要的一个函数,[[#Parser|Parser]]初始化的时候会调用一次,用来定义各种ParserHook。 <syntaxhighlight lang="php" highlight=""> class ExtMultiArrayMap { public static function Init( Parser &$parser ) { $parser->setFunctionHook( 'multimap', 'ExtMultiArrayMap::Map', SFH_OBJECT_ARGS ); $parser->setFunctionHook( 'multitemplate', 'ExtMultiArrayMap::Template' ); $parser->setFunctionHook( 'countmap', 'ExtMultiArrayMap::Count', SFH_OBJECT_ARGS ); $parser->setFunctionHook( 'counttemplate', 'ExtMultiArrayMap::CountTem' ); return true; } } </syntaxhighlight> 定义ParserHook的同时,该ParserHook必须在magic内有对应的值 <syntaxhighlight lang="php" highlight=""> $magicWords['en'] = array( 'multimap' => array( 0, 'multimap', 'multiarraymap' ), 'multitemplate' => array( 0, 'multitem', 'multiarraytemplate', 'multitemplate' ), 'countmap' => array( 0, 'countmap' ), 'counttemplate' => array( 0, 'counttem', 'counttemplate' ), ); </syntaxhighlight> array的第一个值是0则表示调用时不区分大小写,1则是区分大小写。 ===== MagicWordwgVariableIDs ===== 定义魔术字需要用另外一个Hook <syntaxhighlight lang="php" highlight=""> class ExtMultiArrayMap { public static function setMagic ( &$list ) { $nohash = array( 'pagename', 'fullpagename', 'rootpagename', 'basepagename', 'subpagename', 'talkpagename', 'subjectpagename' ); foreach ( $nohash as $func ) { $list[] = $func . 'h'; } } } </syntaxhighlight> 该魔术字也必须在magic内有对应的值 <syntaxhighlight lang="php" highlight=""> $magicWords['en'] = array( 'pagenameh' => array( 0, 'PAGENAMEH' ), 'fullpagenameh' => array( 0, 'FULLPAGENAMEH' ), 'rootpagenameh' => array( 0, 'ROOTPAGENAMEH' ), 'basepagenameh' => array( 0, 'BASEPAGENAMEH' ), 'subpagenameh' => array( 0, 'SUBPAGENAMEH' ), 'talkpagenameh' => array( 0, 'TALKPAGENAMEH' ), 'subjectpagenameh' => array( 0, 'SUBJECTPAGENAMEH' ), ); </syntaxhighlight> array的第一个值是0则表示调用时不区分大小写,1则是区分大小写。 ===== ParserGetVariableValueSwitch ===== 然后再用这个函数返回魔术字对应的值 <syntaxhighlight lang="php" highlight=""> class ExtMultiArrayMap { public static function getMagic ( &$parser, &$cache, &$index, &$value ) { switch( $index ) { case 'pagenameh': $value = ( $parser->mTitle->getText() ); break; case 'fullpagenameh': $value = ( $parser->mTitle->getPrefixedText() ); break; case 'subpagenameh': $value = ( $parser->mTitle->getSubpageText() ); break; case 'rootpagenameh': $value = ( $parser->mTitle->getRootText() ); break; case 'basepagenameh': $value = ( $parser->mTitle->getBaseText() ); break; case 'talkpagenameh': if ( $parser->mTitle->canTalk() ) { $talkPage = $parser->mTitle->getTalkPage(); $value = ( $talkPage->getPrefixedText() ); } else { $value = ''; } break; case 'subjectpagenameh': $subjPage = $parser->mTitle->getSubjectPage(); $value = ( $subjPage->getPrefixedText() ); break; } return true; } } </syntaxhighlight> ===== ParserLimitReport ===== 用来在ParserLimitReport里增加内容,一般情况下不会太用到,但是在调试时可以当作trace来用 <syntaxhighlight lang="php" highlight=""> function onParserLimitReport( $parser, &$report ) { global $wfxxxusedcount; $report .= 'XXX use count: ' . $wfxxxusedcount . "\n"; return true; } </syntaxhighlight> <syntaxhighlight lang="html5" highlight="13"> <!-- NewPP limit report CPU time usage: 0.102 seconds Real time usage: 0.105 seconds Preprocessor visited node count: 16/1000000 Preprocessor generated node count: 82/1000000 Post‐expand include size: 1504/2097152 bytes Template argument size: 0/2097152 bytes Highest expansion depth: 2/40 Expensive parser function count: 0/100 RegexRedirect use time: 0.00149703025818 CollisionManager use time: 4.29153442383E‐5 XXX use count: 0 ExtLoops count: 0/100 ExtRegexFun count: 0 --> </syntaxhighlight> ===== ===== <syntaxhighlight lang="php" highlight=""> </syntaxhighlight> [[分类:扩展帮助文档]]
本页使用的模板:
模板:Lan
(
查看源代码
)(受保护)
模板:Navbar
(
查看源代码
)(受保护)
模板:Navbox
(
查看源代码
)(受保护)
模板:Navbox subgroup
(
查看源代码
)(受保护)
模板:Lan
(
查看源代码
)
模板:头部设定
(
查看源代码
)(受保护)
模板:帮助头部
(
查看源代码
)(受保护)
模板:帮助页面导航
(
查看源代码
)
模板:词条头部
(
查看源代码
)(受保护)
返回
帮助:编写扩展
。
导航菜单
个人工具
创建账号
登录
命名空间
帮助
讨论
查看
阅读
源码
查看历史
更多
搜索
常用
首页
东方Project
上海爱丽丝幻乐团
ZUN
幻想乡
幻想乡年表
东方年表
东方同人规约
近期新闻
沙盒(建议使用)
讨论板
加入我们
官方作品
官方游戏
旧作
东方灵异传
东方封魔录
东方梦时空
东方幻想乡
东方怪绮谈
东方红魔乡
东方妖妖梦
东方永夜抄
东方花映塚
东方风神录
东方地灵殿
东方星莲船
东方神灵庙
东方辉针城
东方绀珠传
东方天空璋
东方鬼形兽
东方虹龙洞
东方兽王园
小数点射击游戏
东方文花帖
东方文花帖DS
妖精大战争
弹幕天邪鬼
秘封噩梦日记
弹幕狂们的黑市
黄昏边境合作游戏
东方萃梦想
东方绯想天
东方非想天则
东方心绮楼
东方深秘录
东方凭依华
东方刚欲异闻
官方音乐
原曲列表
非音乐CD音乐列表
音乐CD曲目列表
蓬莱人形
莲台野夜行
梦违科学世纪
卯酉东海道
大空魔术
未知之花 魅知之旅
鸟船遗迹
伊奘诺物质
燕石博物志
旧约酒馆
虹色的北斗七星
幺乐团的历史系列
幺乐团的历史 vol.1
幺乐团的历史 vol.2
幺乐团的历史 vol.3
幺乐团的历史 vol.4
幺乐团的历史 vol.5
格斗游戏OST
幻想曲拔萃
全人类的天乐录
核热造神非想天则
暗黑能乐集心绮楼
深秘乐曲集
深秘乐曲集·补
完全凭依唱片名录
贪欲之兽的音乐
商业出版品附带CD
官方书籍
东方香霖堂
东方三月精
第一季
月之妖精
第二季
第三季
第四季
东方文花帖
风之号外
东方紫香花
六十年不见的紫香花
东方儚月抄
漫画
小说
四格
东方茨歌仙
东方铃奈庵
东方醉蝶华
东方智灵奇传
东方求闻史纪
记忆幻想乡
东方求闻口授
魔理沙的魔法书
宇佐见的魔法书
东方外来韦编
东方文果真报
东方人妖名鉴
宵暗篇
常世篇
幻想Narrato Graph
官方角色
公式资料
附带文档
游戏对话
官方作品光盘信息
角色自称用词表
官作译名更改记录
原作物品列表
出典文献列表
其他ZUN参与的作品
西方Project
东方关联人物
游戏攻略
东方相关活动
从第二家开始的广播
东方STATION
数码游戏博览会
PoriPori☆Club
niconico超会议
斗会议
niconico原创游戏祭
枯萎Radio
GDGD
其他相关项目
东方我乐多丛志
东方四方山新闻
Play,Doujin!
东方电书流通
东方音乐流通
二次创作与活动
展会及活动导航
Comic Market
博丽神社例大祭
博丽神社例大祭SP
博丽神社秋季例大祭
博丽神社例大祭in台湾
海外博丽神社例大祭
博丽神社歌谣祭
博丽神社崇敬会相关活动
COMICUP
上海THONLY
东方Only活动
东方红楼梦
角色Only活动
作品Only活动
地区Only活动
其他地区举办的展会
其他展会
M3
COMIC1
展会作品列表
展会作品数量
展会同人志列表
展会专辑列表
展会软件列表
展会视频列表
商业二次创作
电脑游戏
东方月神夜
家用机游戏
Play,Doujin
手机游戏
东方大炮弹
东方LostWord
东方Dungeon Dive
东方弹幕神乐
东方幻想Eclipse
同人二次创作
同人社团列表
同人志分类
同人专辑分类
同人专辑搜索
原曲作品数量
同人软件列表
Steam游戏列表
同人角色列表
同人视频列表
其他形式同人
同人文章列表
同人画师列表
同人封面角色
东方相关周边
PVCFigure
GarageKit
小型物品
其他形式周边
MUGEN
THB相关项目
THB策划
中文东方人气投票
东深见讲坛
幻想乡柱状地图
THB衍生
同人专辑搜索
原曲认知测验
东方相关QQ群组列表
THB媒体
微博
Bilibili
直播间
GitHub
THB协力
博丽神主ZUN微博
东方我乐多丛志
MineCraft幻想乡
京都幻想剧团
幻奏盛宴
功能与帮助
最近更改
随机浏览
编写规范
收录方针
命名规范
同人社团
同人音乐
封面图片
二次设定
编辑帮助
基础帮助
常用模板
进阶代码
函数用法
编写翻译表
语义维基
样式类用法
颜色列表
工具
链入页面
相关更改
特殊页面
页面信息
其他
联系管理员
关于THBWiki
捐款支持
语言
English
italiano
日本語
中文