apermo/linkstash
最新稳定版本:v0.2.0
Composer 安装命令:
composer require apermo/linkstash
包简介
Apermo Stash — a self-hosted WordPress bookmark collection with a token-protected REST API.
README 文档
README
A self-hosted WordPress plugin for collecting links. Inspired by linkding. Stores URL + title + notes + tags as a custom post type and exposes a token-protected REST API so a browser extension can save links from anywhere.
Per-link public/private visibility, idempotent save (safe to re-submit),
and CORS configured for chrome-extension://* origins out of the box.
Requirements
- PHP 8.1+
- WordPress 6.4+
- Composer (development only — runtime has no Composer dependencies)
- Node.js 20+ and npm (activates husky pre-commit hook, runs Playwright)
- DDEV (for local development)
Installation
- Clone or download this repository into
wp-content/plugins/apermo-stash/. - Run
composer install --no-devto generate the autoloader. - Activate the plugin through the WordPress "Plugins" screen.
- Visit Settings → Apermo Stash to generate an API token (see Authentication below).
Authentication
Apermo Stash accepts two equivalent authentication schemes; pick whichever fits your client.
WordPress Application Passwords (Basic Auth)
Available in WordPress core. Generate one under Users → Profile → Application Passwords and pass it as Basic Auth:
curl -u "your-username:xxxx xxxx xxxx xxxx xxxx xxxx" \
https://example.tld/wp-json/apermo-stash/v1/links
Apermo Stash Bearer Tokens
Better suited for browser extensions: generate at Settings → Apermo Stash → API Tokens. The plain token is shown once at creation time — copy it immediately. Send it as:
curl -H "Authorization: Bearer <token>" \
https://example.tld/wp-json/apermo-stash/v1/links
Each token is bound to a WordPress user; permission checks run against that
user's capabilities (edit_posts for write endpoints).
REST API
Base path: /wp-json/apermo-stash/v1.
| Method | Path | Description |
|---|---|---|
GET |
/links |
List links (filters: tag, q, unread, archived, public/private, page, per_page) |
POST |
/links |
Create a link (idempotent — same URL returns existing record with X-Apermo-Stash-Existing: 1) |
GET |
/links/{id} |
Fetch a single link |
PATCH |
/links/{id} |
Update fields |
DELETE |
/links/{id} |
Delete a link |
GET |
/tags |
List tags with link counts |
GET |
/check?url=... |
Returns {exists: bool, id?: int} for a given URL |
Examples
Save a link; let the server fetch the title and description:
curl -X POST https://example.tld/wp-json/apermo-stash/v1/links \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.tld/article","tags":["reading"],"public":true}'
Check whether a URL is already saved (browser-extension "already saved" badge):
curl -H "Authorization: Bearer <token>" \ "https://example.tld/wp-json/apermo-stash/v1/check?url=https://example.tld/article"
Search and filter:
curl -H "Authorization: Bearer <token>" \ "https://example.tld/wp-json/apermo-stash/v1/links?tag=reading&unread=1"
Public versus private links
Links use WordPress's native post_status:
publish(public) — readable without authentication via the REST API.private— only the owner (and users withedit_others_posts) can read.
Anonymous GET /links returns only public links. Authenticated users
see their own links plus any public links owned by other users. POST,
PATCH, DELETE always require authentication.
CORS
By default Apermo Stash sends CORS headers permitting chrome-extension://*
origins. Add additional origins via the apermo_stash_allowed_origins filter:
add_filter( 'apermo_stash_allowed_origins', static function ( array $origins ): array { $origins[] = 'https://my-frontend.example.tld'; return $origins; } );
To narrow the default allow-list once you know your extension's specific ID — defense-in-depth on top of the Bearer requirement — return only that origin:
add_filter( 'apermo_stash_allowed_origins', static function (): array { return [ 'chrome-extension://abcdefghijklmnopqrstuvwxyzabcdef' ]; } );
Outbound HTTP
Apermo Stash makes one outbound HTTP request per saved link — to
the saved URL itself, via wp_safe_remote_get (5 s timeout, up
to three redirects, all re-validated). The fetched body is parsed
for <title> and <meta name="description" / og:description>; on
failure the link still saves and an "unreachable" warning is
shown on next edit. wp_safe_remote_get blocks loopback and private
IP ranges, so a hostile URL can't be used to probe internal services.
No third-party services are contacted. No analytics, no telemetry. The companion Chrome extension talks only to the host you configure on its options page.
Development
composer install npm install # activates husky pre-commit hook composer cs # PHPCS composer cs:fix # PHPCBF composer analyse # PHPStan composer test:unit # unit tests (Brain Monkey) composer test:integration # integration tests (wp-phpunit) npm run test:e2e # Playwright E2E
Local WordPress environment
ddev start && ddev orchestrate
License
apermo/linkstash 适用场景与选型建议
apermo/linkstash 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1 次下载、GitHub Stars 达 1, 最近一次更新时间为 2026 年 05 月 02 日, 在 PHP 生态内属于活跃度较高的组件。
我们在过去多个企业项目中使用过 apermo/linkstash 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 apermo/linkstash 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
统计信息
- 总下载量: 1
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 34
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: GPL-2.0-or-later
- 更新时间: 2026-05-02