Merge branch 'master' into dev

# Conflicts:
#	admin/css/style.css
#	var/Widget/Archive.php
This commit is contained in:
joyqi 2023-01-29 14:28:43 +08:00
commit d4a5f765a3
36 changed files with 234 additions and 88 deletions

View File

@ -55,10 +55,3 @@ jobs:
asset_name: typecho.zip
asset_content_type: application/zip
max_releases: 1
- name: Trigger build
run: |
curl -XPOST -H "Authorization: token ${{ secrets.WORKFLOW_TOKEN }}" \
-H "Accept: application/vnd.github.everest-preview+json" \
-H "Content-Type: application/json" \
https://api.github.com/repos/typecho/languages/actions/workflows/update.yml/dispatches --data '{"ref": "master"}'

View File

@ -37,3 +37,9 @@ jobs:
asset_path: ./typecho.zip
asset_name: typecho.zip
asset_content_type: application/zip
- name: Trigger langs build
run: |
curl -XPOST -H "Authorization: token ${{ secrets.WORKFLOW_TOKEN }}" \
-H "Accept: application/vnd.github.everest-preview+json" \
-H "Content-Type: application/json" \
https://api.github.com/repos/typecho/languages/actions/workflows/update.yml/dispatches --data '{"ref": "master"}'

37
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,37 @@
Contributing to Typecho
=======================
Thanks for considering contributing to Typecho! There are many ways to contribute to Typecho, and we appreciate all of them.
## Reporting Bugs
If you find a bug in the source code, you can help us by [submitting an issue](https://github.com/typecho/typecho/issues)
to our [GitHub Repository](https://github.com/typecho/typecho). Even better, you can submit a Pull Request with a fix.
## Contributing Code
If you would like to contribute code to Typecho, please read the following guidelines:
* [Code of Conduct](CODE_OF_CONDUCT.md)
* [Contributing Guide](CONTRIBUTING.md)
* [Coding Style Guide](CODING_STYLE.md)
## Translations
Please see [TRANSLATION](https://github.com/typecho/languages) for details.
## Plugin Development
Please see [Plugin Development](http://docs.typecho.org/plugins) for details.
## Theme Development
Please see [Theme Development](http://docs.typecho.org/themes) for details.
## Community
* [Telegram Channel](https://t.me/typechodev)
* [Homepage](http://typecho.org/)
* [Documents](http://docs.typecho.org/)
* [Community](http://forum.typecho.org/)
* [Download](http://typecho.org/download)

View File

@ -1,19 +1,30 @@
Typecho Blogging Platform
=========================
Typecho is a PHP Blogging Platform. Simple and Powerful.
Typecho is a PHP-based blog software and is designed to be the most powerful blog engine in the world.
Typecho is released under the GNU General Public License 2.0.
#### Telegram Channel
https://t.me/typechodev
## Main Features
#### Homepage
http://typecho.org/
* Multiple databases support (MySQL, SQLite, PostgreSQL)
* Markdown Support
* Plugin Support
* Theme Support
* Custom Fields
* Custom Pages
#### Documents
http://docs.typecho.org/
## Requirements
#### Community
http://forum.typecho.org/
* PHP 7.2.0 or higher
* Database (MySQL, SQLite, PostgreSQL)
* MySQL 5.5.3 or higher
* SQLite 3.7.11 or higher
* PostgreSQL 9.1 or higher
#### Download
http://typecho.org/download
## Screenshots
![Typecho](https://typecho.org/usr/themes/bluecode/img/screenshot/st1.png)
## Contributing
Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

View File

@ -13,7 +13,9 @@
noticeType : $.cookie(prefix + '__typecho_notice_type'),
highlight : $.cookie(prefix + '__typecho_notice_highlight')
},
path = '<?php echo \Typecho\Cookie::getPath(); ?>';
path = '<?php echo \Typecho\Cookie::getPath(); ?>',
domain = '<?php echo \Typecho\Cookie::getDomain(); ?>',
secure = <?php echo json_encode(\Typecho\Cookie::getSecure()); ?>;
if (!!cookies.notice && 'success|notice|error'.indexOf(cookies.noticeType) >= 0) {
var head = $('.typecho-head-nav'),
@ -63,14 +65,13 @@
});
});
$.cookie(prefix + '__typecho_notice', null, {path : path});
$.cookie(prefix + '__typecho_notice_type', null, {path : path});
$.cookie(prefix + '__typecho_notice', null, {path : path, domain: domain, secure: secure});
$.cookie(prefix + '__typecho_notice_type', null, {path : path, domain: domain, secure: secure});
}
if (cookies.highlight) {
$('#' + cookies.highlight).effect('highlight', 1000);
$.cookie(prefix + '__typecho_notice_highlight', null, {path : path});
$.cookie(prefix + '__typecho_notice_highlight', null, {path : path, domain: domain, secure: secure});
}
})();
@ -91,6 +92,7 @@
$('#typecho-nav-list ul.root').each(function () {
const ul = $(this), nav = ul.parent();
let focused = false;
ul.on('click touchend', '.parent a', function (e) {
nav.removeClass('noexpanded').addClass('expanded');
@ -102,6 +104,19 @@
nav.removeClass('expanded').addClass('noexpanded');
return false;
}));
$('a', ul).focus(function () {
ul.addClass('expanded');
focused = true;
}).blur(function () {
focused = false;
setTimeout(function () {
if (!focused) {
ul.removeClass('expanded');
}
});
});
});
if ($('.typecho-login').length == 0) {

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,5 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php \Typecho\Plugin::factory('admin/footer.php')->begin(); ?>
</body>
</html>
<?php

View File

@ -279,10 +279,12 @@ $(document).ready(function () {
form.submit(function () {
var t = $(this), tr = t.parents('tr'),
reply = $('<div class="comment-reply-content"></div>').insertAfter($('.comment-content', tr));
reply.html('<p>' + textarea.val() + '</p>');
var html = DOMPurify.sanitize(textarea.val(), {USE_PROFILES: {html: true}});
reply.html('<p>' + html + '</p>');
$.post(t.attr('action'), t.serialize(), function (o) {
reply.html(o.comment.content)
var html = DOMPurify.sanitize(o.comment.content, {USE_PROFILES: {html: true}});
reply.html(html)
.effect('highlight');
}, 'json');
@ -340,7 +342,7 @@ $(document).ready(function () {
}
});
var html = '<strong class="comment-author">'
var unsafeHTML = '<strong class="comment-author">'
+ (comment.url ? '<a target="_blank" href="' + comment.url + '">'
+ comment.author + '</a>' : comment.author) + '</strong>'
+ ('comment' != comment.type ? '<small><?php _e('引用'); ?></small>' : '')
@ -348,13 +350,16 @@ $(document).ready(function () {
+ comment.mail + '</a></span>' : '')
+ (comment.ip ? '<br /><span>' + comment.ip + '</span>' : '');
var html = DOMPurify.sanitize(unsafeHTML, {USE_PROFILES: {html: true}});
var content = DOMPurify.sanitize(comment.text, {USE_PROFILES: {html: true}});
$('.comment-meta', oldTr).html(html)
.effect('highlight');
$('.comment-content', oldTr).html('<p>' + comment.text + '</p>');
$('.comment-content', oldTr).html('<p>' + content + '</p>');
oldTr.data('comment', comment);
$.post(t.attr('action'), comment, function (o) {
$('.comment-content', oldTr).html(o.comment.content)
var content = DOMPurify.sanitize(o.comment.content, {USE_PROFILES: {html: true}});
$('.comment-content', oldTr).html('<p>' + content + '</p>')
.effect('highlight');
}, 'json');

View File

@ -172,7 +172,7 @@ $isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\
<?php endif; ?>
</td>
<td class="kit-hidden-mb"><a
href="<?php $options->adminUrl('manage-posts.php?uid=' . $posts->author->uid); ?>"><?php $posts->author(); ?></a>
href="<?php $options->adminUrl('manage-posts.php?__typecho_all_posts=off&uid=' . $posts->author->uid); ?>"><?php $posts->author(); ?></a>
</td>
<td class="kit-hidden-mb"><?php $categories = $posts->categories;
$length = count($categories); ?>

View File

@ -64,7 +64,7 @@ $users = \Widget\Users\Admin::alloc();
<td class="kit-hidden-mb"><input type="checkbox" value="<?php $users->uid(); ?>"
name="uid[]"/></td>
<td class="kit-hidden-mb"><a
href="<?php $options->adminUrl('manage-posts.php?uid=' . $users->uid); ?>"
href="<?php $options->adminUrl('manage-posts.php?__typecho_all_posts=off&uid=' . $users->uid); ?>"
class="balloon-button left size-<?php echo \Typecho\Common::splitByCount($users->postsNum, 1, 10, 20, 50, 100); ?>"><?php $users->postsNum(); ?></a>
</td>
<td>

View File

@ -138,7 +138,7 @@ include 'common-js.php';
img.get(0).src = '<?php $attachment->attachment->url(); ?>?' + Math.random();
}
$('#' + id).html('<?php _e('文件 %s 已经替换'); ?>'.replace('%s', data.title))
$('#' + id).text('<?php _e('文件 %s 已经替换'); ?>'.replace('%s', data.title))
.effect('highlight', 1000, function () {
$(this).remove();
$('#file-list').remove();

View File

@ -100,7 +100,7 @@ $color-nav-child-focus: #6DA1BB;
font-weight: bold;
}
&.root:hover .child {
&.root:hover .child, &.root.expanded .child {
display: block;
}
}

View File

@ -504,6 +504,14 @@ a.operate-reply {
max-width: 100%;
}
@media (max-width: $screen-phone - 1px) {
.comment-edit {
display: flex;
flex-direction: column;
width: 90vw;
}
.comment-edit td:first-child { display: none; }
}
/**
* 评论回复

View File

@ -1,4 +1,5 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<script src="<?php $options->adminStaticUrl('js', 'purify.js'); ?>"></script>
<script>
(function () {
$(document).ready(function () {

View File

@ -16,9 +16,9 @@ include 'menu.php';
<li><a class="operate-delete" href="<?php $options->adminUrl('profile.php#change-password'); ?>"><?php _e('强烈建议更改你的默认密码'); ?></a></li>
<?php if($user->pass('contributor', true)): ?>
<li><a href="<?php $options->adminUrl('write-post.php'); ?>"><?php _e('撰写第一篇日志'); ?></a></li>
<li><a href="<?php $options->siteUrl(); ?>"><?php _e('查看我的站点'); ?></a></li>
<li><a href="<?php $options->siteUrl(); ?>"><?php $user->pass('administrator', true) ? _e('查看我的站点') : _e('查看网站'); ?></a></li>
<?php else: ?>
<li><a href="<?php $options->siteUrl(); ?>"><?php _e('查看我的站点'); ?></a></li>
<li><a href="<?php $options->siteUrl(); ?>"><?php _e('查看网站'); ?></a></li>
<?php endif; ?>
</ol>
<p><button type="submit" class="btn primary"><?php _e('让我直接开始使用吧 &raquo;'); ?></button></p>

View File

@ -281,7 +281,7 @@ $(document).ready(function() {
var frame = $('<iframe frameborder="0" class="preview-frame preview-loading"></iframe>')
.attr('src', './preview.php?cid=' + cid)
.attr('sandbox', 'allow-scripts')
.attr('sandbox', 'allow-same-origin allow-scripts')
.appendTo(document.body);
frame.load(function () {

View File

@ -1022,7 +1022,12 @@ function install_step_2_perform()
$error = (new \Typecho\Validate())
->addRule('dbFile', 'required', _t('确认您的配置'))
->addRule('dbFile', function (string $path) {
return !!preg_match("/^(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i", $path);
$pattern = "/^(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i";
if (strstr(PHP_OS, 'WIN'))
{
$pattern = "/(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i";
}
return !!preg_match($pattern, $path);
}, _t('确认您的配置'))
->run($config);
break;

View File

@ -482,7 +482,7 @@ EOF;
*/
public static function filterSearchQuery(?string $query): string
{
return isset($query) ? str_replace('-', ' ', self::slugName($query)) : '';
return isset($query) ? str_replace('-', ' ', self::slugName($query) ?? '') : '';
}
/**
@ -1359,7 +1359,8 @@ EOF;
'ice' => 'x-conference/x-cooltalk',
'vrm' => 'x-world/x-vrml',
'rar' => 'application/x-rar-compressed',
'cab' => 'application/vnd.ms-cab-compressed'
'cab' => 'application/vnd.ms-cab-compressed',
'webp' => 'image/webp'
];
$part = explode('.', $fileName);

View File

@ -27,6 +27,24 @@ class Cookie
*/
private static $path = '/';
/**
* @var string
* @access private
*/
private static $domain = '';
/**
* @var bool
* @access private
*/
private static $secure = false;
/**
* @var bool
* @access private
*/
private static $httponly = false;
/**
* 获取前缀
*
@ -51,6 +69,7 @@ class Cookie
self::$prefix = md5($url);
$parsed = parse_url($url);
self::$domain = $parsed['host'];
/** 在路径后面强制加上斜杠 */
self::$path = empty($parsed['path']) ? '/' : Common::url(null, $parsed['path']);
}
@ -66,6 +85,37 @@ class Cookie
return self::$path;
}
/**
* @access public
* @return string
*/
public static function getDomain(): string
{
return self::$domain;
}
/**
* @access public
* @return bool
*/
public static function getSecure(): bool
{
return self::$secure ?: false;
}
/**
* 设置额外的选项
*
* @param array $options
* @return void
*/
public static function setOptions(array $options)
{
self::$domain = $options['domain'] ?: self::$domain;
self::$secure = $options['secure'] ? (bool) $options['secure'] : false;
self::$httponly = $options['httponly'] ? (bool) $options['httponly'] : false;
}
/**
* 获取指定的COOKIE值
*
@ -91,7 +141,7 @@ class Cookie
{
$key = self::$prefix . $key;
$_COOKIE[$key] = $value;
Response::getInstance()->setCookie($key, $value, $expire, self::$path);
Response::getInstance()->setCookie($key, $value, $expire, self::$path, self::$domain, self::$secure, self::$httponly);
}
/**
@ -106,7 +156,7 @@ class Cookie
return;
}
Response::getInstance()->setCookie($key, '', -1, self::$path);
Response::getInstance()->setCookie($key, '', -1, self::$path, self::$domain, self::$secure, self::$httponly);
unset($_COOKIE[$key]);
}
}

View File

@ -234,7 +234,7 @@ xmlns:dc="http://purl.org/dc/elements/1.1/">' . self::EOL;
$result .= '<channel rdf:about="' . $this->feedUrl . '">
<title>' . htmlspecialchars($this->title) . '</title>
<link>' . $this->baseUrl . '</link>
<description>' . htmlspecialchars($this->subTitle) . '</description>
<description>' . htmlspecialchars($this->subTitle ?? '') . '</description>
<items>
<rdf:Seq>' . self::EOL;
@ -310,7 +310,7 @@ xmlns:wfw="http://wellformedweb.org/CommentAPI/">
<link>' . $this->baseUrl . '</link>
<atom:link href="' . $this->feedUrl . '" rel="self" type="application/rss+xml" />
<language>' . $this->lang . '</language>
<description>' . htmlspecialchars($this->subTitle) . '</description>
<description>' . htmlspecialchars($this->subTitle ?? '') . '</description>
<lastBuildDate>' . $this->dateFormat($lastUpdate) . '</lastBuildDate>
<pubDate>' . $this->dateFormat($lastUpdate) . '</pubDate>' . self::EOL;
@ -380,7 +380,7 @@ xml:base="' . $this->baseUrl . '"
}
$result .= '<title type="text">' . htmlspecialchars($this->title) . '</title>
<subtitle type="text">' . htmlspecialchars($this->subTitle) . '</subtitle>
<subtitle type="text">' . htmlspecialchars($this->subTitle ?? '') . '</subtitle>
<updated>' . $this->dateFormat($lastUpdate) . '</updated>
<generator uri="http://typecho.org/" version="' . $this->version . '">Typecho</generator>
<link rel="alternate" type="text/html" href="' . $this->baseUrl . '" />

View File

@ -430,6 +430,7 @@ class Request
public function isSecure(): bool
{
return (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && !strcasecmp('https', $_SERVER['HTTP_X_FORWARDED_PROTO']))
|| (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && !strcasecmp('quic', $_SERVER['HTTP_X_FORWARDED_PROTO']))
|| (!empty($_SERVER['HTTP_X_FORWARDED_PORT']) && 443 == $_SERVER['HTTP_X_FORWARDED_PORT'])
|| (!empty($_SERVER['HTTPS']) && 'off' != strtolower($_SERVER['HTTPS']))
|| (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT'])

View File

@ -200,7 +200,7 @@ class Response
// set cookie
foreach ($this->cookies as $cookie) {
[$key, $value, $timeout, $path, $domain] = $cookie;
[$key, $value, $timeout, $path, $domain, $secure, $httponly] = $cookie;
if ($timeout > 0) {
$now = time();
@ -209,7 +209,7 @@ class Response
$timeout = 1;
}
setrawcookie($key, rawurlencode($value), $timeout, $path, $domain ?? '');
setrawcookie($key, rawurlencode($value), $timeout, $path, $domain, $secure, $httponly);
}
}
@ -275,6 +275,8 @@ class Response
* @param integer $timeout 过期时间,默认为0,表示随会话时间结束
* @param string $path 路径信息
* @param string|null $domain 域名信息
* @param bool $secure 是否仅可通过安全的 HTTPS 连接传给客户端
* @param bool $httponly 是否仅可通过 HTTP 协议访问
* @return $this
*/
public function setCookie(
@ -282,10 +284,12 @@ class Response
$value,
int $timeout = 0,
string $path = '/',
string $domain = null
string $domain = '',
bool $secure = false,
bool $httponly = false
): Response {
if (!$this->sandbox) {
$this->cookies[] = [$key, $value, $timeout, $path, $domain];
$this->cookies[] = [$key, $value, $timeout, $path, $domain, $secure, $httponly];
}
return $this;

View File

@ -3,6 +3,7 @@
namespace Typecho\Widget\Helper;
use Typecho\Cookie;
use Typecho\Request;
use Typecho\Validate;
use Typecho\Widget\Helper\Form\Element;
@ -130,13 +131,7 @@ class Form extends Layout
*/
public function getAllRequest(): array
{
$result = [];
$source = (self::POST_METHOD == $this->getAttribute('method')) ? $_POST : $_GET;
foreach ($this->inputs as $name => $input) {
$result[$name] = $source[$name] ?? null;
}
return $result;
return $this->getParams(array_keys($this->inputs));
}
/**
@ -204,10 +199,10 @@ class Form extends Layout
public function getParams(array $params): array
{
$result = [];
$source = (self::POST_METHOD == $this->getAttribute('method')) ? $_POST : $_GET;
$request = Request::getInstance();
foreach ($params as $param) {
$result[$param] = $source[$param] ?? null;
$result[$param] = $request->get($param, is_array($this->getInput($param)->value) ? [] : null);
}
return $result;

View File

@ -59,7 +59,7 @@ class Helper
$key = $keys[$table];
$db = Db::get();
$widget = Widget::widget($className);
$widget = Widget::widget($className . '@' . $pkId);
$db->fetchRow(
$widget->select()->where("{$key} = ?", $pkId)->limit(1),

View File

@ -943,8 +943,8 @@ class Archive extends Contents
{
$rules = [];
$allows = [
'description' => htmlspecialchars($this->description),
'keywords' => htmlspecialchars($this->keywords),
'description' => htmlspecialchars($this->description ?? ''),
'keywords' => htmlspecialchars($this->keywords ?? ''),
'generator' => $this->options->generator,
'template' => $this->options->theme,
'pingback' => $this->options->xmlRpcUrl,
@ -1209,7 +1209,7 @@ class Archive extends Contents
*/
public function keywords(string $split = ',', string $default = '')
{
echo empty($this->keywords) ? $default : str_replace(',', $split, htmlspecialchars($this->keywords));
echo empty($this->keywords) ? $default : str_replace(',', $split, htmlspecialchars($this->keywords ?? ''));
}
/**

View File

@ -189,7 +189,12 @@ class Backup extends BaseOptions implements ActionInterface
if (!empty($_FILES)) {
$file = array_pop($_FILES);
if (0 == $file['error'] && is_uploaded_file($file['tmp_name'])) {
if(UPLOAD_ERR_NO_FILE == $file['error']) {
Notice::alloc()->set(_t('没有选择任何备份文件'), 'error');
$this->response->goBack();
}
if (UPLOAD_ERR_OK == $file['error'] && is_uploaded_file($file['tmp_name'])) {
$path = $file['tmp_name'];
} else {
Notice::alloc()->set(_t('备份文件上传失败'), 'error');
@ -270,7 +275,7 @@ class Backup extends BaseOptions implements ActionInterface
}
// 针对PGSQL重置计数
if (false !== strpos($this->db->getVersion(), 'pgsql')) {
if (false !== strpos(strtolower($this->db->getAdapterName()), 'pgsql')) {
foreach ($this->lastIds as $table => $id) {
$seq = $this->db->getPrefix() . $table . '_seq';
$this->db->query('ALTER SEQUENCE ' . $seq . ' RESTART WITH ' . ($id + 1));

View File

@ -289,7 +289,7 @@ class Comments extends Base implements QueryInterface
Comments::pluginHandle()->trigger($plugged)->gravatar($size, $rating, $default, $this);
if (!$plugged) {
$url = Common::gravatarUrl($this->mail, $size, $rating, $default, $this->request->isSecure());
echo '<img class="avatar" src="' . $url . '" alt="' .
echo '<img class="avatar" loading="lazy" src="' . $url . '" alt="' .
$this->author . '" width="' . $size . '" height="' . $size . '" />';
}
}

View File

@ -555,7 +555,7 @@ class Contents extends Base implements QueryInterface
//增加数据信息
$value['attachment'] = new Config($content);
$value['attachment']->isImage = in_array($content['type'], ['jpg', 'jpeg', 'gif', 'png', 'tiff', 'bmp']);
$value['attachment']->isImage = in_array($content['type'], ['jpg', 'jpeg', 'gif', 'png', 'tiff', 'bmp', 'webp', 'avif']);
$value['attachment']->url = Upload::attachmentHandle($value);
if ($value['attachment']->isImage) {
@ -940,7 +940,7 @@ class Contents extends Base implements QueryInterface
{
$html = Contents::pluginHandle()->trigger($parsed)->autoP($text);
if (!$parsed) {
if (!$parsed && $text) {
static $parser;
if (empty($parser)) {

View File

@ -405,7 +405,7 @@ class Edit extends Contents implements ActionInterface
$realId = 0;
/** 是否是从草稿状态发布 */
$isDraftToPublish = ('post_draft' == $this->type);
$isDraftToPublish = ('post_draft' == $this->type || 'page_draft' == $this->type);
$isBeforePublish = ('publish' == $this->status);
$isAfterPublish = ('publish' == $contents['status']);

View File

@ -93,7 +93,10 @@ class Init extends Widget
}
/** cookie初始化 */
Cookie::setPrefix($options->rootUrl);
Cookie::setPrefix($options->rootUrl);
if (defined('__TYPECHO_COOKIE_OPTIONS__')) {
Cookie::setOptions(__TYPECHO_COOKIE_OPTIONS__);
}
/** 初始化路由器 */
Router::setRoutes($options->routingTable);

View File

@ -261,18 +261,18 @@ class Options extends Base
*
* @param string|null $path 子路径
* @param string|null $theme 模版名称
* @return string
* @return string | void
*/
public function themeUrl(?string $path = null, ?string $theme = null): string
public function themeUrl(?string $path = null, ?string $theme = null)
{
if (empty($theme)) {
if (!isset($theme)) {
echo Common::url($path, $this->themeUrl);
} else {
$url = defined('__TYPECHO_THEME_URL__') ? __TYPECHO_THEME_URL__ :
Common::url(__TYPECHO_THEME_DIR__ . '/' . $theme, $this->siteUrl);
return isset($path) ? Common::url($path, $url) : $url;
}
$url = defined('__TYPECHO_THEME_URL__') ? __TYPECHO_THEME_URL__ :
Common::url(__TYPECHO_THEME_DIR__ . '/' . $theme, $this->siteUrl);
return Common::url($path, $url);
}
/**
@ -482,8 +482,7 @@ class Options extends Base
*/
protected function ___themeUrl(): string
{
return defined('__TYPECHO_THEME_URL__') ? __TYPECHO_THEME_URL__ :
Common::url(__TYPECHO_THEME_DIR__ . '/' . $this->theme, $this->siteUrl);
return $this->themeUrl(null, $this->theme);
}
/**
@ -671,7 +670,7 @@ class Options extends Base
$attachmentTypes = str_replace(
['@image@', '@media@', '@doc@'],
[
'gif,jpg,jpeg,png,tiff,bmp', 'mp3,mp4,mov,wmv,wma,rmvb,rm,avi,flv,ogg,oga,ogv',
'gif,jpg,jpeg,png,tiff,bmp,webp', 'mp3,mp4,mov,wmv,wma,rmvb,rm,avi,flv,ogg,oga,ogv',
'txt,doc,docx,xls,xlsx,ppt,pptx,zip,rar,pdf'
],
$this->attachmentTypes

View File

@ -272,7 +272,7 @@ class General extends Options implements ActionInterface
}
$attachmentTypesOptions = [
'@image@' => _t('图片文件') . ' <code>(gif jpg jpeg png tiff bmp)</code>',
'@image@' => _t('图片文件') . ' <code>(gif jpg jpeg png tiff bmp webp avif)</code>',
'@media@' => _t('多媒体文件') . ' <code>(mp3 mp4 mov wmv wma rmvb rm avi flv ogg oga ogv)</code>',
'@doc@' => _t('常用档案文件') . ' <code>(txt doc docx xls xlsx ppt pptx zip rar pdf)</code>',
'@other@' => _t(

View File

@ -238,7 +238,7 @@ class Stat extends Base
}
/**
* 获取当前用户显示的评论数目
* 获取当前用户待审核的评论数目
*
* @return integer
*/
@ -251,7 +251,7 @@ class Stat extends Base
}
/**
* 获取当前用户显示的评论数目
* 获取当前用户垃圾评论数目
*
* @return integer
*/
@ -289,7 +289,7 @@ class Stat extends Base
}
/**
* 获取当前文章显示的评论数目
* 获取当前文章待审核的评论数目
*
* @return integer
*/
@ -302,7 +302,7 @@ class Stat extends Base
}
/**
* 获取当前文章显示的评论数目
* 获取当前文章垃圾评论数目
*
* @return integer
*/

View File

@ -46,6 +46,8 @@ class Edit extends Options implements ActionInterface
$this->update(['value' => 'recent'], $this->db->sql()->where('name = ?', 'frontPage'));
}
$this->options->themeUrl = $this->options->themeUrl(null, $theme);
$configFile = $this->options->themeFile($theme, 'functions.php');
if (file_exists($configFile)) {

View File

@ -45,7 +45,7 @@ class Rows extends Widget
}
$screen = array_filter(glob($theme . '/*'), function ($path) {
return preg_match("/screenshot\.(jpg|png|gif|bmp|jpeg)$/i", $path);
return preg_match("/screenshot\.(jpg|png|gif|bmp|jpeg|webp|avif)$/i", $path);
});
if ($screen) {

View File

@ -463,7 +463,6 @@ class XmlRpc extends Contents implements ActionInterface, Hook
*/
public function wpNewCategory(int $blogId, string $userName, string $password, array $category): int
{
/** 开始接受数据 */
$input['name'] = $category['name'];
$input['slug'] = Common::slugName(empty($category['slug']) ? $category['name'] : $category['slug']);
@ -474,6 +473,11 @@ class XmlRpc extends Contents implements ActionInterface, Hook
$categoryWidget = CategoryEdit::alloc(null, $input, function (CategoryEdit $category) {
$category->insertCategory();
});
if (!$categoryWidget->have()) {
throw new Exception(_t('分类不存在'), 404);
}
return $categoryWidget->mid;
}
@ -1833,7 +1837,7 @@ EOF;
'wp.suggestCategories' => [$this, 'wpSuggestCategories'],
'wp.uploadFile' => [$this, 'mwNewMediaObject'],
/** New Wordpress API since 2.9.2 */
/** New WordPress API since 2.9.2 */
'wp.getUsersBlogs' => [$this, 'wpGetUsersBlogs'],
'wp.getTags' => [$this, 'wpGetTags'],
'wp.deleteCategory' => [$this, 'wpDeleteCategory'],