TypechoBio is a Typecho plugin for running a personal homepage on a specified domain. It can take over requests for selected hostnames, reuse Typecho’s existing comment system, and bind comments to a chosen article ID.
It is not a regular Typecho frontend theme. Instead, it works as an independent plugin entry that renders a complete page when the current request matches a configured domain. This makes it useful for personal profile pages, bio pages, portfolio landing pages, and standalone static-style homepages that still need Typecho’s login state, configuration storage, posts, and comments.
Installation
Option 1: Install through AB-Store
After installing the AdminBeautify plugin, open AB-Store in the Typecho admin panel, search for TypechoBio, and install it with one click. This method is recommended because it also makes later updates easier.
Option 2: Manual installation
- Download the latest Release archive.
- Extract it as a folder named
TypechoBio. - Upload the folder to Typecho’s
usr/plugins/directory. - Log in to the admin panel, go to Console → Plugins, and enable TypechoBio.
Option 3: Clone with Git
cd /path/to/typecho/usr/plugins/
git clone https://github.com/lhl77/TypechoBio.git TypechoBio
Available themes
The plugin can install and use several personal homepage themes, including Imsyy, Duckfolio, Zyyo, Dmego, Wexuo, and IAMI.
Adapting a theme for TypechoBio
The following notes are intended for theme developers who want to adapt an existing frontend page or theme source code to TypechoBio. The guidance follows the current plugin behavior and is suitable for these cases:
- Adding a local theme under
usr/plugins/TypechoBio/templates/<theme>/ - Migrating external HTML pages, static sites, Vite build output, or existing theme source code into TypechoBio
- Connecting a theme to the plugin’s shared configuration system, comment section, and independent-domain runtime context
- Packaging a theme as an installable zip for a remote theme marketplace
How TypechoBio runs
TypechoBio is not mounted as the normal Typecho frontend theme. It takes over output only when the current request host matches the plugin’s configured domain list.
The execution flow is roughly as follows:
- The plugin checks the current Host against
bio_hoststo decide whether TypechoBio should handle the request. - If matched, it first processes theme-specific APIs, then handles static asset requests for the active theme.
- Non-asset requests enter
usr/plugins/TypechoBio/templates/index.php. templates/index.phpprepares runtime context such as the active theme, theme configuration, user state, and comment data.- Finally, it loads
usr/plugins/TypechoBio/templates/<theme>/home.phpto output the full page.
This model has a few important consequences:
home.phpmust output a complete HTML document by itself. Do not assume Typecho’s normal frontend templates will wrap it.- A theme can access the database, login state, and plugin settings at runtime, but it should preferably read the prepared
$typechoBioContext. - Assets, comments, and configuration should follow TypechoBio conventions instead of directly inheriting assumptions from another CMS or theme system.
Minimum theme structure
A theme must provide at least the following files before TypechoBio can recognize it:
usr/plugins/TypechoBio/
└── templates/
└── my-theme/
├── home.php
├── theme.json
├── assets/
│ ├── app.css
│ └── app.js
├── images/
└── ...
The discovery rule is strict:
templates/<dir>/home.phpmust exist.templates/<dir>/theme.jsonmust exist.- If either file is missing,
discoverThemes()will not treat the directory as an available theme.
Recommended practice:
- Use only letters, numbers, underscores, and hyphens in theme directory names.
- Keep the directory name consistent with the theme identifier in
theme.json. - Put all static assets for the theme inside the theme directory instead of scattering files under the plugin root.
What home.php should do
home.php is the real entry file of a TypechoBio theme. It is best treated as the page shell template. At minimum, it should:
- Output the complete HTML document structure
- Read
$typechoBioContext - Render page content based on
themeConfig - Reference static assets from the current theme correctly
- Include the shared comment section, proxy interfaces, or shared fragments when needed
A minimal working example:
<?php
if (!defined('__TYPECHO_ROOT_DIR__')) {
exit;
}
$ctx = isset($typechoBioContext) && is_array($typechoBioContext)
? $typechoBioContext
: array();
$themeConfig = isset($ctx['themeConfig']) && is_array($ctx['themeConfig'])
? $ctx['themeConfig']
: array();
$siteTitle = isset($ctx['siteTitle']) ? (string) $ctx['siteTitle'] : 'TypechoBio';
$themeAssetBase = isset($ctx['themeAssetBase']) ? (string) $ctx['themeAssetBase'] : '';
$pluginRoot = dirname(dirname(__DIR__));
?>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo htmlspecialchars($siteTitle, ENT_QUOTES, 'UTF-8'); ?></title>
<link rel="stylesheet" href="<?php echo htmlspecialchars($themeAssetBase . 'assets/app.css', ENT_QUOTES, 'UTF-8'); ?>">
</head>
<body>
<main>
<h1><?php echo htmlspecialchars($siteTitle, ENT_QUOTES, 'UTF-8'); ?></h1>
</main>
<?php
$bioCommentOptions = array(
'enabled' => true,
'container_class' => 'my-theme-comments',
);
require $pluginRoot . '/views/comment-section.php';
require $pluginRoot . '/views/comment-script.php';
?>
<script src="<?php echo htmlspecialchars($themeAssetBase . 'assets/app.js', ENT_QUOTES, 'UTF-8'); ?>"></script>
</body>
</html>
Runtime context: $typechoBioContext
Before loading home.php, templates/index.php collects shared runtime information into $typechoBioContext. Themes should read values from this array first instead of rebuilding the same data manually.
Common fields include the following.
Basic site information
host: the matched domain for the current requestsiteTitle: site titlesiteUrl: site URLadminUrl: admin panel URLsiteIcon: site icon configured in the plugin settings
User information
userLogged: whether the current visitor is logged inuserName: logged-in usernameuserGroup: user group
Theme and plugin information
themeKey: current theme directory namethemeConfig: parsed configuration array for the current themethemeAssetBase: base URL for static assets in the current themepluginAssetBase: base URL for plugin-level assetspluginNamepluginVersionpluginLink
Comments and APIs
profileApi: login-state query endpointcommentApi: comment submission endpointcommentTarget: target article information for commentscommentList: approved comment listcommentResultcommentMessage
Other useful data
posts: latest posts list; the current implementation defaults to the 10 most recent published postsheadPreMeta: custom head snippet configured in the admin panel, inserted before meta contentheadCustomCss: custom CSS configured in the admin panelheadCustomJs: custom JavaScript configured in the admin panelloadStart: request start time
Reading example:
<?php
$ctx = $typechoBioContext;
$config = isset($ctx['themeConfig']) ? $ctx['themeConfig'] : array();
$title = isset($ctx['siteTitle']) ? $ctx['siteTitle'] : '';
$logged = !empty($ctx['userLogged']);
$commentApi = isset($ctx['commentApi']) ? $ctx['commentApi'] : '';
theme.json format
theme.json is the only standard file TypechoBio uses to identify theme metadata and generate configuration forms.
A recommended complete example:
{
"name": "My Theme",
"version": "1.0.0",
"description": "一个适配到 TypechoBio 的主题",
"fields": [
{
"key": "hero_title",
"label": "首屏标题",
"type": "text",
"default": "Hello TypechoBio",
"description": "显示在首屏的大标题"
},
{
"key": "hero_desc",
"label": "首屏描述",
"type": "textarea",
"default": "这是主题说明",
"description": "支持多行文本"
},
{
"key": "theme_mode",
"label": "配色模式",
"type": "select",
"default": "system",
"description": "主题初始配色模式",
"options": {
"light": "浅色",
"dark": "深色",
"system": "跟随系统"
}
},
{
"key": "show_comments",
"label": "启用评论区",
"type": "checkbox",
"default": "1",
"description": "关闭后不渲染评论区"
}
]
}
Top-level fields
name: display name of the themeversion: theme version, used when the theme marketplace compares updatesdescription: short descriptionfields: array of configuration fields
Supported fields inside fields
Each field object may contain:
key: required field key; only letters, numbers, and underscores are allowedlabel: display name in the admin paneltype: field typedefault: default valuedescription: help text shown in the admin paneloptions: used only byselect
Currently supported type values are limited to:
texttextareanumberselectcheckbox
Important details:
keymust not contain spaces, hyphens, dots, or slashes.- Nested object configuration structures are not supported. For complex data, serialize it into a string or JSON string.
checkboxvalues are normalized to the strings1or0.selectoptionsmust be an object. The object keys are actual values, and the object values are the labels shown in the admin panel.
Default value behavior
TypechoBio automatically synchronizes configuration based on theme.json:
- When a new field is added, its default value is inserted into the configuration JSON.
- When a field is removed, it is also removed from the configuration JSON and the admin form.
- When a theme is newly installed, the current page syncs that theme’s default configuration into the theme configuration JSON.
For that reason, default should be filled in carefully. If omitted, the field’s initial value will be an empty string.
How theme configuration is stored
TypechoBio currently keeps two representations of theme configuration, but developers should treat the JSON value as the final structure:
- Unified JSON:
bio_theme_configs_json - Admin form field:
bio_theme_cfg__{theme}__{key}
In practice:
- The settings page displays normal form fields.
- When the form is submitted, values are synchronized back to
bio_theme_configs_json. - The plugin also normalizes and synchronizes configuration when theme fields are added or removed.
Theme developers should follow these rules:
- In
home.php, read$typechoBioContext['themeConfig']first. - Do not manually assemble
bio_theme_cfg__...keys and query them from the database. - For complex arrays, lists, or objects, store them in a
textortextareafield and decode them inside the theme withjson_decode.
Example:
<?php
$config = isset($typechoBioContext['themeConfig']) ? $typechoBioContext['themeConfig'] : array();
$socialLinks = array();
if (!empty($config['social_links'])) {
$decoded = json_decode((string) $config['social_links'], true);
if (is_array($decoded)) {
$socialLinks = $decoded;
}
}
Static asset handling
TypechoBio intercepts asset requests for the current Typecho frontend theme and serves files directly from the active TypechoBio theme directory.
Recommended asset paths
The most reliable approach is to always build asset URLs with $typechoBioContext['themeAssetBase']:
<link rel="stylesheet" href="<?php echo htmlspecialchars($typechoBioContext['themeAssetBase'] . 'assets/app.css', ENT_QUOTES, 'UTF-8'); ?>">
<script src="<?php echo htmlspecialchars($typechoBioContext['themeAssetBase'] . 'assets/app.js', ENT_QUOTES, 'UTF-8'); ?>"></script>
<img src="<?php echo htmlspecialchars($typechoBioContext['themeAssetBase'] . 'images/avatar.png', ENT_QUOTES, 'UTF-8'); ?>" alt="avatar">
Where to put assets
Keep assets inside the theme directory, for example:
templates/my-theme/
├── home.php
├── theme.json
├── assets/
├── css/
├── js/
├── images/
├── img/
└── font/
Compatibility for root-path assets
The plugin currently resolves these requests back to the active theme directory:
- Regular request paths under the current theme directory
/assets/.../favicon.ico/apple-touch-icon.png/robots.txt
This means that some original themes referencing root-path files such as /assets/app.css may still work under the active TypechoBio theme.
Even so, explicit paths based on themeAssetBase are recommended because they are clearer, do not rely on implicit compatibility behavior, and are easier to migrate, debug, and switch between themes.
Case sensitivity
Linux filesystems are case-sensitive. Asset paths must exactly match the real filenames.
Do not write:
pacifico-regular.ttfif the file is actuallyPacifico-Regular.ttfimages/avatar.pngif the directory is actuallyImages/avatar.png
Relative paths inside CSS must also match the real directory and filename casing.
MIME types
The plugin already maps common asset MIME types, including:
- css
- js / mjs
- json / map
- svg
- ico
- png / jpg / webp / avif
- woff / woff2 / ttf / otf / eot
So theme build output can usually be placed directly into the theme directory without configuring a separate static server.
Adding the shared comment section
TypechoBio provides a unified comment rendering fragment. When adapting a theme, reuse this shared component whenever possible instead of reimplementing the comment backend for every theme.
Required configuration
The plugin settings must include:
评论文章 ID, namelybio_comment_cid
If this is not configured, the shared comment component will display a message saying that the comment article ID has not been set.
Minimal integration
Add the following to the theme’s home.php:
<?php
$pluginRoot = dirname(dirname(__DIR__));
$config = isset($typechoBioContext['themeConfig']) ? $typechoBioContext['themeConfig'] : array();
$showComments = !isset($config['show_comments']) || in_array((string) $config['show_comments'], array('1', 'true', 'on', 'yes'), true);
$bioCommentOptions = array(
'enabled' => $showComments,
'container_tag' => 'section',
'container_class' => 'my-theme-comment-section',
'id' => 'bio-comments',
'title' => '留言板',
'title_tag' => 'h3',
'reload_on_success' => true,
'reload_delay' => 500,
);
require $pluginRoot . '/views/comment-section.php';
require $pluginRoot . '/views/comment-script.php';
Available options
$bioCommentOptions currently supports:
enabledcontainer_tagcontainer_classidtitletitle_tagreload_on_successreload_delaytarget_missing_textempty_list_text
Shared class names
The shared comment template outputs the following class names. Themes only need to style these classes:
.bio-comment-heading.bio-comment-status.bio-comment-form.bio-comment-form-row.bio-comment-field.bio-comment-actions.bio-comment-submit.bio-comment-tip.bio-comment-list.bio-comment-item.bio-comment-meta.bio-comment-author.bio-comment-time.bio-comment-reply-label.bio-comment-replyto.bio-comment-text.bio-comment-children.bio-comment-empty
For comment styling, the recommended direction is to make usernames stand out, keep timestamps visually lighter, give the comment body enough emphasis, and make nested replies readable rather than relying only on thin indentation lines.
Remote theme repositories and zip packages
To make a theme installable through TypechoBio’s backend theme marketplace, prepare both:
- An installable zip package
- A remote
themes.jsondirectory entry
Zip package requirements
During installation, the plugin will:
- Download the zip package.
- Extract it into a temporary directory.
- Search the extracted result for a valid theme directory.
- Require the theme directory to contain both
home.phpandtheme.json. - Copy the valid theme to
usr/plugins/TypechoBio/templates/<dir>/.
Recommended zip structure:
my-theme.zip
└── my-theme/
├── home.php
├── theme.json
├── assets/
└── ...
Avoid placing many files directly at the zip root.
Suggested themes.json entry
A remote catalog entry can be structured like this:
{
"schema_version": 1,
"themes": [
{
"dir": "my-theme",
"name": "My Theme",
"description": "主题简介",
"version": "1.0.0",
"cover": "https://example.com/cover.jpg",
"zip_url": "https://example.com/my-theme.zip",
"github_url": "https://github.com/example/my-theme",
"demo_url": "https://demo.example.com"
}
]
}
Field meanings:
dir: local installation directory namename: display namedescription: descriptionversion: remote version numbercover: cover imagezip_url: zip download URLgithub_url: source repository or introduction pagedemo_url: online demo
Recommended consistency checks:
dirshould match the theme directory name inside the zip.versionshould match theversionvalue intheme.json.coverandzip_urlshould use stable, reachable URLs.
Migrating an existing frontend project
When moving an existing HTML, Vue, React, or static theme project into TypechoBio, a staged process is usually safer.
First: make the page shell run
- Put the final deployable HTML structure into
home.php. - Move CSS, JavaScript, fonts, and images into the theme directory.
- Confirm that the page opens correctly on the TypechoBio independent domain.
Second: connect the plugin context
- Replace the site title with
$typechoBioContext['siteTitle']. - Move social links, navigation, descriptions, and other variable content into
themeConfig. - Replace hardcoded asset URLs with paths based on
themeAssetBase.
Third: expose configurable fields in the backend
- Declare fields in
theme.json. - Open the plugin settings page and confirm the fields appear.
- Switch to the theme and confirm its configuration items are visible.
- Edit and save the fields, then confirm
home.phpcan read the new values.
Fourth: add comments and APIs last
- If the theme needs comments, configure
show_commentsfirst and then include the shared comment fragments. - If remote APIs are needed, prefer a same-origin proxy rather than letting the browser directly call unstable third-party endpoints.
Common issues and checks
Theme does not appear in the backend theme list
Check first:
- Whether
templates/<theme>/home.phpexists - Whether
templates/<theme>/theme.jsonexists - Whether
theme.jsonis valid JSON
Theme appears, but configuration fields do not
Check first:
- Whether the top level of
theme.jsoncontainsfields - Whether
fieldsis an array - Whether every field has a valid
key - Whether each
keycontains only letters, numbers, and underscores
Default values are not applied
Check first:
- Whether the field has a
defaultvalue - Whether a
checkboxdefault is written as1or0 - Whether a complex JSON string default is itself valid JSON
Assets return 404
Check first:
- Whether paths are based on
themeAssetBase - Whether filename casing exactly matches the real files
- Whether relative paths inside CSS are correct
- Whether the assets are actually inside the currently active theme directory
Comment section does not show
Check first:
- Whether
评论文章 IDhas been filled in the plugin settings - Whether
show_commentsis disabled in the theme configuration - Whether
home.phpreally requires bothviews/comment-section.phpandviews/comment-script.php
A theme depending on a third-party API errors as soon as the page opens
Check first:
- Whether the browser is still directly calling a cross-origin API
- Whether the upstream service has TLS, certificate, or rate-limit problems
- Whether the request should be changed to a local plugin proxy
- Whether fallback data with the same shape is provided when the proxy fails
Adaptation checklist
Before considering a new TypechoBio theme ready, verify at least the following:
- The theme directory contains both
home.phpandtheme.json. - The page opens normally under the independent domain.
- All static assets load successfully.
- The backend can recognize and display the theme.
- The backend can switch to the theme.
- Theme configuration fields appear correctly.
- Default values enter
themeConfigproperly. - After configuration changes are saved, the frontend can read the new values.
- The comment section can be enabled or disabled through theme configuration.
- If third-party APIs are used, they have been changed to same-origin proxies or have fallback behavior.
- After installing from a zip package, the current page can display configuration fields and default values without needing a manual refresh.
Suggested directory template
A clean theme structure can look like this:
templates/my-theme/
├── home.php
├── theme.json
├── assets/
│ ├── app.css
│ ├── app.js
│ └── vendor/
├── images/
├── font/
├── partials/
│ ├── hero.php
│ └── footer.php
└── README.md
In this layout:
home.phpassembles the full page.partials/stores internal reusable theme fragments.assets/stores build output.README.mdmay include theme-specific notes, while the plugin-wide conventions should still follow the rules above.