diff --git a/README.md b/README.md index 676994f..6772421 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ Contest data is provided by [OI-contest-fetch](https://github.com/hanyixuanten/O ## Features - Adds an **Upcoming OI Contests** widget to the WordPress dashboard. -- Provides the `[oi_contest_schedule]` shortcode for posts and pages. +- Provides an **OI Contest Schedule** block for posts and pages. +- Keeps the `[oi_contest_schedule]` shortcode available for compatibility and templates. - Shows contest platform, title, start and end times, and a live countdown. - Identifies contests that are currently running. - Supports responsive and compact layouts. @@ -37,9 +38,15 @@ Contest data is provided by [OI-contest-fetch](https://github.com/hanyixuanten/O After activation, the dashboard widget appears automatically on **Dashboard > Home**. +## Editor Block + +In the post or page editor, select **Add block**, search for **OI Contest Schedule**, and insert the block. Use the block settings sidebar to choose how many contests to display (1-50) and whether to use the compact layout. + +The block is rendered dynamically, so contest data remains current without editing the post. + ## Shortcode -Add a Shortcode block to a post or page and use: +For classic editors or templates, the shortcode remains available: ```text [oi_contest_schedule] diff --git a/README_zh.md b/README_zh.md index 9e92c33..7ab5f42 100644 --- a/README_zh.md +++ b/README_zh.md @@ -9,7 +9,8 @@ OI Contest Schedule 是一款轻量级 WordPress 插件,可在 WordPress 仪 ## 功能特性 - 在 WordPress 仪表盘中添加“即将到来的 OI 赛事”小组件。 -- 提供 `[oi_contest_schedule]` 短代码,可插入文章或页面。 +- 提供“**OI 赛事日程**”区块,可直接插入文章或页面。 +- 保留 `[oi_contest_schedule]` 短代码,兼容经典编辑器和模板。 - 展示比赛平台、标题、开始和结束时间,以及实时倒计时。 - 自动标记正在进行的比赛。 - 支持响应式布局和紧凑布局。 @@ -37,9 +38,15 @@ OI Contest Schedule 是一款轻量级 WordPress 插件,可在 WordPress 仪 启用后,赛事小组件会自动显示在 **仪表盘 > 首页** 中。 +## 编辑器区块 + +在文章或页面编辑器中点击“**添加区块**”,搜索“**OI 赛事日程**”并插入。在区块设置侧栏中可以选择显示的赛事数量(1-50),也可以启用紧凑布局。 + +该区块使用动态渲染,无需重新编辑文章即可显示最新赛事数据。 + ## 短代码 -在文章或页面中添加“短代码”区块,然后输入: +经典编辑器或模板仍可使用以下短代码: ```text [oi_contest_schedule] diff --git a/assets/js/schedule-editor.js b/assets/js/schedule-editor.js new file mode 100644 index 0000000..1296edb --- /dev/null +++ b/assets/js/schedule-editor.js @@ -0,0 +1,65 @@ +( function ( blocks, blockEditor, components, element, ServerSideRender ) { + 'use strict'; + + var createElement = element.createElement; + var InspectorControls = blockEditor.InspectorControls; + var PanelBody = components.PanelBody; + var RangeControl = components.RangeControl; + var ToggleControl = components.ToggleControl; + var strings = window.oicsScheduleEditorL10n; + + blocks.registerBlockType( 'oics/contest-schedule', { + apiVersion: 2, + title: strings.title, + description: strings.description, + icon: 'calendar-alt', + category: 'widgets', + attributes: { + limit: { + type: 'number', + default: 10 + }, + compact: { + type: 'boolean', + default: false + } + }, + edit: function ( props ) { + return createElement( + element.Fragment, + null, + createElement( + InspectorControls, + null, + createElement( + PanelBody, + { title: strings.settings }, + createElement( RangeControl, { + label: strings.limit, + value: props.attributes.limit, + min: 1, + max: 50, + onChange: function ( value ) { + props.setAttributes( { limit: value } ); + } + } ), + createElement( ToggleControl, { + label: strings.compact, + checked: props.attributes.compact, + onChange: function ( value ) { + props.setAttributes( { compact: value } ); + } + } ) + ) + ), + createElement( ServerSideRender, { + block: 'oics/contest-schedule', + attributes: props.attributes + } ) + ); + }, + save: function () { + return null; + } + } ); +} )( window.wp.blocks, window.wp.blockEditor, window.wp.components, window.wp.element, window.wp.serverSideRender ); \ No newline at end of file diff --git a/build.sh b/build.sh index 9fc7e9e..fc3fa74 100755 --- a/build.sh +++ b/build.sh @@ -58,6 +58,7 @@ build() { unzip -Z1 "${archive_path}" | grep -q "^${plugin_slug}/includes/class-schedule-renderer.php$" unzip -Z1 "${archive_path}" | grep -q "^${plugin_slug}/assets/css/schedule.css$" unzip -Z1 "${archive_path}" | grep -q "^${plugin_slug}/assets/js/schedule.js$" + unzip -Z1 "${archive_path}" | grep -q "^${plugin_slug}/assets/js/schedule-editor.js$" if unzip -Z1 "${archive_path}" | grep -Eq '/README(\.zh-CN)?\.md$'; then printf 'Unexpected development README found in archive.\n' >&2 exit 1 diff --git a/includes/class-plugin.php b/includes/class-plugin.php index 4c4f4b5..a2595e3 100644 --- a/includes/class-plugin.php +++ b/includes/class-plugin.php @@ -17,12 +17,56 @@ final class OICS_Plugin { private function __construct() { $this->renderer = new OICS_Schedule_Renderer( new OICS_Contest_Client() ); + add_action( 'init', array( $this, 'register_block' ) ); add_action( 'wp_dashboard_setup', array( $this, 'register_dashboard_widget' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_assets' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) ); add_shortcode( 'oi_contest_schedule', array( $this, 'render_shortcode' ) ); } + public function register_block() { + $this->register_assets(); + wp_register_script( + 'oics-schedule-editor', + OICS_URL . 'assets/js/schedule-editor.js', + array( 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-server-side-render' ), + OICS_VERSION, + true + ); + wp_localize_script( + 'oics-schedule-editor', + 'oicsScheduleEditorL10n', + array( + 'title' => __( 'OI Contest Schedule', 'oi-contest-schedule' ), + 'description' => __( 'Display upcoming OI contests with local times and live countdowns.', 'oi-contest-schedule' ), + 'settings' => __( 'Schedule settings', 'oi-contest-schedule' ), + 'limit' => __( 'Number of contests', 'oi-contest-schedule' ), + 'compact' => __( 'Compact layout', 'oi-contest-schedule' ), + ) + ); + + register_block_type( + 'oics/contest-schedule', + array( + 'api_version' => 2, + 'editor_script' => 'oics-schedule-editor', + 'editor_style' => 'oics-schedule', + 'style' => 'oics-schedule', + 'attributes' => array( + 'limit' => array( + 'type' => 'number', + 'default' => 10, + ), + 'compact' => array( + 'type' => 'boolean', + 'default' => false, + ), + ), + 'render_callback' => array( $this, 'render_block' ), + ) + ); + } + private function register_assets() { wp_register_style( 'oics-schedule', OICS_URL . 'assets/css/schedule.css', array(), OICS_VERSION ); wp_register_script( 'oics-schedule', OICS_URL . 'assets/js/schedule.js', array(), OICS_VERSION, true ); @@ -42,7 +86,7 @@ final class OICS_Plugin { public function enqueue_frontend_assets() { $post = get_post(); - if ( ! $post || ! has_shortcode( $post->post_content, 'oi_contest_schedule' ) ) { + if ( ! $post || ( ! has_shortcode( $post->post_content, 'oi_contest_schedule' ) && ! has_block( 'oics/contest-schedule', $post ) ) ) { return; } @@ -90,4 +134,11 @@ final class OICS_Plugin { return $this->renderer->render( $limit, $compact ); } + + public function render_block( $attributes ) { + $limit = isset( $attributes['limit'] ) ? min( 50, max( 1, absint( $attributes['limit'] ) ) ) : 10; + $compact = ! empty( $attributes['compact'] ); + + return $this->renderer->render( $limit, $compact ); + } } \ No newline at end of file diff --git a/languages/oi-contest-schedule-zh_CN.po b/languages/oi-contest-schedule-zh_CN.po index 30bfb09..6234116 100644 --- a/languages/oi-contest-schedule-zh_CN.po +++ b/languages/oi-contest-schedule-zh_CN.po @@ -16,6 +16,21 @@ msgstr "" msgid "Upcoming OI Contests" msgstr "即将到来的 OI 赛事" +msgid "OI Contest Schedule" +msgstr "OI 赛事日程" + +msgid "Display upcoming OI contests with local times and live countdowns." +msgstr "显示即将到来的 OI 赛事、本地时间和实时倒计时。" + +msgid "Schedule settings" +msgstr "日程设置" + +msgid "Number of contests" +msgstr "赛事数量" + +msgid "Compact layout" +msgstr "紧凑布局" + msgid "Running" msgstr "进行中" diff --git a/languages/oi-contest-schedule.pot b/languages/oi-contest-schedule.pot index 4fee4d4..c088a1c 100644 --- a/languages/oi-contest-schedule.pot +++ b/languages/oi-contest-schedule.pot @@ -11,6 +11,21 @@ msgstr "" msgid "Upcoming OI Contests" msgstr "" +msgid "OI Contest Schedule" +msgstr "" + +msgid "Display upcoming OI contests with local times and live countdowns." +msgstr "" + +msgid "Schedule settings" +msgstr "" + +msgid "Number of contests" +msgstr "" + +msgid "Compact layout" +msgstr "" + msgid "Running" msgstr "" diff --git a/oi-contest-schedule.php b/oi-contest-schedule.php index b7fd420..3f4d5b1 100644 --- a/oi-contest-schedule.php +++ b/oi-contest-schedule.php @@ -2,7 +2,7 @@ /** * Plugin Name: OI Contest Schedule * Plugin URI: https://github.com/hanyixuanten/oi-contest-schedule - * Description: Display upcoming OI contests in a dashboard widget or on any page with a shortcode. + * Description: Display upcoming OI contests in a dashboard widget or with an editor block. * Version: 0.1.0 * Requires at least: 6.4 * Requires PHP: 7.4 diff --git a/readme.txt b/readme.txt index e1e2da9..ab5169c 100644 --- a/readme.txt +++ b/readme.txt @@ -1,6 +1,6 @@ === OI Contest Schedule === Contributors: hanyixuanten -Tags: contest, schedule, shortcode, dashboard, competitive programming +Tags: contest, schedule, block, dashboard, competitive programming Requires at least: 6.4 Tested up to: 6.9 Requires PHP: 7.4 @@ -8,13 +8,13 @@ Stable tag: 0.1.0 License: GPL-3.0-only License URI: https://www.gnu.org/licenses/gpl-3.0.html -Display upcoming OI and competitive programming contests in the WordPress dashboard or on any page with a shortcode. +Display upcoming OI and competitive programming contests in the WordPress dashboard or with an editor block. == Description == OI Contest Schedule displays upcoming competitive programming contests with local times and live countdowns. -The plugin adds an **Upcoming OI Contests** widget to the WordPress dashboard. To display the schedule on the front end, add the `[oi_contest_schedule]` shortcode to a post, page, or Shortcode block. +The plugin adds an **Upcoming OI Contests** widget to the WordPress dashboard. To display the schedule on the front end, add the **OI Contest Schedule** block to a post or page. Features include: @@ -25,9 +25,13 @@ Features include: * A five-minute cache using the WordPress Transients API. * English and Simplified Chinese translations. += Block settings = + +Add the **OI Contest Schedule** block from the block inserter. Its settings sidebar lets you display between 1 and 50 contests and enable the compact layout. The block is rendered dynamically so it always uses current contest data. + = Shortcode options = -The default shortcode displays up to 10 contests: +The shortcode remains available for classic editors and templates. By default it displays up to 10 contests: `[oi_contest_schedule]` @@ -44,7 +48,7 @@ Set `compact` to `true` to use the compact layout: 1. Upload the `oi-contest-schedule` directory to `/wp-content/plugins/`, or install the plugin ZIP through the WordPress Plugins screen. 2. Activate **OI Contest Schedule** through the Plugins screen. 3. Open the WordPress dashboard to see the contest widget. -4. To show the schedule on the front end, insert `[oi_contest_schedule]` into a post or page. +4. To show the schedule on the front end, add the **OI Contest Schedule** block to a post or page. == Frequently Asked Questions == @@ -86,6 +90,7 @@ Service and data source: = 0.1.0 = * Added the upcoming contest dashboard widget. +* Added the **OI Contest Schedule** editor block with limit and compact layout settings. * Added the `[oi_contest_schedule]` shortcode with `limit` and `compact` options. * Added visitor-local time formatting and live countdowns. * Added platform styling and responsive layouts.