Compare commits

..

No commits in common. "stable" and "v1.2.0" have entirely different histories.

32 changed files with 374 additions and 547 deletions

View File

@ -2,7 +2,6 @@
/.github
/assets
/bin
/dist
/node_modules
/tests
/vendor

View File

@ -8,17 +8,17 @@ steps:
commands:
- composer install --ignore-platform-req=php
- name: lint-php
image: php:8.2
image: php:7.4
commands:
- ./vendor/bin/phpcs
depends_on:
- composer-install
- name: node-install
image: node:22
image: node:16
commands:
- npm install
- name: lint-assets
image: node:22
image: node:16
commands:
- npx eslint scripts/block.js
- npx eslint scripts/liveticker.js
@ -26,3 +26,4 @@ steps:
- npx stylelint styles/liveticker.css
depends_on:
- node-install

1
.gitattributes vendored
View File

@ -11,7 +11,6 @@
/composer.json export-ignore
/composer.lock export-ignore
/CONTRIBUTING.md export-ignore
/dist export-ignore
/package.json export-ignore
/package-lock.json export-ignore
/phpcs.xml export-ignore

View File

@ -6,33 +6,20 @@ jobs:
strategy:
matrix:
include:
- php: '8.3'
wordpress: '6.6'
- php: '8.2'
wordpress: '6.4'
- php: '8.1'
wordpress: '6.2'
- php: '8.0'
wordpress: '6.0'
- php: '7.4'
wordpress: '5.9'
wordpress: '5.8'
- php: '5.6'
wordpress: '4.7'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install SVN
run: |
if ! command -v svn > /dev/null; then
sudo apt-get update
sudo apt-get install -y subversion
fi
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: xdebug
tools: composer
- name: Setup DB
run: sudo sudo systemctl start mysql.service
run: sudo /etc/init.d/mysql start
- name: Setup WP
run: bash bin/install-wp-tests.sh wordpress root root localhost "${{ matrix.wordpress }}"
- name: Install
@ -44,16 +31,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
php-version: '7.4'
tools: composer
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v2
with:
node-version: '22'
node-version: '14'
- name: Install
run: |
composer install --no-interaction
@ -68,12 +55,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Analyze with SonarCloud
if: env.SONAR_TOKEN != ''
uses: sonarsource/sonarcloud-github-action@v3
uses: sonarsource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

View File

@ -9,11 +9,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
php-version: '7.4'
tools: composer
- name: Install
run: composer install --no-interaction

View File

@ -1,23 +0,0 @@
name: Plugin check
on:
push:
branches: [ 'stable', 'release/*' ]
pull_request:
branches: [ 'stable' ]
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Package plugin
run: |
mkdir -p ./dist
tail -n +7 README.md > README.md.tmp && mv README.md.tmp README.md
rsync -rc --exclude-from=.distignore ./ ./dist/stklcode-liveticker --delete --delete-excluded
- name: Check WP plugin
uses: wordpress/plugin-check-action@v1
with:
build-dir: ./dist/stklcode-liveticker

View File

@ -10,11 +10,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
php-version: '7.4'
tools: composer
- name: Install
run: composer install --no-interaction

View File

@ -6,14 +6,14 @@
# Liveticker (by stklcode)
* Contributors: stklcode
* Contributors: Stefan Kalscheuer
* Tags: liveticker, feed, rss
* Requires at least: 5.0
* Tested up to: 6.7
* Requires PHP: 7.2
* Stable tag: 1.3.0
* Requires at least: 4.7
* Tested up to: 5.8
* Requires PHP: 5.6
* Stable tag: 1.2.0
* License: GPLv2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* License URI: http://www.gnu.org/licenses/gpl-2.0.html
A simple ajaxified liveticker plugin for WordPress.
@ -42,8 +42,8 @@ Alternatively you can also use _Copmposer_.
### Requirements ###
* PHP 7.2 or above
* WordPress 5.0 or above
* PHP 5.6 or above
* WordPress 4.7 or above
## Frequently asked questions
@ -80,26 +80,6 @@ caching time of 12 hours obviously makes no sense.
## Changelog
### 1.3.0 - 2025-03-10
* Requires at least PHP 7.2 and WordPress 5.0
* Sorting direction can now be changed for liveticker blocks
### 1.2.3 - 2025-02-04
* Escape ticker ID in shortcode output
* Tested with WP 6.7
### 1.2.2 - 2024-03-02
* Update use of deprecated WP core functions
* Extend output sanitization
* Tested with WP 6.4
### 1.2.1 - 2022-02-01
* Fix issue with limit in Gutenberg block.
### 1.2.0 - 2022-01-23
* Requires WordPress 4.7 or above

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -22,17 +22,6 @@ download() {
curl -s "$1" > "$2";
elif [ `which wget` ]; then
wget -nv -O "$2" "$1"
else
echo "Error: Neither curl nor wget is installed."
exit 1
fi
}
# Check if svn is installed
check_svn_installed() {
if ! command -v svn > /dev/null; then
echo "Error: svn is not installed. Please install svn and try again."
exit 1
fi
}
@ -75,7 +64,6 @@ install_wp() {
if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
mkdir -p $TMPDIR/wordpress-trunk
rm -rf $TMPDIR/wordpress-trunk/*
check_svn_installed
svn export --quiet https://core.svn.wordpress.org/trunk $TMPDIR/wordpress-trunk/wordpress
mv $TMPDIR/wordpress-trunk/wordpress/* $WP_CORE_DIR
else
@ -104,7 +92,7 @@ install_wp() {
tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR
fi
download https://raw.githubusercontent.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
}
install_test_suite() {
@ -120,7 +108,6 @@ install_test_suite() {
# set up testing suite
mkdir -p $WP_TESTS_DIR
rm -rf $WP_TESTS_DIR/{includes,data}
check_svn_installed
svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data
fi

View File

@ -1,6 +1,6 @@
{
"name": "stklcode/stklcode-liveticker",
"version": "1.3.0",
"version": "1.2.0",
"description": "A simple Liveticker for Wordpress.",
"keywords": [
"wordpress",
@ -17,17 +17,18 @@
],
"type": "wordpress-plugin",
"require": {
"php": ">=7.2",
"composer/installers": "~v2.3.0"
"php": ">=5.6",
"composer/installers": "~1.12"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^v1.0",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7",
"matthiasmullie/minify": "^1.3",
"phpcompatibility/phpcompatibility-wp": "^2.1",
"phpunit/phpunit": "^5|^6|^7",
"slowprog/composer-copy-file": "~0.3",
"squizlabs/php_codesniffer": "^3.11",
"wp-coding-standards/wpcs": "^3.1",
"yoast/wp-test-utils": "^1.2"
"squizlabs/php_codesniffer": "^3.6",
"wp-coding-standards/wpcs": "^2.3",
"yoast/phpunit-polyfills": "^1.0"
},
"scripts": {
"post-install-cmd": [
@ -64,11 +65,5 @@
"minifyjs scripts/block.js > scripts/block.min.js",
"minifyjs scripts/liveticker.js > scripts/liveticker.min.js"
]
},
"config": {
"allow-plugins": {
"composer/installers": true,
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}

View File

@ -23,7 +23,7 @@ class Admin extends SCLiveticker {
*
* @return void
*/
public static function dashboard_right_now(): void {
public static function dashboard_right_now() {
$total_files = wp_count_posts( 'scliveticker_tick' );
echo '<tr>';
@ -37,24 +37,231 @@ class Admin extends SCLiveticker {
*
* @return void
*/
public static function register_settings_page(): void {
public static function register_settings_page() {
add_submenu_page(
'edit.php?post_type=scliveticker_tick',
'Liveticker ' . __( 'Settings', 'stklcode-liveticker' ),
__( 'Settings', 'stklcode-liveticker' ),
'manage_options',
'scliveticker_settings',
array( Settings::class, 'render_settings_page' )
array(
__CLASS__,
'settings_page',
)
);
}
/**
* Register settings API
*
* @return void
*/
public static function register_settings() {
register_setting(
'scliveticker_settings',
self::OPTION,
array( __CLASS__, 'validate_settings' )
);
// Form sections.
add_settings_section(
'scliveticker_settings_general',
__( 'General', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_general_section' ),
'scliveticker-settings-page'
);
// Form fields.
add_settings_field(
'enable_ajax',
__( 'Use AJAX', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_enable_ajax_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-enable-ajax' )
);
add_settings_field(
'poll_interval',
__( 'AJAX poll interval', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_poll_interval_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-poll-interval' )
);
add_settings_field(
'enable_css',
__( 'Default CSS Styles', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_enable_css_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-enable-css' )
);
add_settings_field(
'show_feed',
__( 'Show RSS feed', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_show_feed_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-show-feed' )
);
add_settings_field(
'enable_shortcode',
__( 'Shortcode support', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_enable_shortcode_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-enable-shortcode' )
);
add_settings_field(
'embedded_script',
__( 'Embedded JavaScript', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_embedded_script_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-embedded-script' )
);
}
/**
* Render general section.
*
* @return void
*/
public static function settings_general_section() {
}
/**
* Render uninstall section.
*
* @return void
*/
public static function settings_uninstall_section() {
}
/**
* Render enable AJAX field.
*
* @return void
*/
public static function settings_enable_ajax_field() {
$checked = self::$options['enable_ajax'];
echo '<input id="' . esc_attr( self::OPTION ) . '-enable-ajax" type="checkbox" name="' . esc_attr( self::OPTION ) . '[enable_ajax]" value="1" ' . checked( $checked, 1, false ) . '> ';
esc_html_e( 'Enable', 'stklcode-liveticker' );
echo '<p class="description">' . esc_html__( 'Disable this option to not use AJAX update. This means all liveticker widgets and shortcodes are only updated once on site load.', 'stklcode-liveticker' ) . '</p>';
}
/**
* Render AJAX poll interval field.
*
* @return void
*/
public static function settings_poll_interval_field() {
$poll_interval = self::$options['poll_interval'];
echo '<input id="' . esc_attr( self::OPTION ) . '-poll-interval" type="number" name="' . esc_attr( self::OPTION ) . '[poll_interval]" value="' . esc_attr( $poll_interval ) . '"> ';
esc_html_e( 'seconds', 'stklcode-liveticker' );
echo '<p class="description">' . esc_html__( 'Interval (in seconds) to update ticker if AJAX is enabled.', 'stklcode-liveticker' ) . '</p>';
}
/**
* Render enable css field.
*
* @return void
*/
public static function settings_enable_css_field() {
$checked = self::$options['enable_css'];
echo '<input id="' . esc_attr( self::OPTION ) . '-enable-css" type="checkbox" name="' . esc_attr( self::OPTION ) . '[enable_css]" value="1" ' . checked( $checked, 1, false ) . ' /> ';
esc_html_e( 'Enable', 'stklcode-liveticker' );
echo '<p class="description">' . esc_html__( 'Disable this option to remove the default styling CSS file.', 'stklcode-liveticker' ) . '</p>';
}
/**
* Render enable css field.
*
* @return void
*/
public static function settings_show_feed_field() {
$checked = self::$options['show_feed'];
echo '<input id="' . esc_attr( self::OPTION ) . '-show-feed" type="checkbox" name="' . esc_attr( self::OPTION ) . '[show_feed]" value="1" ' . checked( $checked, 1, false ) . ' /> ';
esc_html_e( 'Enable', 'stklcode-liveticker' );
echo '<p class="description">' . esc_html__( 'Can be overwritten in shortcode.', 'stklcode-liveticker' ) . '</p>';
}
/**
* Render enable shortcode field.
*
* @return void
*
* @since 1.2
*/
public static function settings_enable_shortcode_field() {
$checked = self::$options['enable_shortcode'];
echo '<input id="' . esc_attr( self::OPTION ) . '-enable-shortcode" type="checkbox" name="' . esc_attr( self::OPTION ) . '[enable_shortcode]" value="1" ' . checked( $checked, 1, false ) . ' /> ';
esc_html_e( 'Enable', 'stklcode-liveticker' );
echo '<p class="description">' . esc_html__( 'Enable shortcode processing in tick content.', 'stklcode-liveticker' ) . '</p>';
}
/**
* Render embedded script field.
*
* @return void
*
* @since 1.2
*/
public static function settings_embedded_script_field() {
$checked = self::$options['embedded_script'];
echo '<input id="' . esc_attr( self::OPTION ) . '-embedded-script" type="checkbox" name="' . esc_attr( self::OPTION ) . '[embedded_script]" value="1" ' . checked( $checked, 1, false ) . ' /> ';
esc_html_e( 'Enable', 'stklcode-liveticker' );
echo '<p class="description">' . esc_html__( 'Allow embedded script evaluation in tick contents. This might be useful for embedded content, e.g. social media integrations.', 'stklcode-liveticker' ) . '</p>';
}
/**
* Render the settings page.
*
* @return void
*/
public static function settings_page() {
include SCLIVETICKER_DIR . 'views/settings-page.php';
}
/**
* Validate settings callback.
*
* @param array $input Input arguments.
*
* @return array Parsed arguments.
*/
public static function validate_settings( $input ) {
$defaults = self::default_options();
$result['enable_ajax'] = isset( $input['enable_ajax'] ) ? intval( $input['enable_ajax'] ) : 0;
$result['poll_interval'] = isset( $input['poll_interval'] ) ? intval( $input['poll_interval'] ) : $defaults['poll_interval'];
$result['enable_css'] = isset( $input['enable_css'] ) ? intval( $input['enable_css'] ) : 0;
$result['show_feed'] = isset( $input['show_feed'] ) ? intval( $input['show_feed'] ) : 0;
$result['enable_shortcode'] = isset( $input['enable_shortcode'] ) ? intval( $input['enable_shortcode'] ) : 0;
$result['embedded_script'] = isset( $input['embedded_script'] ) ? intval( $input['embedded_script'] ) : 0;
return $result;
}
/**
* Register custom Gutenberg block type.
*
* @return void
* @since 1.1
*/
public static function register_block(): void {
public static function register_block() {
wp_register_script(
'scliveticker-editor',
SCLIVETICKER_BASE . 'scripts/block.min.js',

View File

@ -15,7 +15,6 @@ if ( ! defined( 'ABSPATH' ) ) {
}
use DateTime;
use WP_REST_Request;
/**
* Liveticker.
@ -28,7 +27,7 @@ class Api {
*
* @return void
*/
public static function init(): void {
public static function init() {
// Add rendered modification date to WP_Post object.
register_rest_field(
'scliveticker_tick',
@ -49,11 +48,11 @@ class Api {
* Filter tick queries by ticker slug and date.
*
* @param array $args Query vars.
* @param WP_REST_Request $request The REST request.
* @param \WP_REST_Request $request The REST request.
*
* @return array Filtered query values.
*/
public static function tick_query_filter( array $args, WP_REST_Request $request ): array {
public static function tick_query_filter( $args, $request ) {
// Extract arguments.
$ticker_slug = $request->get_param( 'ticker' );
$limit = intval( $request->get_param( 'limit' ) );

View File

@ -26,7 +26,7 @@ class SCLiveticker {
*
* @var string OPTIONS
*/
const VERSION = '1.3.0';
const VERSION = '1.2.0';
/**
* Options tag.
@ -62,7 +62,7 @@ class SCLiveticker {
*
* @return void
*/
public static function init(): void {
public static function init() {
// Skip on autosave.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
@ -81,7 +81,7 @@ class SCLiveticker {
}
// Load Textdomain.
load_plugin_textdomain( 'stklcode-liveticker' );
load_plugin_textdomain( 'stklcode-liveticker', false );
// Allow shortcodes in widgets.
add_filter( 'widget_text', 'do_shortcode' );
@ -104,7 +104,7 @@ class SCLiveticker {
add_action( 'right_now_content_table_end', array( 'SCLiveticker\\Admin', 'dashboard_right_now' ) );
// Settings.
add_action( 'admin_init', array( 'SCLiveticker\\Settings', 'register_settings' ) );
add_action( 'admin_init', array( 'SCLiveticker\\Admin', 'register_settings' ) );
add_action( 'admin_menu', array( 'SCLiveticker\\Admin', 'register_settings_page' ) );
}
}
@ -114,7 +114,7 @@ class SCLiveticker {
*
* @return void
*/
public static function register_types(): void {
public static function register_types() {
// Add new taxonomy, make it hierarchical (like categories).
$labels = array(
'name' => _x( 'Ticker', 'taxonomy general name', 'stklcode-liveticker' ),
@ -182,7 +182,7 @@ class SCLiveticker {
*
* @return string
*/
public static function shortcode_ticker_show( array $atts ): string {
public static function shortcode_ticker_show( $atts ) {
// Indicate presence of shortcode (to enqueue styles/scripts later).
self::$shortcode_present = true;
@ -232,7 +232,7 @@ class SCLiveticker {
$output = '<div class="wp-block-scliveticker-ticker';
if ( 1 === self::$options['enable_ajax'] ) {
$output .= ' sclt-ajax" '
. 'data-sclt-ticker="' . esc_attr( $ticker ) . '" '
. 'data-sclt-ticker="' . $ticker . '" '
. 'data-sclt-limit="' . $limit . '" '
. 'data-sclt-last="' . $last;
}
@ -242,9 +242,9 @@ class SCLiveticker {
if ( $show_feed ) {
$feed_link = get_post_type_archive_feed_link( 'scliveticker_tick' ) . '';
if ( false === strpos( $feed_link, '&' ) ) {
$feed_link .= '?scliveticker_ticker=' . rawurlencode( $ticker );
$feed_link .= '?scliveticker_ticker=' . $ticker;
} else {
$feed_link .= '&scliveticker_ticker=' . rawurlencode( $ticker );
$feed_link .= '&scliveticker_ticker=' . $ticker;
}
$output .= '<a href="' . esc_attr( $feed_link ) . '">Feed</a>';
}
@ -259,9 +259,9 @@ class SCLiveticker {
* @return void
* @since 1.1 Combined former methods "enqueue_styles" and "enqueue_scripts".
*/
public static function enqueue_resources(): void {
public static function enqueue_resources() {
// Only add if shortcode is present.
if ( self::$shortcode_present || self::$widget_present || has_block( 'scliveticker/ticker' ) ) {
if ( self::$shortcode_present || self::$widget_present || self::block_present() ) {
wp_enqueue_script(
'scliveticker-js',
SCLIVETICKER_BASE . 'scripts/liveticker.min.js',
@ -289,7 +289,8 @@ class SCLiveticker {
'sclt-css',
SCLIVETICKER_BASE . 'styles/liveticker.min.css',
'',
self::VERSION
self::VERSION,
'all'
);
}
}
@ -300,7 +301,7 @@ class SCLiveticker {
*
* @return void
*/
public static function ajax_update(): void {
public static function ajax_update() {
// Verify AJAX nonce.
check_ajax_referer( 'scliveticker_update-ticks' );
@ -393,19 +394,18 @@ class SCLiveticker {
*
* @return void
*/
public static function mark_widget_present(): void {
public static function mark_widget_present() {
self::$widget_present = true;
}
/**
* Update options.
*
* @return void
* @param array $options Optional. New options to save.
*
* @since 1.0.0
* @since 1.3.0 removed unused parameter
* @return void
*/
protected static function update_options(): void {
protected static function update_options( $options = null ) {
self::$options = wp_parse_args(
get_option( self::OPTION ),
self::default_options()
@ -417,7 +417,7 @@ class SCLiveticker {
*
* @return array The options array.
*/
protected static function default_options(): array {
protected static function default_options() {
return array(
'enable_ajax' => 1,
'poll_interval' => 60,
@ -439,7 +439,7 @@ class SCLiveticker {
*
* @return string HTML code of tick.
*/
private static function tick_html( string $time, string $title, string $content, int $id ): string {
private static function tick_html( $time, $title, $content, $id ) {
if ( self::$options['enable_shortcode'] ) {
$content = do_shortcode( $content );
}
@ -460,7 +460,7 @@ class SCLiveticker {
*
* @return string HTML code of widget tick.
*/
public static function tick_html_widget( string $time, string $title, bool $highlight, int $id = 0 ): string {
public static function tick_html_widget( $time, $title, $highlight, $id = 0 ) {
$out = '<li';
if ( $highlight ) {
$out .= ' class="sclt-widget-new"';
@ -473,4 +473,15 @@ class SCLiveticker {
. '<span class="sclt-widget-title">' . $title . '</span>'
. '</li>';
}
/**
* Check if the Gutenberg block is present in current post.
*
* @return boolean True, if Gutenberg block is present.
* @since 1.1
*/
private static function block_present() {
return function_exists( 'has_block' ) && // We are in WP 5.x environment.
has_block( 'scliveticker/ticker' ); // Specific block is present.
}
}

View File

@ -1,305 +0,0 @@
<?php
/**
* Liveticker: Plugin settings class.
*
* This file contains the derived class for the plugin's settings.
*
* @package SCLiveticker
*/
namespace SCLiveticker;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Liveticker admin configuration.
*
* @since 1.3.0 extracted from {@link Admin} class
*/
class Settings extends SCLiveticker {
/**
* Register settings API
*
* @return void
*
* @since 1.0.0
* @since 1.3.0 moved from Admin to Settings class
*/
public static function register_settings(): void {
register_setting(
'scliveticker_settings',
self::OPTION,
array( __CLASS__, 'validate_settings' )
);
// Form sections.
add_settings_section(
'scliveticker_settings_general',
__( 'General', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_general_section' ),
'scliveticker-settings-page'
);
// Form fields.
add_settings_field(
'enable_ajax',
__( 'Use AJAX', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_enable_ajax_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-enable-ajax' )
);
add_settings_field(
'poll_interval',
__( 'AJAX poll interval', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_poll_interval_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-poll-interval' )
);
add_settings_field(
'enable_css',
__( 'Default CSS Styles', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_enable_css_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-enable-css' )
);
add_settings_field(
'show_feed',
__( 'Show RSS feed', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_show_feed_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-show-feed' )
);
add_settings_field(
'enable_shortcode',
__( 'Shortcode support', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_enable_shortcode_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-enable-shortcode' )
);
add_settings_field(
'embedded_script',
__( 'Embedded JavaScript', 'stklcode-liveticker' ),
array( __CLASS__, 'settings_embedded_script_field' ),
'scliveticker-settings-page',
'scliveticker_settings_general',
array( 'label_for' => esc_attr( self::OPTION ) . '-embedded-script' )
);
}
/**
* Render the settings page.
*
* @return void
*
* @since 1.0.0
* @since 1.3.0 moved from Admin to Settings class
*/
public static function render_settings_page(): void {
?>
<div class="wrap">
<div id="icon-options-general" class="icon32"><br></div>
<h2>Liveticker <?php esc_html_e( 'Settings', 'stklcode-liveticker' ); ?></h2>
<?php
if ( isset( $_GET['settings-updated'] ) ) { // phpcs:ignore
echo '<div class="updated"><p>' . esc_html__( 'Settings updated successfully.', 'stklcode-liveticker' ) . '</p></div>';
}
?>
<form action="options.php" method="post">
<?php
settings_fields( 'scliveticker_settings' );
do_settings_sections( 'scliveticker-settings-page' );
submit_button();
?>
</form>
</div>
<?php
}
/**
* Render general section.
*
* @return void
*
* @since 1.0.0
* @since 1.3.0 moved from Admin to Settings class
*/
public static function settings_general_section(): void {
}
/**
* Render enable AJAX field.
*
* @return void
*
* @since 1.0.0
* @since 1.3.0 moved from Admin to Settings class
*/
public static function settings_enable_ajax_field(): void {
self::render_checkbox(
'enable-ajax',
'[enable_ajax]',
self::$options['enable_ajax'],
__( 'Disable this option to not use AJAX update. This means all liveticker widgets and shortcodes are only updated once on site load.', 'stklcode-liveticker' ),
__( 'Enable AJAX updates', 'stklcode-liveticker' )
);
}
/**
* Render AJAX poll interval field.
*
* @return void
*
* @since 1.0.0
* @since 1.3.0 moved from Admin to Settings class
*/
public static function settings_poll_interval_field(): void {
$poll_interval = self::$options['poll_interval'];
echo '<input id="' . esc_attr( self::OPTION ) . '-poll-interval" type="number" name="' . esc_attr( self::OPTION ) . '[poll_interval]" value="' . esc_attr( $poll_interval ) . '"> ';
esc_html_e( 'seconds', 'stklcode-liveticker' );
echo '<p class="description">' . esc_html__( 'Interval (in seconds) to update ticker if AJAX is enabled.', 'stklcode-liveticker' ) . '</p>';
}
/**
* Render enable css field.
*
* @return void
*
* @since 1.0.0
* @since 1.3.0 moved from Admin to Settings class
*/
public static function settings_enable_css_field(): void {
self::render_checkbox(
'enable-css',
'[enable_css]',
self::$options['enable_css'],
__( 'Disable this option to remove the default styling CSS file.', 'stklcode-liveticker' ),
__( 'Enable default stylesheet', 'stklcode-liveticker' )
);
}
/**
* Render enable css field.
*
* @return void
*
* @since 1.0.0
* @since 1.3.0 moved from Admin to Settings class
*/
public static function settings_show_feed_field(): void {
self::render_checkbox(
'show-feed',
'[show_feed]',
self::$options['show_feed'],
__( 'Can be overwritten in shortcode.', 'stklcode-liveticker' ),
__( 'Show RSS feed in shortcode', 'stklcode-liveticker' )
);
}
/**
* Render enable shortcode field.
*
* @return void
*
* @since 1.2.0
* @since 1.3.0 moved from Admin to Settings class
*/
public static function settings_enable_shortcode_field(): void {
self::render_checkbox(
'enable-shortcode',
'[enable_shortcode]',
self::$options['enable_shortcode'],
__( 'Enable shortcode processing in tick content.', 'stklcode-liveticker' ),
__( 'Allow shortcodes in tick content', 'stklcode-liveticker' )
);
}
/**
* Render embedded script field.
*
* @return void
*
* @since 1.2.0
* @since 1.3.0 moved from Admin to Settings class
*/
public static function settings_embedded_script_field(): void {
self::render_checkbox(
'embedded-script',
'[embedded_script]',
self::$options['embedded_script'],
__( 'Allow embedded script evaluation in tick contents. This might be useful for embedded content, e.g. social media integrations.', 'stklcode-liveticker' ) .
' ' .
__( 'Be aware that this feature potentially enables cross-site scripting, so make sure content is created by trusted people and only enable this if required.', 'stklcode-liveticker' ),
__( 'Allow JavaScript in tick content', 'stklcode-liveticker' )
);
}
/**
* Validate settings callback.
*
* @param array $input Input arguments.
*
* @return array Parsed arguments.
*
* @since 1.0.0
* @since 1.3.0 moved from Admin to Settings class
*/
public static function validate_settings( array $input ): array {
$defaults = self::default_options();
$result['enable_ajax'] = isset( $input['enable_ajax'] ) ? intval( $input['enable_ajax'] ) : 0;
$result['poll_interval'] = isset( $input['poll_interval'] ) ? intval( $input['poll_interval'] ) : $defaults['poll_interval'];
$result['enable_css'] = isset( $input['enable_css'] ) ? intval( $input['enable_css'] ) : 0;
$result['show_feed'] = isset( $input['show_feed'] ) ? intval( $input['show_feed'] ) : 0;
$result['enable_shortcode'] = isset( $input['enable_shortcode'] ) ? intval( $input['enable_shortcode'] ) : 0;
$result['embedded_script'] = isset( $input['embedded_script'] ) ? intval( $input['embedded_script'] ) : 0;
return $result;
}
/**
* Render a checkbox field.
*
* @param string $id Field ID.
* @param string $name Option name.
* @param mixed $value Current value.
* @param string $description Description text.
* @param string $screen_reader_text Screen reader text.
*
* @return void
*/
private static function render_checkbox(
string $id,
string $name,
$value,
string $description,
string $screen_reader_text
) {
?>
<fieldset>
<legend class="screen-reader-text"><?php echo esc_html( $screen_reader_text ); ?></legend>
<label for="<?php echo esc_attr( self::OPTION . '-' . $id ); ?>">
<input id="<?php echo esc_attr( self::OPTION . '-' . $id ); ?>" name="<?php echo esc_attr( self::OPTION . $name ); ?>" type="checkbox" value="1" <?php checked( $value, 1 ); ?>>
<?php esc_html_e( 'Enable', 'stklcode-liveticker' ); ?>
</label>
<p class="description"><?php echo esc_html( $description ); ?></p>
</fieldset>
<?php
}
}

View File

@ -28,7 +28,7 @@ class System extends SCLiveticker {
*
* @return void
*/
public static function activate(): void {
public static function activate() {
// Load current options.
self::update_options();
@ -49,7 +49,7 @@ class System extends SCLiveticker {
*
* @return void
*/
public static function uninstall(): void {
public static function uninstall() {
// Delete all ticks.
$ticks = new WP_Query( array( 'post_type' => 'scliveticker_tick' ) );
foreach ( $ticks->get_posts() as $tick ) {

View File

@ -31,7 +31,7 @@ class Widget extends WP_Widget {
/**
* Register the widget.
*/
public static function register(): void {
public static function register() {
register_widget( __CLASS__ );
}
@ -49,10 +49,10 @@ class Widget extends WP_Widget {
SCLiveticker::mark_widget_present();
$instance = self::fill_options_with_defaults( $instance );
$before_widget = $args['before_widget'] ?? '';
$after_widget = $args['after_widget'] ?? '';
$before_title = $args['before_title'] ?? '';
$after_title = $args['after_title'] ?? '';
$before_widget = isset( $args['before_widget'] ) ? $args['before_widget'] : '';
$after_widget = isset( $args['after_widget'] ) ? $args['after_widget'] : '';
$before_title = isset( $args['before_title'] ) ? $args['before_title'] : '';
$after_title = isset( $args['after_title'] ) ? $args['after_title'] : '';
$title = apply_filters( 'scliveticker_catlit', $instance['title'] );
$category = apply_filters( 'scliveticker_catlit', $instance['category'] );
$count = apply_filters( 'scliveticker_catlit', $instance['count'] );
@ -95,16 +95,15 @@ class Widget extends WP_Widget {
$wp_query = new WP_Query( $args );
$cnt = 0;
while ( $wp_query->have_posts() && ( $count <= 0 || ++$cnt < $count ) ) {
while ( $wp_query->have_posts() && ( $count <= 0 || ++ $cnt < $count ) ) {
$wp_query->the_post();
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
// @codingStandardsIgnoreLine
echo SCLiveticker::tick_html_widget(
esc_html( get_the_time( 'd.m.Y - H:i' ) ),
get_the_title(),
( '1' === $highlight && get_the_time( 'U' ) > ( time() - $highlight_time ) ),
get_the_ID()
);
// phpcs:enable
}
echo '</ul>';
@ -146,13 +145,7 @@ class Widget extends WP_Widget {
$highlight = isset( $instance['highlight'] ) ? esc_attr( $instance['highlight'] ) : '0';
$highlight_time = isset( $instance['highlight_time'] ) ? esc_attr( $instance['highlight_time'] ) : '0';
$ajax = isset( $instance['ajax'] ) ? esc_attr( $instance['ajax'] ) : '0';
$categories = get_terms(
array(
'taxonomy' => 'scliveticker_ticker',
'orderby' => 'name',
'order' => 'ASC',
)
);
$categories = get_terms( 'scliveticker_ticker', 'orderby=name&order=ASC' );
include SCLIVETICKER_DIR . 'views/widget-form.php';
}
@ -164,7 +157,7 @@ class Widget extends WP_Widget {
*
* @return array Complete instance configuration.
*/
private static function fill_options_with_defaults( array $instance ): array {
private static function fill_options_with_defaults( $instance ) {
$default = array(
'title' => '',
'category' => '',

View File

@ -1,13 +1,13 @@
{
"name": "stklcode-liveticker",
"version": "1.3.0",
"version": "1.2.0",
"description": "A simple Liveticker for Wordpress.",
"author": "Stefan Kalscheuer",
"license": "GPL-2.0+",
"devDependencies": {
"@wordpress/eslint-plugin": "^22",
"@wordpress/stylelint-config": "^23",
"eslint": "^8",
"stylelint": "^16"
"@wordpress/eslint-plugin": "^9",
"@wordpress/stylelint-config": "^19",
"eslint": "^7",
"stylelint": "^13"
}
}

View File

@ -12,7 +12,7 @@
<file>views</file>
<!-- Compliance with WordPress Coding Standard -->
<config name="minimum_supported_wp_version" value="5.0"/>
<config name="minimum_supported_wp_version" value="4.7"/>
<rule ref="WordPress">
<exclude name="WordPress.DB.SlowDBQuery.slow_db_query_tax_query"/>
</rule>
@ -25,6 +25,6 @@
</rule>
<!-- PHP compatibility level -->
<config name="testVersion" value="7.2-"/>
<config name="testVersion" value="5.6-"/>
<rule ref="PHPCompatibilityWP"/>
</ruleset>

View File

@ -86,10 +86,6 @@
type: 'boolean',
default: false,
},
sort: {
type: 'string',
// implicit default: 'desc', left empty here for backwards compatibility of the block
},
},
edit: withSelect( function( select ) {
return {
@ -156,7 +152,7 @@
disabled: props.attributes.unlimited,
value: props.attributes.limit,
onChange: function( val ) {
props.setAttributes( { limit: Number( val ) } );
props.setAttributes( { limit: val } );
},
}
),
@ -170,26 +166,6 @@
},
}
),
el(
wp.components.SelectControl,
{
label: __( 'Output direction', 'stklcode-liveticker' ),
value: props.attributes.sort,
options: [
{
value: 'desc',
label: __( 'newest first', 'stklcode-liveticker' ),
},
{
value: 'asc',
label: __( 'oldest first', 'stklcode-liveticker' ),
},
],
onChange: function( val ) {
props.setAttributes( { sort: val } );
},
}
),
];
}
@ -207,7 +183,6 @@
'data-sclt-ticker': props.attributes.ticker,
'data-sclt-limit': props.attributes.unlimited ? 0 : props.attributes.limit,
'data-sclt-last': 0,
'data-sclt-sort': props.attributes.sort,
}
);
},

View File

@ -1,5 +1,5 @@
/**
* Constructor of the scLiveticker object.
* Contructor of the scLiveticker object.
*
* @class
*/
@ -73,7 +73,6 @@
var parseElement = function( elem, widget, n ) {
var list = elem.querySelector( 'ul' );
var last = elem.getAttribute( 'data-sclt-last' );
var sort = elem.getAttribute( 'data-sclt-sort' );
elem.id = 'sclt-' + n;
@ -93,16 +92,11 @@
);
}
if ( 'asc' !== sort && 'desc' !== 'sort' ) {
sort = 'desc';
}
return {
id: n,
ticker: elem.getAttribute( 'data-sclt-ticker' ),
limit: elem.getAttribute( 'data-sclt-limit' ),
lastPoll: last,
sort: sort,
ticks: list,
isWidget: widget,
updating: false,
@ -216,11 +210,8 @@
if ( old ) {
// Replace entry, if it already exists (i.e. has been updated).
t.ticks.replaceChild( li, old );
} else if ( 'asc' === t.sort ) {
// Append new tick as last element to container.
t.ticks.appendChild( li );
} else {
// Prepend new tick as fist element to container.
// Prepend new tick to container.
t.ticks.insertBefore( li, t.ticks.firstChild );
}
@ -229,13 +220,8 @@
t.ticks.parentNode.setAttribute( 'data-sclt-last', u.date_gmt );
// Remove tail, if limit is set.
if ( 0 < t.limit && t.limit < t.ticks.children.length ) {
if ( 'asc' === t.sort ) {
old = [].slice.call( t.ticks.children, 0, -t.limit );
} else {
old = [].slice.call( t.ticks.children, t.limit );
}
old.forEach(
if ( 0 < t.limit ) {
[].slice.call( t.ticks.getElementsByTagName( 'li' ), t.limit ).forEach(
function( l ) {
l.remove();
}

View File

@ -9,7 +9,7 @@
* @wordpress-plugin
* Plugin Name: Liveticker (by stklcode)
* Description: A simple Liveticker for WordPress.
* Version: 1.3.0
* Version: 1.2.0
* Author: Stefan Kalscheuer
* Author URI: https://www.stklcode.de
* Text Domain: stklcode-liveticker
@ -26,7 +26,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Liveticker (by stklcode). If not, see https://www.gnu.org/licenses/gpl-2.0.html.
* along with Liveticker (by stklcode). If not, see http://www.gnu.org/licenses/gpl-2.0.html.
*/
// Exit if accessed directly.
@ -64,24 +64,23 @@ spl_autoload_register( 'scliveticker_autoload' );
/**
* Autoloader for Liveticker classes.
*
* @param string $class_name Name of the class to load.
* @param string $class Name of the class to load.
*
* @return void
*/
function scliveticker_autoload( string $class_name ): void {
function scliveticker_autoload( $class ) {
$plugin_classes = array(
'SCLiveticker\\SCLiveticker',
'SCLiveticker\\Admin',
'SCLiveticker\\Api',
'SCLiveticker\\Settings',
'SCLiveticker\\System',
'SCLiveticker\\Widget',
);
if ( in_array( $class_name, $plugin_classes, true ) ) {
if ( in_array( $class, $plugin_classes, true ) ) {
require_once sprintf(
'%s/includes/class-%s.php',
SCLIVETICKER_DIR,
strtolower( str_replace( '_', '-', substr( $class_name, 13 ) ) )
strtolower( str_replace( '_', '-', substr( $class, 13 ) ) )
);
}
}

View File

@ -5,25 +5,34 @@
* @package SCLiveticker
*/
use Yoast\WPTestUtils\WPIntegration;
$_tests_dir = getenv( 'WP_TESTS_DIR' );
require_once dirname( __DIR__ ) . '/vendor/yoast/wp-test-utils/src/WPIntegration/bootstrap-functions.php';
if ( ! $_tests_dir ) {
$_tests_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-lib';
}
$_tests_dir = WPIntegration\get_path_to_wp_test_dir();
// Forward custom PHPUnit Polyfills configuration to PHPUnit bootstrap file.
$_phpunit_polyfills_path = getenv( 'WP_TESTS_PHPUNIT_POLYFILLS_PATH' );
if ( false !== $_phpunit_polyfills_path ) {
define( 'WP_TESTS_PHPUNIT_POLYFILLS_PATH', $_phpunit_polyfills_path );
}
// Get access to tests_add_filter() function.
require_once $_tests_dir . 'includes/functions.php';
if ( ! file_exists( "{$_tests_dir}/includes/functions.php" ) ) {
echo "Could not find {$_tests_dir}/includes/functions.php, have you run bin/install-wp-tests.sh ?" . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
exit( 1 );
}
// Add plugin to active mu-plugins to make sure it gets loaded.
tests_add_filter(
'muplugins_loaded',
function() {
require dirname( __DIR__ ) . '/stklcode-liveticker.php';
}
);
// Give access to tests_add_filter() function.
require_once "{$_tests_dir}/includes/functions.php";
/*
* Bootstrap WordPress. This will also load the Composer autoload file, the PHPUnit Polyfills
* and the custom autoloader for the TestCase and the mock object classes.
/**
* Manually load the plugin being tested.
*/
WPIntegration\bootstrap_it();
function _manually_load_plugin() {
require dirname( dirname( __FILE__ ) ) . '/stklcode-liveticker.php';
}
tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
// Start up the WP testing environment.
require "{$_tests_dir}/includes/bootstrap.php";

View File

@ -13,19 +13,19 @@ use DateInterval;
use DateTime;
use WP_REST_Request;
use WP_REST_Server;
use Yoast\WPTestUtils\WPIntegration\TestCase;
use WP_UnitTestCase;
/**
* Class Test_API.
*/
class Test_API extends TestCase {
class Test_API extends WP_UnitTestCase {
/**
* Initialize WP REST API for tests.
*
* @return void
*/
public function set_up(): void {
parent::set_up();
public function setUp() {
parent::setUp();
global $wp_rest_server;
$wp_rest_server = new WP_REST_Server();
do_action( 'rest_api_init' );
@ -36,7 +36,7 @@ class Test_API extends TestCase {
*
* @return void
*/
public function test_register_route(): void {
public function test_register_route() {
global $wp_rest_server;
$routes = $wp_rest_server->get_routes();
@ -52,7 +52,7 @@ class Test_API extends TestCase {
*
* @return void
*/
public function test_get_ticks(): void {
public function test_get_ticks() {
global $wp_rest_server;
$request = new WP_REST_Request( 'GET', '/wp/v2/scliveticker_tick' );

29
views/settings-page.php Normal file
View File

@ -0,0 +1,29 @@
<?php
/**
* Liveticker: Settings page.
*
* This file contains the view model for the Plugin settings oage.
*
* @package Liveticker
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<div class="wrap">
<div id="icon-options-general" class="icon32"><br></div>
<h2>Liveticker <?php esc_html_e( 'Settings', 'stklcode-liveticker' ); ?></h2>
<?php
if ( isset( $_GET['settings-updated'] ) ) { // phpcs:ignore
echo '<div class="updated"><p>' . esc_html__( 'Settings updated successfully.', 'stklcode-liveticker' ) . '</p></div>';
}
?>
<form action="options.php" method="post">
<?php
settings_fields( 'scliveticker_settings' );
do_settings_sections( 'scliveticker-settings-page' );
submit_button();
?>
</form>
</div>

View File

@ -54,10 +54,10 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php esc_html_e( 'all', 'stklcode-liveticker' ); ?>
</option>
<?php
for ( $i = 1; $i <= 10; $i++ ) {
for ( $i = 1; $i <= 10; $i ++ ) {
printf(
'<option value="%d"%s>%d</option>',
intval( $i ),
$i,
( $i === $count ) ? ' selected' : '',
intval( $i )
);