Compare commits
No commits in common. "develop" and "v1.0.0" have entirely different histories.
23
.distignore
@ -1,23 +0,0 @@
|
|||||||
/.git
|
|
||||||
/.github
|
|
||||||
/assets
|
|
||||||
/bin
|
|
||||||
/dist
|
|
||||||
/node_modules
|
|
||||||
/tests
|
|
||||||
/vendor
|
|
||||||
/.distignore
|
|
||||||
/.drone.yml
|
|
||||||
/.eslintrc.json
|
|
||||||
/.gitattributes
|
|
||||||
/.gitignore
|
|
||||||
/.phpunit.result.cache
|
|
||||||
/.stylelintrc.json
|
|
||||||
/.travis.yml
|
|
||||||
/composer.json
|
|
||||||
/composer.lock
|
|
||||||
/CONTRIBUTING.md
|
|
||||||
/package.json
|
|
||||||
/package-lock.json
|
|
||||||
/phpcs.xml
|
|
||||||
/phpunit.xml
|
|
58
.drone.yml
@ -1,28 +1,38 @@
|
|||||||
kind: pipeline
|
clone:
|
||||||
name: default
|
git:
|
||||||
type: docker
|
image: plugins/git
|
||||||
|
depth: 1
|
||||||
|
skip_verify: true
|
||||||
|
|
||||||
steps:
|
pipeline:
|
||||||
- name: composer-install
|
restore-cache:
|
||||||
image: composer:2
|
image: drillster/drone-volume-cache
|
||||||
|
restore: true
|
||||||
|
mount:
|
||||||
|
- vendor
|
||||||
|
volumes:
|
||||||
|
- /var/lib/drone/cache:/cache
|
||||||
|
cache_key: [ DRONE_REPO_OWNER, DRONE_REPO_NAME, DRONE_BRANCH ]
|
||||||
|
|
||||||
|
pre-build:
|
||||||
|
image: composer
|
||||||
commands:
|
commands:
|
||||||
- composer install --ignore-platform-req=php
|
- composer install
|
||||||
- name: lint-php
|
test:
|
||||||
image: php:8.2
|
image: composer
|
||||||
commands:
|
commands:
|
||||||
- ./vendor/bin/phpcs
|
- ./vendor/bin/robo test
|
||||||
depends_on:
|
|
||||||
- composer-install
|
test-style:
|
||||||
- name: node-install
|
image: composer
|
||||||
image: node:22
|
|
||||||
commands:
|
commands:
|
||||||
- npm install
|
- ./vendor/bin/robo test:cs
|
||||||
- name: lint-assets
|
|
||||||
image: node:22
|
rebuild-cache:
|
||||||
commands:
|
image: drillster/drone-volume-cache
|
||||||
- npx eslint scripts/block.js
|
rebuild: true
|
||||||
- npx eslint scripts/liveticker.js
|
mount:
|
||||||
- npx stylelint styles/block.css
|
- vendor
|
||||||
- npx stylelint styles/liveticker.css
|
volumes:
|
||||||
depends_on:
|
- /var/lib/drone/cache:/cache
|
||||||
- node-install
|
cache_key: [ DRONE_REPO_OWNER, DRONE_REPO_NAME, DRONE_BRANCH ]
|
||||||
|
@ -1,34 +1,3 @@
|
|||||||
{
|
{
|
||||||
"env": {
|
"extends": "./vendor/npm-asset/eslint-config-wordpress/index.js"
|
||||||
"es6": false,
|
|
||||||
"browser": true
|
|
||||||
},
|
|
||||||
"globals": {
|
|
||||||
"scliveticker": "readonly",
|
|
||||||
"wp": "readonly"
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"plugin:@wordpress/eslint-plugin/custom",
|
|
||||||
"plugin:@wordpress/eslint-plugin/es5",
|
|
||||||
"plugin:@wordpress/eslint-plugin/i18n"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"@wordpress/i18n-text-domain": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"allowedTextDomain": [ "stklcode-liveticker" ]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
"*"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"no-var": "off",
|
|
||||||
"object-shorthand": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
20
.gitattributes
vendored
@ -1,20 +0,0 @@
|
|||||||
/assets export-ignore
|
|
||||||
/.github export-ignore
|
|
||||||
/.distignore export-ignore
|
|
||||||
/.drone.yml export-ignore
|
|
||||||
/.eslintrc.json export-ignore
|
|
||||||
/.gitattributes export-ignore
|
|
||||||
/.gitignore export-ignore
|
|
||||||
/.stylelintrc.json export-ignore
|
|
||||||
/.travis.yml export-ignore
|
|
||||||
/bin export-ignore
|
|
||||||
/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
|
|
||||||
/phpunit.xml export-ignore
|
|
||||||
/tests export-ignore
|
|
||||||
|
|
85
.github/workflows/test.yml
vendored
@ -1,85 +0,0 @@
|
|||||||
name: CI
|
|
||||||
on: [push, pull_request]
|
|
||||||
jobs:
|
|
||||||
integration:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
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'
|
|
||||||
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
|
|
||||||
- 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
|
|
||||||
- name: Setup WP
|
|
||||||
run: bash bin/install-wp-tests.sh wordpress root root localhost "${{ matrix.wordpress }}"
|
|
||||||
- name: Install
|
|
||||||
run: composer install --no-interaction
|
|
||||||
- name: Test
|
|
||||||
run: composer test
|
|
||||||
|
|
||||||
quality:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Setup PHP
|
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
|
||||||
php-version: '8.2'
|
|
||||||
tools: composer
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '22'
|
|
||||||
- name: Install
|
|
||||||
run: |
|
|
||||||
composer install --no-interaction
|
|
||||||
npm install
|
|
||||||
- name: Code style checks for PHP, JS and CSS
|
|
||||||
run: |
|
|
||||||
composer lint-php
|
|
||||||
composer lint-js
|
|
||||||
composer lint-css
|
|
||||||
|
|
||||||
analysis:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Analyze with SonarCloud
|
|
||||||
if: env.SONAR_TOKEN != ''
|
|
||||||
uses: sonarsource/sonarcloud-github-action@v3
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
||||||
with:
|
|
||||||
args: >
|
|
||||||
-Dsonar.organization=stklcode-github
|
|
||||||
-Dsonar.projectKey=stklcode:wp-liveticker
|
|
||||||
-Dsonar.sources=includes,scripts,views,stklcode-liveticker.php
|
|
||||||
-Dsonar.exclusions=scripts/*.min.js,styles/*.min.css
|
|
@ -1,29 +0,0 @@
|
|||||||
name: Plugin asset/readme update
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- stable
|
|
||||||
jobs:
|
|
||||||
master:
|
|
||||||
name: Push to stable
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Setup PHP
|
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
|
||||||
php-version: '8.2'
|
|
||||||
tools: composer
|
|
||||||
- name: Install
|
|
||||||
run: composer install --no-interaction
|
|
||||||
- name: Clean README.md
|
|
||||||
run: tail -n +7 README.md > README.md.tmp && mv README.md.tmp README.md
|
|
||||||
- name: WordPress.org plugin asset/readme update
|
|
||||||
uses: 10up/action-wordpress-plugin-asset-update@stable
|
|
||||||
env:
|
|
||||||
SLUG: stklcode-liveticker
|
|
||||||
ASSETS_DIR: assets
|
|
||||||
README_NAME: README.md
|
|
||||||
SVN_PASSWORD: ${{ secrets.WP_SVN_PASSWORD }}
|
|
||||||
SVN_USERNAME: ${{ secrets.WP_SVN_USERNAME }}
|
|
23
.github/workflows/wordpress-plugin-check.yml
vendored
@ -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
|
|
29
.github/workflows/wordpress-plugin-deploy.yml
vendored
@ -1,29 +0,0 @@
|
|||||||
name: Deploy to WordPress.org
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*"
|
|
||||||
- "!v*-*"
|
|
||||||
jobs:
|
|
||||||
tag:
|
|
||||||
name: New tag
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Setup PHP
|
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
|
||||||
php-version: '8.2'
|
|
||||||
tools: composer
|
|
||||||
- name: Install
|
|
||||||
run: composer install --no-interaction
|
|
||||||
- name: Clean README.md
|
|
||||||
run: tail -n +7 README.md > README.md.tmp && mv README.md.tmp README.md
|
|
||||||
- name: WordPress Plugin Deploy
|
|
||||||
uses: 10up/action-wordpress-plugin-deploy@stable
|
|
||||||
env:
|
|
||||||
SLUG: stklcode-liveticker
|
|
||||||
ASSETS_DIR: assets
|
|
||||||
SVN_PASSWORD: ${{ secrets.WP_SVN_PASSWORD }}
|
|
||||||
SVN_USERNAME: ${{ secrets.WP_SVN_USERNAME }}
|
|
5
.gitignore
vendored
@ -1,8 +1,7 @@
|
|||||||
|
composer.lock
|
||||||
/vendor/
|
/vendor/
|
||||||
/node_modules/
|
/node_modules/
|
||||||
/dist/
|
/dist/
|
||||||
/.phpunit.result.cache
|
.idea
|
||||||
/composer.lock
|
|
||||||
/package-lock.json
|
|
||||||
**/*.min.css
|
**/*.min.css
|
||||||
**/*.min.js
|
**/*.min.js
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"extends": "@wordpress/stylelint-config"
|
"extends": "stylelint-config-wordpress"
|
||||||
}
|
}
|
||||||
|
13
.travis.yml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
language: php
|
||||||
|
dist: trusty
|
||||||
|
php:
|
||||||
|
- '5.5'
|
||||||
|
- '5.6'
|
||||||
|
- '7.0'
|
||||||
|
- '7.1'
|
||||||
|
- '7.2'
|
||||||
|
- '7.3'
|
||||||
|
before_script:
|
||||||
|
- composer install
|
||||||
|
script:
|
||||||
|
- composer test-all
|
@ -111,10 +111,10 @@ We probably find a solution for that.
|
|||||||
|
|
||||||
## Continuous Integration
|
## Continuous Integration
|
||||||
|
|
||||||
Automated tests are run using [Travis CI](https://travis-ci.org/stklcode/wp-liveticker) for every commit including pull requests.
|
Automated tests are run using [Travis CI](https://travis-ci.org/stklcode/wp-liveticker2) for every commit including pull requests.
|
||||||
They ensure compatibility with the supported PHP versions and the WP Coding Standards.
|
They ensure compatibility with the supported PHP versions and the WP Coding Standards.
|
||||||
|
|
||||||
There is also a semi-automated code quality analysis pushing results to [SonarCloud](https://sonarcloud.io/dashboard?id=de.stklcode.web.wordpress.plugins%3Awp-liveticker).
|
There is also a semi-automated code quality analysis pushing results to [SonarCloud](https://sonarcloud.io/dashboard?id=de.stklcode.web.wordpress.plugins%3Awp-liveticker2).
|
||||||
Keep in mind that the ruleset is not yet perfect, so not every minor issue has to be fixed immediately.
|
Keep in mind that the ruleset is not yet perfect, so not every minor issue has to be fixed immediately.
|
||||||
|
|
||||||
## Still Open Questions?
|
## Still Open Questions?
|
||||||
|
90
README.md
@ -1,19 +1,13 @@
|
|||||||
[](https://github.com/stklcode/wp-liveticker/actions/workflows/test.yml)
|
|
||||||
[](https://sonarcloud.io/dashboard?id=stklcode%3Awp-liveticker)
|
|
||||||
[](https://wordpress.org/plugins/stklcode-liveticker/)
|
|
||||||
[](https://packagist.org/packages/stklcode/stklcode-liveticker)
|
|
||||||
[](https://github.com/stklcode/wp-liveticker/blob/stable/LICENSE.md)
|
|
||||||
|
|
||||||
# Liveticker (by stklcode)
|
# Liveticker (by stklcode)
|
||||||
|
|
||||||
* Contributors: stklcode
|
* Contributors: Stefan Kalscheuer
|
||||||
* Tags: liveticker, feed, rss
|
* Tags: liveticker, feed, rss
|
||||||
* Requires at least: 5.0
|
* Requires at least: 4.0
|
||||||
* Tested up to: 6.7
|
* Tested up to: 5.0
|
||||||
* Requires PHP: 7.2
|
* Requires PHP: 5.2
|
||||||
* Stable tag: 1.3.0
|
* Stable tag: 1.0.0
|
||||||
* License: GPLv2 or later
|
* 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.
|
A simple ajaxified liveticker plugin for WordPress.
|
||||||
|
|
||||||
@ -27,31 +21,28 @@ Easily add multiple livetickers, add them to posts with shortcode or use them as
|
|||||||
* Handle multiple Tickers
|
* Handle multiple Tickers
|
||||||
* Automatic update via AJAX
|
* Automatic update via AJAX
|
||||||
* RSS feed capability
|
* RSS feed capability
|
||||||
* Gutenberg block and shortcode to display liveticker
|
* Shortcode to display liveticker
|
||||||
* Add ticker to sidebar widgets
|
* Add ticker to sidebar widgets
|
||||||
* Ability to customize through CSS
|
* Ability to customise through CSS
|
||||||
* Localization support
|
* Localization support
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
If you don’t know how to install a plugin for WordPress, [here’s how](https://wordpress.org/support/article/managing-plugins/).
|
1. Upload `stklcode-liveticker` to the `/wp-content/plugins/` directory.
|
||||||
|
2. Activate the plugin through the 'Plugins' menu in WordPress.
|
||||||
You can obtain the plugin through fhe official WordPress plugin repository.
|
3. Go to Liveticker menu to start.
|
||||||
Alternatively you can also use _Copmposer_.
|
|
||||||
|
|
||||||
### Requirements ###
|
### Requirements ###
|
||||||
|
|
||||||
* PHP 7.2 or above
|
* PHP 5.2 or above
|
||||||
* WordPress 5.0 or above
|
* WordPress 4.0 or above
|
||||||
|
|
||||||
## Frequently asked questions
|
## Frequently asked questions
|
||||||
|
|
||||||
### How do I display a liveticker on my post/page?
|
### How do I display a liveticker on my post/page?
|
||||||
|
|
||||||
On WordPress 5 sites there is a Gutenberg Block available to embed a liveticker in your post.
|
Use the shortcode `[liveticker ticker="my-ticker"]`.
|
||||||
|
|
||||||
You can also use the shortcode `[liveticker ticker="my-ticker"]` on WordPress 4 or classic-mode sites.
|
|
||||||
If you want to define a custom tick limit, you might also add a limit with `[liveticker ticker="my-ticker" limit="10"]`.
|
If you want to define a custom tick limit, you might also add a limit with `[liveticker ticker="my-ticker" limit="10"]`.
|
||||||
|
|
||||||
### Can I use my own styles?
|
### Can I use my own styles?
|
||||||
@ -61,11 +52,9 @@ You can deactivate the default stylesheet on the settings page and include your
|
|||||||
|
|
||||||
### Does the liveticker work with caching?
|
### Does the liveticker work with caching?
|
||||||
|
|
||||||
If you activate AJAX updates (enabled by default), the JavaScript will automatically update the content, even when the
|
It strongly depends on the use case.
|
||||||
page is loaded from cached.
|
If you update your ticker every 5 minutes, a caching time of 12 hours obviously makes no sense.
|
||||||
|
However the AJAX update will fetch the latest ticks and update cached tickers depending on the configured interval.
|
||||||
If AJAX is disabled, it depends on your update and caching intervals. If you update your ticker every 5 minutes, a
|
|
||||||
caching time of 12 hours obviously makes no sense.
|
|
||||||
|
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
@ -74,52 +63,11 @@ caching time of 12 hours obviously makes no sense.
|
|||||||
2. Tick management
|
2. Tick management
|
||||||
3. Ticker configuration.
|
3. Ticker configuration.
|
||||||
4. Settings page
|
4. Settings page
|
||||||
5. Gutenberg block
|
5. Example shortcode
|
||||||
6. Example shortcode
|
6. Example widget
|
||||||
7. Example widget
|
|
||||||
|
|
||||||
## Changelog
|
## 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
|
|
||||||
* Migrated AJAX to REST API
|
|
||||||
* Resolved Javascript compatibility issues with IE11
|
|
||||||
* Added optional shortcode support for tick content
|
|
||||||
* Support embedded JavaScript execution in tick content (e.g. for social media integrations)
|
|
||||||
|
|
||||||
### 1.1.1 - 2021-03-20
|
|
||||||
|
|
||||||
* "Ticker" taxonomy name is now translatable
|
|
||||||
|
|
||||||
### 1.1.0 - 2020-05-02
|
|
||||||
|
|
||||||
* Requires PHP 5.6 or above
|
|
||||||
* Use GMT for automatic updates
|
|
||||||
* Gutenberg Block available
|
|
||||||
* Ticks exposed through REST API
|
|
||||||
* Changed AJAX update logic for embedded media compatibility
|
|
||||||
|
|
||||||
### 1.0.0 - 2018-11-02
|
### 1.0.0 - 2018-11-02
|
||||||
|
|
||||||
* Initial release
|
* Initial release
|
||||||
|
490
RoboFile.php
Normal file
@ -0,0 +1,490 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Liveticker Robo build script.
|
||||||
|
*
|
||||||
|
* This file contains the Robo tasks for building a distributable plugin package.
|
||||||
|
* Should not be included in final package.
|
||||||
|
*
|
||||||
|
* @author Stefan Kalscheuer <stefan@stklcode.de>
|
||||||
|
*
|
||||||
|
* @package Liveticker
|
||||||
|
* @version 1.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Robo\Exception\TaskException;
|
||||||
|
use Robo\Tasks;
|
||||||
|
use Symfony\Component\Finder\Finder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class RoboFile
|
||||||
|
*/
|
||||||
|
class RoboFile extends Tasks {
|
||||||
|
const PROJECT_NAME = 'stklcode-liveticker';
|
||||||
|
const SVN_URL = 'https://plugins.svn.wordpress.org/stklcode-liveticker';
|
||||||
|
|
||||||
|
const OPT_TARGET = 'target';
|
||||||
|
const OPT_SKIPTEST = 'skipTests';
|
||||||
|
const OPT_SKIPSTYLE = 'skipStyle';
|
||||||
|
const OPT_MINIFY = 'minify';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version tag (read from composer.json).
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target directory path.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $target_dir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Final package name.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $final_name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RoboFile constructor
|
||||||
|
*
|
||||||
|
* @param array $opts Options.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct( $opts = array( self::OPT_TARGET => 'dist' ) ) {
|
||||||
|
// Read composer configuration and extract version number..
|
||||||
|
$composer = json_decode( file_get_contents( __DIR__ . '/composer.json' ) );
|
||||||
|
// Extract parameter from options.
|
||||||
|
$this->version = $composer->version;
|
||||||
|
$this->target_dir = $opts[ self::OPT_TARGET ];
|
||||||
|
$this->final_name = self::PROJECT_NAME . '.' . $this->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up target directory
|
||||||
|
*
|
||||||
|
* @param array $opts Options.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function clean( $opts = array( self::OPT_TARGET => 'dist' ) ) {
|
||||||
|
$this->say( 'Cleaning target directory...' );
|
||||||
|
if ( is_dir( $this->target_dir . '/' . $this->final_name ) ) {
|
||||||
|
$this->_deleteDir( array( $this->target_dir . '/' . $this->final_name ) );
|
||||||
|
}
|
||||||
|
if ( is_file( $this->target_dir . '/' . $this->final_name . '.zip' ) ) {
|
||||||
|
$this->_remove( $this->target_dir . '/' . $this->final_name . '.zip' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run PHPUnit tests
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function test() {
|
||||||
|
$this->say( 'Executing PHPUnit tests...' );
|
||||||
|
$this->taskPhpUnit()->configFile( __DIR__ . '/phpunit.xml' )->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run code style tests
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testCS() {
|
||||||
|
$this->say( 'Executing PHPCS tests...' );
|
||||||
|
$this->_exec( __DIR__ . '/vendor/bin/phpcs --standard=phpcs.xml -s' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a distributable bundle.
|
||||||
|
*
|
||||||
|
* @param array $opts Options.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function build(
|
||||||
|
$opts = array(
|
||||||
|
self::OPT_TARGET => 'dist',
|
||||||
|
self::OPT_SKIPTEST => false,
|
||||||
|
self::OPT_SKIPSTYLE => false,
|
||||||
|
self::OPT_MINIFY => true,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$this->clean( $opts );
|
||||||
|
if ( isset( $opts[ self::OPT_SKIPTEST ] ) && true === $opts[ self::OPT_SKIPTEST ] ) {
|
||||||
|
$this->say( 'Tests skipped' );
|
||||||
|
} else {
|
||||||
|
$this->test();
|
||||||
|
}
|
||||||
|
if ( isset( $opts[ self::OPT_SKIPSTYLE ] ) && true === $opts[ self::OPT_SKIPSTYLE ] ) {
|
||||||
|
$this->say( 'Style checks skipped' );
|
||||||
|
} else {
|
||||||
|
$this->testCS();
|
||||||
|
}
|
||||||
|
$this->bundle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bundle global resources.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function bundle() {
|
||||||
|
$this->say( 'Bundling resources...' );
|
||||||
|
$this->taskCopyDir( array(
|
||||||
|
'includes' => $this->target_dir . '/' . $this->final_name . '/includes',
|
||||||
|
'scripts' => $this->target_dir . '/' . $this->final_name . '/scripts',
|
||||||
|
'styles' => $this->target_dir . '/' . $this->final_name . '/styles',
|
||||||
|
'views' => $this->target_dir . '/' . $this->final_name . '/views',
|
||||||
|
) )->run();
|
||||||
|
$this->_copy( 'stklcode-liveticker.php', $this->target_dir . '/' . $this->final_name . '/stklcode-liveticker.php' );
|
||||||
|
$this->_copy( 'README.md', $this->target_dir . '/' . $this->final_name . '/README.md' );
|
||||||
|
$this->_copy( 'LICENSE.md', $this->target_dir . '/' . $this->final_name . '/LICENSE.md' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minify JavaScript and CSS assets in target director.
|
||||||
|
*
|
||||||
|
* @param array $opts Options.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function minify(
|
||||||
|
$opts = array(
|
||||||
|
self::OPT_TARGET => 'dist',
|
||||||
|
self::OPT_SKIPTEST => false,
|
||||||
|
self::OPT_SKIPSTYLE => false,
|
||||||
|
self::OPT_MINIFY => true,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if ( $opts[ self::OPT_MINIFY ] ) {
|
||||||
|
$this->minifyJS( $opts );
|
||||||
|
$this->minifyCSS( $opts );
|
||||||
|
} else {
|
||||||
|
$this->say( 'Minification skipped.' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minify CSS assets.
|
||||||
|
*
|
||||||
|
* @param array $opts Options.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function minifyCSS(
|
||||||
|
$opts = array(
|
||||||
|
self::OPT_TARGET => 'dist',
|
||||||
|
self::OPT_SKIPTEST => false,
|
||||||
|
self::OPT_SKIPSTYLE => false,
|
||||||
|
self::OPT_MINIFY => true,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if ( ! isset( $opts[ self::OPT_MINIFY ] ) ) {
|
||||||
|
$this->say( 'CSS minification skipped.' );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->say( 'Minifying CSS...' );
|
||||||
|
|
||||||
|
$finder = Finder::create()->name( '*.css*' )
|
||||||
|
->notName( '*.min.css' )
|
||||||
|
->in( $this->target_dir . '/' . $this->final_name . '/styles' );
|
||||||
|
foreach ( $finder as $file ) {
|
||||||
|
$this->taskMinify( $file )->run();
|
||||||
|
// Replace original file for in-place minification.
|
||||||
|
$abspath = $file->getPath() . '/' . $file->getFilename();
|
||||||
|
$this->_rename( str_replace( '.css', '.min.css', $abspath ), $abspath, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minify JavaScript assets.
|
||||||
|
*
|
||||||
|
* @param array $opts Options.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function minifyJS(
|
||||||
|
$opts = array(
|
||||||
|
self::OPT_TARGET => 'dist',
|
||||||
|
self::OPT_SKIPTEST => false,
|
||||||
|
self::OPT_SKIPSTYLE => false,
|
||||||
|
self::OPT_MINIFY => true,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if ( ! isset( $opts[ self::OPT_MINIFY ] ) ) {
|
||||||
|
$this->say( 'JS minification skipped.' );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->say( 'Minifying JavaScript...' );
|
||||||
|
|
||||||
|
// Minify global JavaScripts files except already minified.
|
||||||
|
$finder = Finder::create()->name( '*.js*' )
|
||||||
|
->notName( '*.min.js' )
|
||||||
|
->in( $this->target_dir . '/' . $this->final_name . '/scripts' );
|
||||||
|
foreach ( $finder as $file ) {
|
||||||
|
$this->taskMinify( $file )->run();
|
||||||
|
// Replace original file for in-place minification.
|
||||||
|
$abspath = $file->getPath() . '/' . $file->getFilename();
|
||||||
|
$this->_rename( str_replace( '.js', '.min.js', $abspath ), $abspath, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create ZIP package from distribution bundle.
|
||||||
|
*
|
||||||
|
* @param array $opts Options.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function package(
|
||||||
|
$opts = array(
|
||||||
|
self::OPT_TARGET => 'dist',
|
||||||
|
self::OPT_SKIPTEST => false,
|
||||||
|
self::OPT_SKIPSTYLE => false,
|
||||||
|
self::OPT_MINIFY => true,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$this->build( $opts );
|
||||||
|
$this->say( 'Packaging...' );
|
||||||
|
$this->taskPack( $this->target_dir . '/' . $this->final_name . '.zip' )
|
||||||
|
->addDir( '', $this->target_dir . '/' . $this->final_name )
|
||||||
|
->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy development version (trunk).
|
||||||
|
*
|
||||||
|
* @param array $opts Options.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws TaskException On errors.
|
||||||
|
*/
|
||||||
|
public function deployTrunk(
|
||||||
|
$opts = array(
|
||||||
|
self::OPT_TARGET => 'dist',
|
||||||
|
self::OPT_SKIPTEST => false,
|
||||||
|
self::OPT_SKIPSTYLE => false,
|
||||||
|
self::OPT_MINIFY => true,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// First execute build job.
|
||||||
|
$this->build( $opts );
|
||||||
|
|
||||||
|
// Prepare VCS, either checkout or update local copy.
|
||||||
|
$this->prepareVCS();
|
||||||
|
|
||||||
|
$this->say( 'Preparing deployment directory...' );
|
||||||
|
$this->updateVCStrunk();
|
||||||
|
|
||||||
|
// Update remote repository.
|
||||||
|
$this->say( 'Deploying...' );
|
||||||
|
$this->commitVCS(
|
||||||
|
'--force trunk/*',
|
||||||
|
'Updated ' . self::PROJECT_NAME . ' trunk'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy current version tag.
|
||||||
|
*
|
||||||
|
* @param array $opts Options.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws TaskException On errors.
|
||||||
|
*/
|
||||||
|
public function deployTag(
|
||||||
|
$opts = array(
|
||||||
|
self::OPT_TARGET => 'dist',
|
||||||
|
self::OPT_SKIPTEST => false,
|
||||||
|
self::OPT_SKIPSTYLE => false,
|
||||||
|
self::OPT_MINIFY => true,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// First execute build job.
|
||||||
|
$this->build( $opts );
|
||||||
|
|
||||||
|
// Prepare VCS, either checkout or update local copy.
|
||||||
|
$this->prepareVCS();
|
||||||
|
|
||||||
|
$this->say( 'Preparing deployment directory...' );
|
||||||
|
$this->updateVCStag();
|
||||||
|
|
||||||
|
// Update remote repository.
|
||||||
|
$this->say( 'Deploying...' );
|
||||||
|
$this->commitVCS(
|
||||||
|
'tags/' . $this->version,
|
||||||
|
'Updated ' . self::PROJECT_NAME . ' v' . $this->version
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy current version tag.
|
||||||
|
*
|
||||||
|
* @param array $opts Options.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws TaskException On errors.
|
||||||
|
*/
|
||||||
|
public function deployReadme(
|
||||||
|
$opts = array(
|
||||||
|
self::OPT_TARGET => 'dist',
|
||||||
|
self::OPT_SKIPTEST => false,
|
||||||
|
self::OPT_SKIPSTYLE => false,
|
||||||
|
self::OPT_MINIFY => true,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// First execute build job.
|
||||||
|
$this->build( $opts );
|
||||||
|
|
||||||
|
// Prepare VCS, either checkout or update local copy.
|
||||||
|
$this->prepareVCS();
|
||||||
|
|
||||||
|
$this->updateVCSreadme();
|
||||||
|
|
||||||
|
// Update remote repository.
|
||||||
|
$this->say( 'Deploying...' );
|
||||||
|
$this->commitVCS(
|
||||||
|
'--force trunk/README.md',
|
||||||
|
'Updated ' . self::PROJECT_NAME . ' ReadMe'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy current version tag and trunk.
|
||||||
|
*
|
||||||
|
* @param array $opts Options.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws TaskException On errors.
|
||||||
|
*/
|
||||||
|
public function deployAll(
|
||||||
|
$opts = array(
|
||||||
|
self::OPT_TARGET => 'dist',
|
||||||
|
self::OPT_SKIPTEST => false,
|
||||||
|
self::OPT_SKIPSTYLE => false,
|
||||||
|
self::OPT_MINIFY => true,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// First execute build job.
|
||||||
|
$this->build( $opts );
|
||||||
|
|
||||||
|
// Prepare VCS, either checkout or update local copy.
|
||||||
|
$this->prepareVCS();
|
||||||
|
|
||||||
|
$this->say( 'Preparing deployment directory...' );
|
||||||
|
$this->updateVCStrunk();
|
||||||
|
$this->updateVCStag();
|
||||||
|
|
||||||
|
// Update remote repository.
|
||||||
|
$this->say( 'Deploying...' );
|
||||||
|
$this->commitVCS(
|
||||||
|
array(
|
||||||
|
'--force trunk/*',
|
||||||
|
'--force tags/' . $this->version,
|
||||||
|
),
|
||||||
|
'Updated ' . self::PROJECT_NAME . ' v' . $this->version
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare VCS direcory.
|
||||||
|
*
|
||||||
|
* Checkout or update local copy of SVN repository.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws TaskException On errors.
|
||||||
|
*/
|
||||||
|
private function prepareVCS() {
|
||||||
|
if ( is_dir( $this->target_dir . '/svn' ) ) {
|
||||||
|
$this->taskSvnStack()
|
||||||
|
->stopOnFail()
|
||||||
|
->dir( $this->target_dir . '/svn/stklcode-liveticker' )
|
||||||
|
->update()
|
||||||
|
->run();
|
||||||
|
} else {
|
||||||
|
$this->_mkdir( $this->target_dir . '/svn' );
|
||||||
|
$this->taskSvnStack()
|
||||||
|
->dir( $this->target_dir . '/svn' )
|
||||||
|
->checkout( self::SVN_URL )
|
||||||
|
->run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commit VCS changes
|
||||||
|
*
|
||||||
|
* @param string|array $to_add Files to add.
|
||||||
|
* @param string $msg Commit message.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws TaskException On errors.
|
||||||
|
*/
|
||||||
|
private function commitVCS( $to_add, $msg ) {
|
||||||
|
$task = $this->taskSvnStack()
|
||||||
|
->stopOnFail()
|
||||||
|
->dir( $this->target_dir . '/svn/stklode-liveticker' );
|
||||||
|
|
||||||
|
if ( is_array( $to_add ) ) {
|
||||||
|
foreach ( $to_add as $ta ) {
|
||||||
|
$task = $task->add( $ta );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$task = $task->add( $to_add );
|
||||||
|
}
|
||||||
|
|
||||||
|
$task->commit( $msg )->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update SVN readme file.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function updateVCSreadme() {
|
||||||
|
$trunk_dir = $this->target_dir . '/svn/stklcode-liveticker/trunk';
|
||||||
|
$this->_copy( $this->target_dir . '/' . $this->final_name . 'README.md', $trunk_dir . 'README.md' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update SVN development version (trunk).
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function updateVCStrunk() {
|
||||||
|
// Clean trunk directory.
|
||||||
|
$trunk_dir = $this->target_dir . '/svn/stklcode-liveticker/trunk';
|
||||||
|
$this->taskCleanDir( $trunk_dir )->run();
|
||||||
|
|
||||||
|
// Copy built bundle to trunk.
|
||||||
|
$this->taskCopyDir( array( $this->target_dir . '/' . $this->final_name => $trunk_dir ) )->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update current SVN version tag.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function updateVCStag() {
|
||||||
|
// Clean tag directory if it exists.
|
||||||
|
$tag_dir = $this->target_dir . '/svn/stklcode-liveticker/tags/' . $this->version;
|
||||||
|
if ( is_dir( $tag_dir ) ) {
|
||||||
|
$this->taskCleanDir( $this->target_dir . '/svn/stklcode-liveticker/tags/' . $this->version )->run();
|
||||||
|
} else {
|
||||||
|
$this->_mkdir( $tag_dir );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy built bundle to trunk.
|
||||||
|
$this->taskCopyDir( array( $this->target_dir . '/' . $this->final_name => $tag_dir ) )->run();
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 26 KiB |
@ -1,194 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
if [ $# -lt 3 ]; then
|
|
||||||
echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
DB_NAME=$1
|
|
||||||
DB_USER=$2
|
|
||||||
DB_PASS=$3
|
|
||||||
DB_HOST=${4-localhost}
|
|
||||||
WP_VERSION=${5-latest}
|
|
||||||
SKIP_DB_CREATE=${6-false}
|
|
||||||
|
|
||||||
TMPDIR=${TMPDIR-/tmp}
|
|
||||||
TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//")
|
|
||||||
WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib}
|
|
||||||
WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress}
|
|
||||||
|
|
||||||
download() {
|
|
||||||
if [ `which curl` ]; then
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then
|
|
||||||
WP_BRANCH=${WP_VERSION%\-*}
|
|
||||||
WP_TESTS_TAG="branches/$WP_BRANCH"
|
|
||||||
|
|
||||||
elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
|
|
||||||
WP_TESTS_TAG="branches/$WP_VERSION"
|
|
||||||
elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
|
||||||
if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
|
|
||||||
# version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
|
|
||||||
WP_TESTS_TAG="tags/${WP_VERSION%??}"
|
|
||||||
else
|
|
||||||
WP_TESTS_TAG="tags/$WP_VERSION"
|
|
||||||
fi
|
|
||||||
elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
|
|
||||||
WP_TESTS_TAG="trunk"
|
|
||||||
else
|
|
||||||
# http serves a single offer, whereas https serves multiple. we only want one
|
|
||||||
download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
|
|
||||||
grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
|
|
||||||
LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
|
|
||||||
if [[ -z "$LATEST_VERSION" ]]; then
|
|
||||||
echo "Latest WordPress version could not be found"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
WP_TESTS_TAG="tags/$LATEST_VERSION"
|
|
||||||
fi
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
install_wp() {
|
|
||||||
|
|
||||||
if [ -d $WP_CORE_DIR ]; then
|
|
||||||
return;
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p $WP_CORE_DIR
|
|
||||||
|
|
||||||
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
|
|
||||||
if [ $WP_VERSION == 'latest' ]; then
|
|
||||||
local ARCHIVE_NAME='latest'
|
|
||||||
elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then
|
|
||||||
# https serves multiple offers, whereas http serves single.
|
|
||||||
download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json
|
|
||||||
if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
|
|
||||||
# version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
|
|
||||||
LATEST_VERSION=${WP_VERSION%??}
|
|
||||||
else
|
|
||||||
# otherwise, scan the releases and get the most up to date minor version of the major release
|
|
||||||
local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'`
|
|
||||||
LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1)
|
|
||||||
fi
|
|
||||||
if [[ -z "$LATEST_VERSION" ]]; then
|
|
||||||
local ARCHIVE_NAME="wordpress-$WP_VERSION"
|
|
||||||
else
|
|
||||||
local ARCHIVE_NAME="wordpress-$LATEST_VERSION"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
local ARCHIVE_NAME="wordpress-$WP_VERSION"
|
|
||||||
fi
|
|
||||||
download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
install_test_suite() {
|
|
||||||
# portable in-place argument for both GNU sed and Mac OSX sed
|
|
||||||
if [[ $(uname -s) == 'Darwin' ]]; then
|
|
||||||
local ioption='-i.bak'
|
|
||||||
else
|
|
||||||
local ioption='-i'
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set up testing suite if it doesn't yet exist
|
|
||||||
if [ ! -d $WP_TESTS_DIR ]; then
|
|
||||||
# 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
|
|
||||||
|
|
||||||
if [ ! -f wp-tests-config.php ]; then
|
|
||||||
download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
|
|
||||||
# remove all forward slashes in the end
|
|
||||||
WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::")
|
|
||||||
sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
|
|
||||||
sed $ioption "s:__DIR__ . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
|
|
||||||
sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
|
|
||||||
sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
|
|
||||||
sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
|
|
||||||
sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
recreate_db() {
|
|
||||||
shopt -s nocasematch
|
|
||||||
if [[ $1 =~ ^(y|yes)$ ]]
|
|
||||||
then
|
|
||||||
mysqladmin drop $DB_NAME -f --user="$DB_USER" --password="$DB_PASS"$EXTRA
|
|
||||||
create_db
|
|
||||||
echo "Recreated the database ($DB_NAME)."
|
|
||||||
else
|
|
||||||
echo "Leaving the existing database ($DB_NAME) in place."
|
|
||||||
fi
|
|
||||||
shopt -u nocasematch
|
|
||||||
}
|
|
||||||
|
|
||||||
create_db() {
|
|
||||||
mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
|
|
||||||
}
|
|
||||||
|
|
||||||
install_db() {
|
|
||||||
|
|
||||||
if [ ${SKIP_DB_CREATE} = "true" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# parse DB_HOST for port or socket references
|
|
||||||
local PARTS=(${DB_HOST//\:/ })
|
|
||||||
local DB_HOSTNAME=${PARTS[0]};
|
|
||||||
local DB_SOCK_OR_PORT=${PARTS[1]};
|
|
||||||
local EXTRA=""
|
|
||||||
|
|
||||||
if ! [ -z $DB_HOSTNAME ] ; then
|
|
||||||
if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
|
|
||||||
EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
|
|
||||||
elif ! [ -z $DB_SOCK_OR_PORT ] ; then
|
|
||||||
EXTRA=" --socket=$DB_SOCK_OR_PORT"
|
|
||||||
elif ! [ -z $DB_HOSTNAME ] ; then
|
|
||||||
EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# create database
|
|
||||||
if [ $(mysql --user="$DB_USER" --password="$DB_PASS"$EXTRA --execute='show databases;' | grep ^$DB_NAME$) ]
|
|
||||||
then
|
|
||||||
echo "Reinstalling will delete the existing test database ($DB_NAME)"
|
|
||||||
read -p 'Are you sure you want to proceed? [y/N]: ' DELETE_EXISTING_DB
|
|
||||||
recreate_db $DELETE_EXISTING_DB
|
|
||||||
else
|
|
||||||
create_db
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install_wp
|
|
||||||
install_test_suite
|
|
||||||
install_db
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stklcode/stklcode-liveticker",
|
"name": "stklcode/wp-liveticker",
|
||||||
"version": "1.3.0",
|
"version": "1.0.0",
|
||||||
"description": "A simple Liveticker for Wordpress.",
|
"description": "A simple Liveticker for Wordpress.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"wordpress",
|
"wordpress",
|
||||||
@ -17,17 +17,23 @@
|
|||||||
],
|
],
|
||||||
"type": "wordpress-plugin",
|
"type": "wordpress-plugin",
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.2",
|
"php": ">=5.2",
|
||||||
"composer/installers": "~v2.3.0"
|
"composer/installers": "~1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"dealerdirect/phpcodesniffer-composer-installer": "^v1.0",
|
"php": ">=5.2",
|
||||||
|
"consolidation/robo": "^1.0.0",
|
||||||
|
"phpunit/phpunit": "*",
|
||||||
|
"phpunit/php-code-coverage": "*",
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "^0.4",
|
||||||
|
"slowprog/composer-copy-file": "~0.2",
|
||||||
|
"squizlabs/php_codesniffer": "^3.1",
|
||||||
|
"wimg/php-compatibility": "^8.0",
|
||||||
|
"wp-coding-standards/wpcs": "~0.14",
|
||||||
|
"patchwork/jsqueeze": "^2.0.5",
|
||||||
|
"natxet/CssMin": "^3.0.5",
|
||||||
"matthiasmullie/minify": "^1.3",
|
"matthiasmullie/minify": "^1.3",
|
||||||
"phpcompatibility/phpcompatibility-wp": "^2.1",
|
"npm-asset/eslint-config-wordpress": "^2.0"
|
||||||
"slowprog/composer-copy-file": "~0.3",
|
|
||||||
"squizlabs/php_codesniffer": "^3.11",
|
|
||||||
"wp-coding-standards/wpcs": "^3.1",
|
|
||||||
"yoast/wp-test-utils": "^1.2"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"post-install-cmd": [
|
"post-install-cmd": [
|
||||||
@ -37,38 +43,39 @@
|
|||||||
"@minify"
|
"@minify"
|
||||||
],
|
],
|
||||||
"build": [
|
"build": [
|
||||||
"@minify"
|
"@minify",
|
||||||
|
"robo build"
|
||||||
|
],
|
||||||
|
"package": [
|
||||||
|
"@minify",
|
||||||
|
"robo package"
|
||||||
|
],
|
||||||
|
"deploy": [
|
||||||
|
"@minify",
|
||||||
|
"robo deploy:all"
|
||||||
|
],
|
||||||
|
"test-all": [
|
||||||
|
"@test",
|
||||||
|
"@test-cs"
|
||||||
],
|
],
|
||||||
"test": [
|
"test": [
|
||||||
"phpunit"
|
"phpunit"
|
||||||
],
|
],
|
||||||
"lint-all": [
|
"test-cs": [
|
||||||
"@lint-php",
|
|
||||||
"@lint-css",
|
|
||||||
"@lint-js"
|
|
||||||
],
|
|
||||||
"lint-php": [
|
|
||||||
"phpcs --standard=phpcs.xml -s"
|
"phpcs --standard=phpcs.xml -s"
|
||||||
],
|
],
|
||||||
"lint-css": [
|
"fix-cs": [
|
||||||
"npx stylelint styles/block.css",
|
"phpcbf --standard=phpcs.xml"
|
||||||
"npx stylelint styles/liveticker.css"
|
|
||||||
],
|
|
||||||
"lint-js": [
|
|
||||||
"npx eslint scripts/block.js",
|
|
||||||
"npx eslint scripts/liveticker.js"
|
|
||||||
],
|
],
|
||||||
"minify": [
|
"minify": [
|
||||||
"minifycss styles/block.css > styles/block.min.css",
|
|
||||||
"minifycss styles/liveticker.css > styles/liveticker.min.css",
|
"minifycss styles/liveticker.css > styles/liveticker.min.css",
|
||||||
"minifyjs scripts/block.js > scripts/block.min.js",
|
|
||||||
"minifyjs scripts/liveticker.js > scripts/liveticker.min.js"
|
"minifyjs scripts/liveticker.js > scripts/liveticker.min.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"config": {
|
"repositories": [
|
||||||
"allow-plugins": {
|
{
|
||||||
"composer/installers": true,
|
"type": "composer",
|
||||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
"url": "https://asset-packagist.org"
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Liveticker: Plugin admin class.
|
|
||||||
*
|
|
||||||
* This file contains the derived class for the plugin's administration features.
|
|
||||||
*
|
|
||||||
* @package SCLiveticker
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace SCLiveticker;
|
|
||||||
|
|
||||||
// Exit if accessed directly.
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Liveticker admin configuration.
|
|
||||||
*/
|
|
||||||
class Admin extends SCLiveticker {
|
|
||||||
/**
|
|
||||||
* Add to Right Now Widget
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function dashboard_right_now(): void {
|
|
||||||
$total_files = wp_count_posts( 'scliveticker_tick' );
|
|
||||||
|
|
||||||
echo '<tr>';
|
|
||||||
echo '<td class="first b b-tags"><a href="edit.php?post_type=scliveticker_tick">' . esc_html( $total_files->publish ) . '</a></td>';
|
|
||||||
echo '<td class="t tags"><a href="edit.php?post_type=scliveticker_tick">' . esc_html__( 'Ticks', 'stklcode-liveticker' ) . '</a></td>';
|
|
||||||
echo '</tr>';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register settings page.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function register_settings_page(): void {
|
|
||||||
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' )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register custom Gutenberg block type.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @since 1.1
|
|
||||||
*/
|
|
||||||
public static function register_block(): void {
|
|
||||||
wp_register_script(
|
|
||||||
'scliveticker-editor',
|
|
||||||
SCLIVETICKER_BASE . 'scripts/block.min.js',
|
|
||||||
array( 'wp-blocks', 'wp-element' ),
|
|
||||||
self::VERSION,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
wp_register_style(
|
|
||||||
'scliveticker-editor',
|
|
||||||
SCLIVETICKER_BASE . 'styles/block.min.css',
|
|
||||||
array(),
|
|
||||||
self::VERSION
|
|
||||||
);
|
|
||||||
|
|
||||||
register_block_type(
|
|
||||||
'scliveticker-block/liveticker',
|
|
||||||
array(
|
|
||||||
'editor_script' => 'scliveticker-editor',
|
|
||||||
'editor_style' => 'scliveticker-editor',
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Liveticker: Plugin API class.
|
|
||||||
*
|
|
||||||
* This file contains the plugin's REST API extensions.
|
|
||||||
*
|
|
||||||
* @package SCLiveticker
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace SCLiveticker;
|
|
||||||
|
|
||||||
// Exit if accessed directly.
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use WP_REST_Request;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Liveticker.
|
|
||||||
*
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
class Api {
|
|
||||||
/**
|
|
||||||
* Initialize custom fields for REST API responses.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function init(): void {
|
|
||||||
// Add rendered modification date to WP_Post object.
|
|
||||||
register_rest_field(
|
|
||||||
'scliveticker_tick',
|
|
||||||
'modified_rendered',
|
|
||||||
array(
|
|
||||||
'get_callback' => function ( $post ) {
|
|
||||||
return ( new DateTime( $post['modified'] ) )->format( 'd.m.Y H:i' );
|
|
||||||
},
|
|
||||||
'schema' => array(
|
|
||||||
'description' => __( 'Rendered modification date and time.', 'stklcode-liveticker' ),
|
|
||||||
'type' => 'string',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter tick queries by ticker slug and date.
|
|
||||||
*
|
|
||||||
* @param array $args Query vars.
|
|
||||||
* @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 {
|
|
||||||
// Extract arguments.
|
|
||||||
$ticker_slug = $request->get_param( 'ticker' );
|
|
||||||
$limit = intval( $request->get_param( 'limit' ) );
|
|
||||||
$last_poll = $request->get_param( 'last' );
|
|
||||||
|
|
||||||
if ( ! empty( $ticker_slug ) ) {
|
|
||||||
$args['tax_query'][] = array(
|
|
||||||
'taxonomy' => 'scliveticker_ticker',
|
|
||||||
'field' => 'slug',
|
|
||||||
'terms' => $ticker_slug,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $limit > 0 ) {
|
|
||||||
$args['posts_per_page'] = $limit;
|
|
||||||
$args['paged'] = 1;
|
|
||||||
} elseif ( $limit < 0 ) {
|
|
||||||
$args['nopaging'] = true;
|
|
||||||
$args['paged'] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! empty( $last_poll ) ) {
|
|
||||||
$last_poll = explode(
|
|
||||||
',',
|
|
||||||
gmdate(
|
|
||||||
'Y,m,d,H,i,s',
|
|
||||||
rest_parse_date( $last_poll )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$args['date_query'] = array(
|
|
||||||
'column' => 'post_date_gmt',
|
|
||||||
'after' => array(
|
|
||||||
'year' => intval( $last_poll[0] ),
|
|
||||||
'month' => intval( $last_poll[1] ),
|
|
||||||
'day' => intval( $last_poll[2] ),
|
|
||||||
'hour' => intval( $last_poll[3] ),
|
|
||||||
'minute' => intval( $last_poll[4] ),
|
|
||||||
'second' => intval( $last_poll[5] ),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $args;
|
|
||||||
}
|
|
||||||
}
|
|
205
includes/class-scliveticker-admin.php
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Liveticker: Plugin admin class.
|
||||||
|
*
|
||||||
|
* This file contains the derived class for the plugin's administration features.
|
||||||
|
*
|
||||||
|
* @package Liveticker
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liveticker admin configuration.
|
||||||
|
*/
|
||||||
|
class SCLiveticker_Admin extends SCLiveticker {
|
||||||
|
/**
|
||||||
|
* Add to Right Now Widget
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function dashboard_right_now() {
|
||||||
|
$total_files = wp_count_posts( 'scliveticker_tick' );
|
||||||
|
|
||||||
|
echo '<tr>';
|
||||||
|
echo '<td class="first b b-tags"><a href="edit.php?post_type=scliveticker_tick">' . esc_html( $total_files->publish ) . '</a></td>';
|
||||||
|
echo '<td class="t tags"><a href="edit.php?post_type=scliveticker_tick">' . esc_html__( 'Ticks', 'stklcode-liveticker' ) . '</a></td>';
|
||||||
|
echo '</tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register settings page.
|
||||||
|
*
|
||||||
|
* @return 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(
|
||||||
|
__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' )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
@ -4,13 +4,9 @@
|
|||||||
*
|
*
|
||||||
* This file contains the derived class for the plugin's system operations.
|
* This file contains the derived class for the plugin's system operations.
|
||||||
*
|
*
|
||||||
* @package SCLiveticker
|
* @package Liveticker
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace SCLiveticker;
|
|
||||||
|
|
||||||
use WP_Query;
|
|
||||||
|
|
||||||
// Exit if accessed directly.
|
// Exit if accessed directly.
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
@ -19,7 +15,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
/**
|
/**
|
||||||
* Liveticker system configuration.
|
* Liveticker system configuration.
|
||||||
*/
|
*/
|
||||||
class System extends SCLiveticker {
|
class SCLiveticker_System extends SCLiveticker {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activation hook.
|
* Activation hook.
|
||||||
@ -28,14 +24,14 @@ class System extends SCLiveticker {
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function activate(): void {
|
public static function activate() {
|
||||||
// Load current options.
|
// Load current options.
|
||||||
self::update_options();
|
self::update_options();
|
||||||
|
|
||||||
// Add default settings to database.
|
// Add default settings to database.
|
||||||
$defaults = self::default_options();
|
$defaults = self::default_options();
|
||||||
|
|
||||||
if ( self::$options['reset_settings'] ) {
|
if ( self::$_options['reset_settings'] ) {
|
||||||
// Reset requested, overwrite existing options with default.
|
// Reset requested, overwrite existing options with default.
|
||||||
update_option( self::OPTION, $defaults );
|
update_option( self::OPTION, $defaults );
|
||||||
} else {
|
} else {
|
||||||
@ -49,7 +45,7 @@ class System extends SCLiveticker {
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function uninstall(): void {
|
public static function uninstall() {
|
||||||
// Delete all ticks.
|
// Delete all ticks.
|
||||||
$ticks = new WP_Query( array( 'post_type' => 'scliveticker_tick' ) );
|
$ticks = new WP_Query( array( 'post_type' => 'scliveticker_tick' ) );
|
||||||
foreach ( $ticks->get_posts() as $tick ) {
|
foreach ( $ticks->get_posts() as $tick ) {
|
@ -4,22 +4,17 @@
|
|||||||
*
|
*
|
||||||
* This file contains the liveticker widget.
|
* This file contains the liveticker widget.
|
||||||
*
|
*
|
||||||
* @package SCLiveticker
|
* @package Liveticker
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace SCLiveticker;
|
|
||||||
|
|
||||||
use WP_Query;
|
|
||||||
use WP_Widget;
|
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Widget.
|
* Class SCLiveticker_Widget.
|
||||||
*/
|
*/
|
||||||
class Widget extends WP_Widget {
|
class SCLiveticker_Widget extends WP_Widget {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SCLiveticker_Widget constructor.
|
* SCLiveticker_Widget constructor.
|
||||||
@ -31,7 +26,7 @@ class Widget extends WP_Widget {
|
|||||||
/**
|
/**
|
||||||
* Register the widget.
|
* Register the widget.
|
||||||
*/
|
*/
|
||||||
public static function register(): void {
|
public static function register() {
|
||||||
register_widget( __CLASS__ );
|
register_widget( __CLASS__ );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,10 +44,10 @@ class Widget extends WP_Widget {
|
|||||||
SCLiveticker::mark_widget_present();
|
SCLiveticker::mark_widget_present();
|
||||||
|
|
||||||
$instance = self::fill_options_with_defaults( $instance );
|
$instance = self::fill_options_with_defaults( $instance );
|
||||||
$before_widget = $args['before_widget'] ?? '';
|
$before_widget = isset( $args['before_widget'] ) ? $args['before_widget'] : '';
|
||||||
$after_widget = $args['after_widget'] ?? '';
|
$after_widget = isset( $args['after_widget'] ) ? $args['after_widget'] : '';
|
||||||
$before_title = $args['before_title'] ?? '';
|
$before_title = isset( $args['before_title'] ) ? $args['before_title'] : '';
|
||||||
$after_title = $args['after_title'] ?? '';
|
$after_title = isset( $args['after_title'] ) ? $args['after_title'] : '';
|
||||||
$title = apply_filters( 'scliveticker_catlit', $instance['title'] );
|
$title = apply_filters( 'scliveticker_catlit', $instance['title'] );
|
||||||
$category = apply_filters( 'scliveticker_catlit', $instance['category'] );
|
$category = apply_filters( 'scliveticker_catlit', $instance['category'] );
|
||||||
$count = apply_filters( 'scliveticker_catlit', $instance['count'] );
|
$count = apply_filters( 'scliveticker_catlit', $instance['count'] );
|
||||||
@ -73,14 +68,14 @@ class Widget extends WP_Widget {
|
|||||||
echo $before_title . esc_html( $title ) . $after_title;
|
echo $before_title . esc_html( $title ) . $after_title;
|
||||||
}
|
}
|
||||||
|
|
||||||
echo '<div class="wp-widget-scliveticker-ticker';
|
echo '<ul class="sclt-widget';
|
||||||
if ( '1' === $ajax ) {
|
if ( '1' === $ajax ) {
|
||||||
echo ' sclt-ajax" '
|
echo ' sclt-widget-ajax" '
|
||||||
. 'data-sclt-ticker="' . esc_attr( $category ) . '" '
|
. 'data-sclt-ticker="' . esc_attr( $category ) . '" '
|
||||||
. 'data-sclt-limit="' . esc_attr( $count ) . '" '
|
. 'data-sclt-limit="' . esc_attr( $count ) . '" '
|
||||||
. 'data-sclt-last="' . esc_attr( current_datetime()->getTimestamp() );
|
. 'data-sclt-last="' . esc_attr( current_time( 'timestamp' ) );
|
||||||
}
|
}
|
||||||
echo '"><ul class="sclt-widget">';
|
echo '">';
|
||||||
|
|
||||||
$args = array(
|
$args = array(
|
||||||
'post_type' => 'scliveticker_tick',
|
'post_type' => 'scliveticker_tick',
|
||||||
@ -95,16 +90,14 @@ class Widget extends WP_Widget {
|
|||||||
|
|
||||||
$wp_query = new WP_Query( $args );
|
$wp_query = new WP_Query( $args );
|
||||||
$cnt = 0;
|
$cnt = 0;
|
||||||
while ( $wp_query->have_posts() && ( $count <= 0 || ++$cnt < $count ) ) {
|
while ( $wp_query->have_posts() && ( $count <= 0 || ++ $cnt < $count ) ) {
|
||||||
$wp_query->the_post();
|
$wp_query->the_post();
|
||||||
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
|
// @codingStandardsIgnoreLine
|
||||||
echo SCLiveticker::tick_html_widget(
|
echo SCLiveticker::tick_html_widget(
|
||||||
esc_html( get_the_time( 'd.m.Y - H:i' ) ),
|
esc_html( get_the_time( 'd.m.Y - H.i' ) ),
|
||||||
get_the_title(),
|
get_the_title(),
|
||||||
( '1' === $highlight && get_the_time( 'U' ) > ( time() - $highlight_time ) ),
|
( '1' === $highlight && get_the_time( 'U' ) > ( time() - $highlight_time ) )
|
||||||
get_the_ID()
|
|
||||||
);
|
);
|
||||||
// phpcs:enable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
echo '</ul>';
|
echo '</ul>';
|
||||||
@ -146,13 +139,7 @@ class Widget extends WP_Widget {
|
|||||||
$highlight = isset( $instance['highlight'] ) ? esc_attr( $instance['highlight'] ) : '0';
|
$highlight = isset( $instance['highlight'] ) ? esc_attr( $instance['highlight'] ) : '0';
|
||||||
$highlight_time = isset( $instance['highlight_time'] ) ? esc_attr( $instance['highlight_time'] ) : '0';
|
$highlight_time = isset( $instance['highlight_time'] ) ? esc_attr( $instance['highlight_time'] ) : '0';
|
||||||
$ajax = isset( $instance['ajax'] ) ? esc_attr( $instance['ajax'] ) : '0';
|
$ajax = isset( $instance['ajax'] ) ? esc_attr( $instance['ajax'] ) : '0';
|
||||||
$categories = get_terms(
|
$categories = get_terms( 'scliveticker_ticker', 'orderby=name&order=ASC' );
|
||||||
array(
|
|
||||||
'taxonomy' => 'scliveticker_ticker',
|
|
||||||
'orderby' => 'name',
|
|
||||||
'order' => 'ASC',
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
include SCLIVETICKER_DIR . 'views/widget-form.php';
|
include SCLIVETICKER_DIR . 'views/widget-form.php';
|
||||||
}
|
}
|
||||||
@ -164,7 +151,7 @@ class Widget extends WP_Widget {
|
|||||||
*
|
*
|
||||||
* @return array Complete instance configuration.
|
* @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(
|
$default = array(
|
||||||
'title' => '',
|
'title' => '',
|
||||||
'category' => '',
|
'category' => '',
|
@ -4,19 +4,14 @@
|
|||||||
*
|
*
|
||||||
* This file contains the plugin's base class.
|
* This file contains the plugin's base class.
|
||||||
*
|
*
|
||||||
* @package SCLiveticker
|
* @package Liveticker
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace SCLiveticker;
|
|
||||||
|
|
||||||
use WP_Query;
|
|
||||||
|
|
||||||
// Exit if accessed directly.
|
// Exit if accessed directly.
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Liveticker.
|
* Liveticker.
|
||||||
*/
|
*/
|
||||||
@ -26,7 +21,7 @@ class SCLiveticker {
|
|||||||
*
|
*
|
||||||
* @var string OPTIONS
|
* @var string OPTIONS
|
||||||
*/
|
*/
|
||||||
const VERSION = '1.3.0';
|
const VERSION = '1.0.0';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options tag.
|
* Options tag.
|
||||||
@ -38,9 +33,9 @@ class SCLiveticker {
|
|||||||
/**
|
/**
|
||||||
* Plugin options.
|
* Plugin options.
|
||||||
*
|
*
|
||||||
* @var array $options
|
* @var array $_options
|
||||||
*/
|
*/
|
||||||
protected static $options;
|
protected static $_options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marker if shortcode is present.
|
* Marker if shortcode is present.
|
||||||
@ -62,7 +57,7 @@ class SCLiveticker {
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function init(): void {
|
public static function init() {
|
||||||
// Skip on autosave.
|
// Skip on autosave.
|
||||||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||||||
return;
|
return;
|
||||||
@ -71,17 +66,13 @@ class SCLiveticker {
|
|||||||
// Load plugin options.
|
// Load plugin options.
|
||||||
self::update_options();
|
self::update_options();
|
||||||
|
|
||||||
// Add filter for REST API queries.
|
// Skip on AJAX if not enabled disabled.
|
||||||
add_filter( 'rest_api_init', array( 'SCLiveticker\\Api', 'init' ) );
|
if ( ( ! isset( self::$_options['enable_ajax'] ) || 1 !== self::$_options['enable_ajax'] ) && ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
|
||||||
add_filter( 'rest_scliveticker_tick_query', array( 'SCLiveticker\\Api', 'tick_query_filter' ), 10, 2 );
|
|
||||||
|
|
||||||
// Skip on AJAX if not enabled.
|
|
||||||
if ( ( ! isset( self::$options['enable_ajax'] ) || 1 !== self::$options['enable_ajax'] ) && ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load Textdomain.
|
// Load Textdomain.
|
||||||
load_plugin_textdomain( 'stklcode-liveticker' );
|
load_plugin_textdomain( 'stklcode-liveticker', false );
|
||||||
|
|
||||||
// Allow shortcodes in widgets.
|
// Allow shortcodes in widgets.
|
||||||
add_filter( 'widget_text', 'do_shortcode' );
|
add_filter( 'widget_text', 'do_shortcode' );
|
||||||
@ -89,11 +80,14 @@ class SCLiveticker {
|
|||||||
// Add shortcode.
|
// Add shortcode.
|
||||||
add_shortcode( 'liveticker', array( __CLASS__, 'shortcode_ticker_show' ) );
|
add_shortcode( 'liveticker', array( __CLASS__, 'shortcode_ticker_show' ) );
|
||||||
|
|
||||||
// Enqueue styles and JavaScript.
|
// Enqueue styles.
|
||||||
add_action( 'wp_footer', array( __CLASS__, 'enqueue_resources' ) );
|
add_action( 'wp_footer', array( __CLASS__, 'enqueue_styles' ) );
|
||||||
|
|
||||||
|
// Enqueue JavaScript.
|
||||||
|
add_action( 'wp_footer', array( __CLASS__, 'enqueue_scripts' ) );
|
||||||
|
|
||||||
// Add AJAX hook if configured.
|
// Add AJAX hook if configured.
|
||||||
if ( 1 === self::$options['enable_ajax'] ) {
|
if ( 1 === self::$_options['enable_ajax'] ) {
|
||||||
add_action( 'wp_ajax_sclt_update-ticks', array( __CLASS__, 'ajax_update' ) );
|
add_action( 'wp_ajax_sclt_update-ticks', array( __CLASS__, 'ajax_update' ) );
|
||||||
add_action( 'wp_ajax_nopriv_sclt_update-ticks', array( __CLASS__, 'ajax_update' ) );
|
add_action( 'wp_ajax_nopriv_sclt_update-ticks', array( __CLASS__, 'ajax_update' ) );
|
||||||
}
|
}
|
||||||
@ -101,11 +95,11 @@ class SCLiveticker {
|
|||||||
// Admin only actions.
|
// Admin only actions.
|
||||||
if ( is_admin() ) {
|
if ( is_admin() ) {
|
||||||
// Add dashboard "right now" functionality.
|
// Add dashboard "right now" functionality.
|
||||||
add_action( 'right_now_content_table_end', array( 'SCLiveticker\\Admin', 'dashboard_right_now' ) );
|
add_action( 'right_now_content_table_end', array( 'SCLiveticker_Admin', 'dashboard_right_now' ) );
|
||||||
|
|
||||||
// Settings.
|
// 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' ) );
|
add_action( 'admin_menu', array( 'SCLiveticker_Admin', 'register_settings_page' ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,11 +108,11 @@ class SCLiveticker {
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function register_types(): void {
|
public static function register_types() {
|
||||||
// Add new taxonomy, make it hierarchical (like categories).
|
// Add new taxonomy, make it hierarchical (like categories).
|
||||||
$labels = array(
|
$labels = array(
|
||||||
'name' => _x( 'Ticker', 'taxonomy general name', 'stklcode-liveticker' ),
|
'name' => _x( 'Ticker', 'taxonomy general name' ),
|
||||||
'singular_name' => _x( 'Ticker', 'taxonomy singular name', 'stklcode-liveticker' ),
|
'singular_name' => _x( 'Ticker', 'taxonomy singular name' ),
|
||||||
'search_items' => __( 'Search Tickers', 'stklcode-liveticker' ),
|
'search_items' => __( 'Search Tickers', 'stklcode-liveticker' ),
|
||||||
'all_items' => __( 'All Tickers', 'stklcode-liveticker' ),
|
'all_items' => __( 'All Tickers', 'stklcode-liveticker' ),
|
||||||
'parent_item' => __( 'Parent Ticker', 'stklcode-liveticker' ),
|
'parent_item' => __( 'Parent Ticker', 'stklcode-liveticker' ),
|
||||||
@ -139,7 +133,6 @@ class SCLiveticker {
|
|||||||
'show_ui' => true,
|
'show_ui' => true,
|
||||||
'show_admin_column' => true,
|
'show_admin_column' => true,
|
||||||
'query_var' => true,
|
'query_var' => true,
|
||||||
'show_in_rest' => true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -169,7 +162,6 @@ class SCLiveticker {
|
|||||||
'supports' => array( 'title', 'editor', 'author' ),
|
'supports' => array( 'title', 'editor', 'author' ),
|
||||||
'taxonomies' => array( 'scliveticker_ticker' ),
|
'taxonomies' => array( 'scliveticker_ticker' ),
|
||||||
'has_archive' => true,
|
'has_archive' => true,
|
||||||
'show_in_rest' => true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
register_post_type( 'scliveticker_tick', $args );
|
register_post_type( 'scliveticker_tick', $args );
|
||||||
@ -182,7 +174,7 @@ class SCLiveticker {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @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).
|
// Indicate presence of shortcode (to enqueue styles/scripts later).
|
||||||
self::$shortcode_present = true;
|
self::$shortcode_present = true;
|
||||||
|
|
||||||
@ -203,8 +195,18 @@ class SCLiveticker {
|
|||||||
if ( isset( $atts['feed'] ) ) {
|
if ( isset( $atts['feed'] ) ) {
|
||||||
$show_feed = 'true' === strtolower( $atts['feed'] ) || '1' === $atts['feed'];
|
$show_feed = 'true' === strtolower( $atts['feed'] ) || '1' === $atts['feed'];
|
||||||
} else {
|
} else {
|
||||||
$show_feed = 1 === self::$options['show_feed'];
|
$show_feed = 1 === self::$_options['show_feed'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$output = '<ul class="sclt-ticker';
|
||||||
|
if ( 1 === self::$_options['enable_ajax'] ) {
|
||||||
|
$output .= ' sclt-ticker-ajax" '
|
||||||
|
. 'data-sclt-ticker="' . $ticker . '" '
|
||||||
|
. 'data-sclt-limit="' . $limit . '" '
|
||||||
|
. 'data-sclt-last="' . current_time( 'timestamp' );
|
||||||
|
}
|
||||||
|
$output .= '">';
|
||||||
|
|
||||||
$args = array(
|
$args = array(
|
||||||
'post_type' => 'scliveticker_tick',
|
'post_type' => 'scliveticker_tick',
|
||||||
'posts_per_page' => $limit,
|
'posts_per_page' => $limit,
|
||||||
@ -219,32 +221,20 @@ class SCLiveticker {
|
|||||||
|
|
||||||
$wp_query = new WP_Query( $args );
|
$wp_query = new WP_Query( $args );
|
||||||
|
|
||||||
$ticks = '';
|
|
||||||
$last = null;
|
|
||||||
while ( $wp_query->have_posts() ) {
|
while ( $wp_query->have_posts() ) {
|
||||||
$wp_query->the_post();
|
$wp_query->the_post();
|
||||||
$ticks .= self::tick_html( get_the_time( 'd.m.Y H:i' ), get_the_title(), get_the_content(), get_the_ID() );
|
$output .= self::tick_html( get_the_time( 'd.m.Y H.i' ), get_the_title(), get_the_content() );
|
||||||
if ( is_null( $last ) ) {
|
|
||||||
$last = get_post_modified_time( 'Y-m-d\TH:i:s', true );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$output = '<div class="wp-block-scliveticker-ticker';
|
$output .= '</ul>';
|
||||||
if ( 1 === self::$options['enable_ajax'] ) {
|
|
||||||
$output .= ' sclt-ajax" '
|
|
||||||
. 'data-sclt-ticker="' . esc_attr( $ticker ) . '" '
|
|
||||||
. 'data-sclt-limit="' . $limit . '" '
|
|
||||||
. 'data-sclt-last="' . $last;
|
|
||||||
}
|
|
||||||
$output .= '"><ul>' . $ticks . '</ul></div>';
|
|
||||||
|
|
||||||
// Show RSS feed link, if configured.
|
// Show RSS feed link, if configured.
|
||||||
if ( $show_feed ) {
|
if ( $show_feed ) {
|
||||||
$feed_link = get_post_type_archive_feed_link( 'scliveticker_tick' ) . '';
|
$feed_link = get_post_type_archive_feed_link( 'scliveticker_tick' ) . '';
|
||||||
if ( false === strpos( $feed_link, '&' ) ) {
|
if ( false === strpos( $feed_link, '&' ) ) {
|
||||||
$feed_link .= '?scliveticker_ticker=' . rawurlencode( $ticker );
|
$feed_link .= '?scliveticker_ticker=' . $ticker;
|
||||||
} else {
|
} else {
|
||||||
$feed_link .= '&scliveticker_ticker=' . rawurlencode( $ticker );
|
$feed_link .= '&scliveticker_ticker=' . $ticker;
|
||||||
}
|
}
|
||||||
$output .= '<a href="' . esc_attr( $feed_link ) . '">Feed</a>';
|
$output .= '<a href="' . esc_attr( $feed_link ) . '">Feed</a>';
|
||||||
}
|
}
|
||||||
@ -253,15 +243,31 @@ class SCLiveticker {
|
|||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register frontend CSS.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function enqueue_styles() {
|
||||||
|
// Only add if shortcode is present.
|
||||||
|
if ( self::$shortcode_present || self::$widget_present ) {
|
||||||
|
wp_enqueue_style(
|
||||||
|
'wplt-css',
|
||||||
|
SCLIVETICKER_BASE . 'styles/liveticker.min.css',
|
||||||
|
'',
|
||||||
|
self::VERSION, 'all'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register frontend JS.
|
* Register frontend JS.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
* @since 1.1 Combined former methods "enqueue_styles" and "enqueue_scripts".
|
|
||||||
*/
|
*/
|
||||||
public static function enqueue_resources(): void {
|
public static function enqueue_scripts() {
|
||||||
// Only add if shortcode is present.
|
// Only add if shortcode is present.
|
||||||
if ( self::$shortcode_present || self::$widget_present || has_block( 'scliveticker/ticker' ) ) {
|
if ( self::$shortcode_present || self::$widget_present ) {
|
||||||
wp_enqueue_script(
|
wp_enqueue_script(
|
||||||
'scliveticker-js',
|
'scliveticker-js',
|
||||||
SCLIVETICKER_BASE . 'scripts/liveticker.min.js',
|
SCLIVETICKER_BASE . 'scripts/liveticker.min.js',
|
||||||
@ -273,25 +279,13 @@ class SCLiveticker {
|
|||||||
// Add endpoint to script.
|
// Add endpoint to script.
|
||||||
wp_localize_script(
|
wp_localize_script(
|
||||||
'scliveticker-js',
|
'scliveticker-js',
|
||||||
'scliveticker',
|
'sclivetickerAjax',
|
||||||
array(
|
array(
|
||||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||||
'nonce' => wp_create_nonce( 'scliveticker_update-ticks' ),
|
'nonce' => wp_create_nonce( 'scliveticker_update-ticks' ),
|
||||||
'api' => rest_url(),
|
'poll_interval' => self::$_options['poll_interval'] * 1000,
|
||||||
'embedded_script' => boolval( self::$options['embedded_script'] ),
|
|
||||||
'poll_interval' => self::$options['poll_interval'] * 1000,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Enqueue CSS if enabled.
|
|
||||||
if ( 1 === self::$options['enable_css'] ) {
|
|
||||||
wp_enqueue_style(
|
|
||||||
'sclt-css',
|
|
||||||
SCLIVETICKER_BASE . 'styles/liveticker.min.css',
|
|
||||||
'',
|
|
||||||
self::VERSION
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,14 +294,14 @@ class SCLiveticker {
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function ajax_update(): void {
|
public static function ajax_update() {
|
||||||
// Verify AJAX nonce.
|
// Verify AJAX nonce.
|
||||||
check_ajax_referer( 'scliveticker_update-ticks' );
|
check_ajax_referer( 'scliveticker_update-ticks' );
|
||||||
|
|
||||||
// Extract update requests.
|
// Extract update requests.
|
||||||
if ( isset( $_POST['update'] ) && is_array( $_POST['update'] ) ) { // Input var okay.
|
if ( isset( $_POST['update'] ) && is_array( $_POST['update'] ) ) { // Input var okay.
|
||||||
$res = array();
|
$res = array();
|
||||||
// @codingStandardsIgnoreLine Sanitization of array handled on field level.
|
// @codingStandardsIgnoreLine Sanitization of arrayhandled on field level.
|
||||||
foreach ( wp_unslash( $_POST['update'] ) as $update_req ) {
|
foreach ( wp_unslash( $_POST['update'] ) as $update_req ) {
|
||||||
if ( is_array( $update_req ) && ( isset( $update_req['s'] ) || isset( $update_req['w'] ) ) ) {
|
if ( is_array( $update_req ) && ( isset( $update_req['s'] ) || isset( $update_req['w'] ) ) ) {
|
||||||
if ( isset( $update_req['s'] ) ) {
|
if ( isset( $update_req['s'] ) ) {
|
||||||
@ -317,18 +311,12 @@ class SCLiveticker {
|
|||||||
$is_widget = true;
|
$is_widget = true;
|
||||||
$slug = sanitize_text_field( $update_req['w'] );
|
$slug = sanitize_text_field( $update_req['w'] );
|
||||||
} else {
|
} else {
|
||||||
// Should never occur, but for completeness' sake...
|
// Should never occur, but for completenes' sake...
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$limit = ( isset( $update_req['l'] ) ) ? intval( $update_req['l'] ) : - 1;
|
$limit = ( isset( $update_req['l'] ) ) ? intval( $update_req['l'] ) : - 1;
|
||||||
$last_poll = explode(
|
$last_poll = ( isset( $update_req['t'] ) ) ? intval( $update_req['t'] ) : 0;
|
||||||
',',
|
|
||||||
gmdate(
|
|
||||||
'Y,m,d,H,i,s',
|
|
||||||
( isset( $update_req['t'] ) ) ? intval( $update_req['t'] ) : 0
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Query new ticks from DB.
|
// Query new ticks from DB.
|
||||||
$query_args = array(
|
$query_args = array(
|
||||||
@ -342,15 +330,7 @@ class SCLiveticker {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
'date_query' => array(
|
'date_query' => array(
|
||||||
'column' => 'post_date_gmt',
|
'after' => date( 'c', $last_poll ),
|
||||||
'after' => array(
|
|
||||||
'year' => intval( $last_poll[0] ),
|
|
||||||
'month' => intval( $last_poll[1] ),
|
|
||||||
'day' => intval( $last_poll[2] ),
|
|
||||||
'hour' => intval( $last_poll[3] ),
|
|
||||||
'minute' => intval( $last_poll[4] ),
|
|
||||||
'second' => intval( $last_poll[5] ),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -360,9 +340,9 @@ class SCLiveticker {
|
|||||||
while ( $query->have_posts() ) {
|
while ( $query->have_posts() ) {
|
||||||
$query->the_post();
|
$query->the_post();
|
||||||
if ( $is_widget ) {
|
if ( $is_widget ) {
|
||||||
$out .= self::tick_html_widget( get_the_time( 'd.m.Y H:i' ), get_the_title(), false, get_the_ID() );
|
$out .= self::tick_html_widget( get_the_time( 'd.m.Y H.i' ), get_the_title(), false );
|
||||||
} else {
|
} else {
|
||||||
$out .= self::tick_html( get_the_time( 'd.m.Y H:i' ), get_the_title(), get_the_content(), get_the_ID() );
|
$out .= self::tick_html( get_the_time( 'd.m.Y H.i' ), get_the_title(), get_the_content(), $is_widget );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,13 +350,13 @@ class SCLiveticker {
|
|||||||
$res[] = array(
|
$res[] = array(
|
||||||
'w' => $slug,
|
'w' => $slug,
|
||||||
'h' => $out,
|
'h' => $out,
|
||||||
't' => time(),
|
't' => current_time( 'timestamp' ),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$res[] = array(
|
$res[] = array(
|
||||||
's' => $slug,
|
's' => $slug,
|
||||||
'h' => $out,
|
'h' => $out,
|
||||||
't' => time(),
|
't' => current_time( 'timestamp' ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -393,20 +373,19 @@ class SCLiveticker {
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function mark_widget_present(): void {
|
public static function mark_widget_present() {
|
||||||
self::$widget_present = true;
|
self::$widget_present = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update options.
|
* Update options.
|
||||||
*
|
*
|
||||||
* @return void
|
* @param array $options Optional. New options to save.
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @return void
|
||||||
* @since 1.3.0 removed unused parameter
|
|
||||||
*/
|
*/
|
||||||
protected static function update_options(): void {
|
protected static function update_options( $options = null ) {
|
||||||
self::$options = wp_parse_args(
|
self::$_options = wp_parse_args(
|
||||||
get_option( self::OPTION ),
|
get_option( self::OPTION ),
|
||||||
self::default_options()
|
self::default_options()
|
||||||
);
|
);
|
||||||
@ -417,37 +396,31 @@ class SCLiveticker {
|
|||||||
*
|
*
|
||||||
* @return array The options array.
|
* @return array The options array.
|
||||||
*/
|
*/
|
||||||
protected static function default_options(): array {
|
protected static function default_options() {
|
||||||
return array(
|
return array(
|
||||||
'enable_ajax' => 1,
|
'enable_ajax' => 1,
|
||||||
'poll_interval' => 60,
|
'poll_interval' => 60,
|
||||||
'enable_css' => 1,
|
'enable_css' => 1,
|
||||||
'show_feed' => 0,
|
'show_feed' => 0,
|
||||||
'enable_shortcode' => 0,
|
'reset_settings' => 0,
|
||||||
'embedded_script' => 0,
|
|
||||||
'reset_settings' => 0,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate HTML code for a tick element.
|
* Generate HTML code for a tick element.
|
||||||
*
|
*
|
||||||
* @param string $time Tick time (readable).
|
* @param string $time Tick time (readable).
|
||||||
* @param string $title Tick title.
|
* @param string $title Tick title.
|
||||||
* @param string $content Tick content.
|
* @param string $content Tick content.
|
||||||
* @param integer $id Tick ID.
|
* @param boolean $is_widget Is the code for Widget.
|
||||||
*
|
*
|
||||||
* @return string HTML code of tick.
|
* @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, $is_widget = false ) {
|
||||||
if ( self::$options['enable_shortcode'] ) {
|
return '<li class="sclt-tick">'
|
||||||
$content = do_shortcode( $content );
|
. '<p><span class="sclt-tick_time">' . esc_html( $time ) . '</span>'
|
||||||
}
|
. '<span class="sclt-tick-title">' . esc_html( $title ) . '</span></p>'
|
||||||
|
. '<p class="sclt-tick-content">' . $content . '</p></li>';
|
||||||
return '<li class="sclt-tick" data-sclt-tick-id="' . esc_attr( $id ) . '">'
|
|
||||||
. '<span class="sclt-tick-time">' . esc_html( $time ) . '</span>'
|
|
||||||
. '<span class="sclt-tick-title">' . esc_html( $title ) . '</span>'
|
|
||||||
. '<div class="sclt-tick-content">' . $content . '</div></li>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -456,18 +429,14 @@ class SCLiveticker {
|
|||||||
* @param string $time Tick time (readable).
|
* @param string $time Tick time (readable).
|
||||||
* @param string $title Tick title.
|
* @param string $title Tick title.
|
||||||
* @param boolean $highlight Highlight element.
|
* @param boolean $highlight Highlight element.
|
||||||
* @param integer $id Tick ID.
|
|
||||||
*
|
*
|
||||||
* @return string HTML code of widget tick.
|
* @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 ) {
|
||||||
$out = '<li';
|
$out = '<li';
|
||||||
if ( $highlight ) {
|
if ( $highlight ) {
|
||||||
$out .= ' class="sclt-widget-new"';
|
$out .= ' class="sclt-widget-new"';
|
||||||
}
|
}
|
||||||
if ( $id > 0 ) {
|
|
||||||
$out .= ' data-sclt-tick-id="' . esc_attr( $id ) . '"';
|
|
||||||
}
|
|
||||||
return $out . '>'
|
return $out . '>'
|
||||||
. '<span class="sclt-widget-time">' . esc_html( $time ) . '</span>'
|
. '<span class="sclt-widget-time">' . esc_html( $time ) . '</span>'
|
||||||
. '<span class="sclt-widget-title">' . $title . '</span>'
|
. '<span class="sclt-widget-title">' . $title . '</span>'
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
88
package-lock.json
generated
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
{
|
||||||
|
"name": "wp-liveticker2",
|
||||||
|
"version": "1.0.0-beta",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"cssesc": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-S2hzrpWvE6G/rW7i7IxJfWBYn27QWfOIncUW++8Rbo1VB5zsJDSVPcnI+Q8z7rhxT6/yZeLOCja4cZnghJrNGA=="
|
||||||
|
},
|
||||||
|
"indexes-of": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc="
|
||||||
|
},
|
||||||
|
"lodash": {
|
||||||
|
"version": "4.17.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
||||||
|
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
|
||||||
|
},
|
||||||
|
"postcss-media-query-parser": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz",
|
||||||
|
"integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ="
|
||||||
|
},
|
||||||
|
"postcss-resolve-nested-selector": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
|
||||||
|
"integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4="
|
||||||
|
},
|
||||||
|
"postcss-selector-parser": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-5h+MvEjnzu1qy6MabjuoPatsGAjjDV9B24e7Cktjl+ClNtjVjmvAXjOFQr1u7RlWULKNGYaYVE4s+DIIQ4bOGA==",
|
||||||
|
"requires": {
|
||||||
|
"cssesc": "^1.0.1",
|
||||||
|
"indexes-of": "^1.0.1",
|
||||||
|
"uniq": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"postcss-value-parser": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
|
||||||
|
},
|
||||||
|
"stylelint-config-recommended": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-ajMbivOD7JxdsnlS5945KYhvt7L/HwN6YeYF2BH6kE4UCLJR0YvXMf+2j7nQpJyYLZx9uZzU5G1ZOSBiWAc6yA=="
|
||||||
|
},
|
||||||
|
"stylelint-config-recommended-scss": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-M8BFHMRf8KNz5EQPKJd8nMCGmBd2o5coDEObfHVbEkyLDgjIf1V+U5dHjaGgvhm0zToUxshxN+Gc5wpbOOew4g==",
|
||||||
|
"requires": {
|
||||||
|
"stylelint-config-recommended": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"stylelint-config-wordpress": {
|
||||||
|
"version": "13.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylelint-config-wordpress/-/stylelint-config-wordpress-13.1.0.tgz",
|
||||||
|
"integrity": "sha512-dpKj2/d3/XjDVoOvQzd54GoM8Rj5zldluOZKkVhBCc4JYMc6r1VYL5hpcgIjqy/i2Hyqg4Rh7zTafE/2AWq//w==",
|
||||||
|
"requires": {
|
||||||
|
"stylelint-config-recommended": "^2.1.0",
|
||||||
|
"stylelint-config-recommended-scss": "^3.2.0",
|
||||||
|
"stylelint-scss": "^3.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"stylelint-scss": {
|
||||||
|
"version": "3.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-3.3.2.tgz",
|
||||||
|
"integrity": "sha512-0x+nD1heoMJYOfi3FfGcz3Hrwhcm+Qyq+BuvoBv5v9xrZZ1aziRXQauuhjwb87gWAa9MBzxhfUqBnvTUrHlLjA==",
|
||||||
|
"requires": {
|
||||||
|
"lodash": "^4.17.10",
|
||||||
|
"postcss-media-query-parser": "^0.2.3",
|
||||||
|
"postcss-resolve-nested-selector": "^0.1.1",
|
||||||
|
"postcss-selector-parser": "^4.0.0",
|
||||||
|
"postcss-value-parser": "^3.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniq": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
package.json
@ -1,13 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "stklcode-liveticker",
|
"name": "wp-liveticker",
|
||||||
"version": "1.3.0",
|
"version": "1.0.0",
|
||||||
"description": "A simple Liveticker for Wordpress.",
|
"description": "A simple Liveticker for Wordpress.",
|
||||||
"author": "Stefan Kalscheuer",
|
"author": "Stefan Kalscheuer",
|
||||||
"license": "GPL-2.0+",
|
"license": "GPL-2.0+",
|
||||||
"devDependencies": {
|
"dependencies": {
|
||||||
"@wordpress/eslint-plugin": "^22",
|
"stylelint-config-wordpress": "^13.1.0"
|
||||||
"@wordpress/stylelint-config": "^23",
|
|
||||||
"eslint": "^8",
|
|
||||||
"stylelint": "^16"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
phpcs.xml
@ -12,19 +12,12 @@
|
|||||||
<file>views</file>
|
<file>views</file>
|
||||||
|
|
||||||
<!-- Compliance with WordPress Coding Standard -->
|
<!-- Compliance with WordPress Coding Standard -->
|
||||||
<config name="minimum_supported_wp_version" value="5.0"/>
|
<config name="minimum_supported_wp_version" value="4.0"/>
|
||||||
<rule ref="WordPress">
|
<rule ref="WordPress">
|
||||||
<exclude name="WordPress.DB.SlowDBQuery.slow_db_query_tax_query"/>
|
<exclude name="WordPress.VIP.SlowDBQuery.slow_db_query_tax_query"/>
|
||||||
</rule>
|
|
||||||
|
|
||||||
<!-- Verify usage of the correct textdomain for WP translation -->
|
|
||||||
<rule ref="WordPress.WP.I18n">
|
|
||||||
<properties>
|
|
||||||
<property name="text_domain" type="array" value="stklcode-liveticker"/>
|
|
||||||
</properties>
|
|
||||||
</rule>
|
</rule>
|
||||||
|
|
||||||
<!-- PHP compatibility level -->
|
<!-- PHP compatibility level -->
|
||||||
<config name="testVersion" value="7.2-"/>
|
<config name="testVersion" value="5.2-"/>
|
||||||
<rule ref="PHPCompatibilityWP"/>
|
<rule ref="PHPCompatibility"/>
|
||||||
</ruleset>
|
</ruleset>
|
||||||
|
15
phpunit.xml
@ -1,19 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<phpunit bootstrap="tests/bootstrap.php"
|
<phpunit bootstrap="./vendor/autoload.php">
|
||||||
backupGlobals="false"
|
|
||||||
colors="true"
|
|
||||||
convertErrorsToExceptions="true"
|
|
||||||
convertNoticesToExceptions="true"
|
|
||||||
convertWarningsToExceptions="true">
|
|
||||||
<testsuites>
|
<testsuites>
|
||||||
<testsuite name="WP Liveticker 2 TestSuite">
|
<testsuite name="WP Liveticker 2 TestSuite">
|
||||||
<directory prefix="test-" suffix=".php">./tests/</directory>
|
<directory suffix="-test.php">./test/</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
<filter>
|
|
||||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
|
||||||
<directory suffix=".php">includes</directory>
|
|
||||||
</whitelist>
|
|
||||||
</filter>
|
|
||||||
</phpunit>
|
</phpunit>
|
||||||
|
215
scripts/block.js
@ -1,215 +0,0 @@
|
|||||||
/**
|
|
||||||
* stklcode-liveticker Gutenberg Block
|
|
||||||
*
|
|
||||||
* Gutenberg Block to integrate the liveticker widget without shortcode.
|
|
||||||
*/
|
|
||||||
( function() {
|
|
||||||
var __ = wp.i18n.__;
|
|
||||||
var registerBlockType = wp.blocks.registerBlockType;
|
|
||||||
var registerStore = wp.data.registerStore;
|
|
||||||
var withSelect = wp.data.withSelect;
|
|
||||||
var el = wp.element.createElement;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Datastore actions.
|
|
||||||
*/
|
|
||||||
var actions = {
|
|
||||||
setTickers: function( tickers ) {
|
|
||||||
return {
|
|
||||||
type: 'SET_TICKERS',
|
|
||||||
tickers: tickers,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
getTickers: function( path ) {
|
|
||||||
return {
|
|
||||||
type: 'RECEIVE_TICKERS',
|
|
||||||
path: path,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
registerStore( 'scliveticker/ticker', {
|
|
||||||
reducer: function( state, action ) {
|
|
||||||
if ( undefined === state ) {
|
|
||||||
state = { tickers: null };
|
|
||||||
}
|
|
||||||
switch ( action.type ) {
|
|
||||||
case 'SET_TICKERS':
|
|
||||||
state.tickers = action.tickers;
|
|
||||||
return state;
|
|
||||||
case 'RECEIVE_TICKERS':
|
|
||||||
return action.tickers;
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: actions,
|
|
||||||
|
|
||||||
selectors: {
|
|
||||||
receiveTickers: function( state ) {
|
|
||||||
return state.tickers;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
resolvers: {
|
|
||||||
receiveTickers: function() {
|
|
||||||
return wp.apiFetch( { path: '/wp/v2/scliveticker_ticker' } ).then( function( tickers ) {
|
|
||||||
return actions.setTickers( tickers.map( function( t ) {
|
|
||||||
return {
|
|
||||||
name: t.name,
|
|
||||||
slug: t.slug,
|
|
||||||
};
|
|
||||||
} ) );
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} );
|
|
||||||
|
|
||||||
registerBlockType( 'scliveticker/ticker', {
|
|
||||||
title: __( 'Liveticker', 'stklcode-liveticker' ),
|
|
||||||
icon: 'rss',
|
|
||||||
category: 'widgets',
|
|
||||||
keywords: [
|
|
||||||
__( 'Liveticker', 'stklcode-liveticker' ),
|
|
||||||
],
|
|
||||||
attributes: {
|
|
||||||
ticker: {
|
|
||||||
type: 'string',
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
limit: {
|
|
||||||
type: 'number',
|
|
||||||
default: 5,
|
|
||||||
},
|
|
||||||
unlimited: {
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
sort: {
|
|
||||||
type: 'string',
|
|
||||||
// implicit default: 'desc', left empty here for backwards compatibility of the block
|
|
||||||
},
|
|
||||||
},
|
|
||||||
edit: withSelect( function( select ) {
|
|
||||||
return {
|
|
||||||
tickers: select( 'scliveticker/ticker' ).receiveTickers(),
|
|
||||||
};
|
|
||||||
} )( function( props ) {
|
|
||||||
var label = [
|
|
||||||
el(
|
|
||||||
wp.components.Dashicon,
|
|
||||||
{ icon: 'rss' }
|
|
||||||
),
|
|
||||||
__( 'Liveticker', 'stklcode-liveticker' ),
|
|
||||||
];
|
|
||||||
var content;
|
|
||||||
if ( null === props.tickers ) {
|
|
||||||
// Tickers not yet loaded.
|
|
||||||
content = [
|
|
||||||
el(
|
|
||||||
'span',
|
|
||||||
{ className: 'components-base-control label' },
|
|
||||||
label
|
|
||||||
),
|
|
||||||
el( wp.components.Spinner ),
|
|
||||||
];
|
|
||||||
} else if ( 0 === props.tickers.length ) {
|
|
||||||
// No tickers available.
|
|
||||||
content = [
|
|
||||||
el(
|
|
||||||
'span',
|
|
||||||
{ className: 'components-base-control label' },
|
|
||||||
label
|
|
||||||
),
|
|
||||||
el( 'span', null, __( 'No tickers available', 'stklcode-liveticker' ) ),
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
// Tickers loaded and available.
|
|
||||||
if ( 0 === props.attributes.ticker.length && props.tickers.length > 0 ) {
|
|
||||||
props.attributes.ticker = props.tickers[ 0 ].slug;
|
|
||||||
}
|
|
||||||
content = [
|
|
||||||
el(
|
|
||||||
wp.components.SelectControl,
|
|
||||||
{
|
|
||||||
label: label,
|
|
||||||
value: props.attributes.ticker,
|
|
||||||
options: props.tickers.map( function( t ) {
|
|
||||||
return {
|
|
||||||
value: t.slug,
|
|
||||||
label: t.name,
|
|
||||||
};
|
|
||||||
} ),
|
|
||||||
onChange: function( val ) {
|
|
||||||
props.setAttributes( { ticker: val } );
|
|
||||||
},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
el(
|
|
||||||
wp.components.TextControl,
|
|
||||||
{
|
|
||||||
label: __( 'Number of Ticks', 'stklcode-liveticker' ),
|
|
||||||
type: 'number',
|
|
||||||
min: 1,
|
|
||||||
step: 1,
|
|
||||||
disabled: props.attributes.unlimited,
|
|
||||||
value: props.attributes.limit,
|
|
||||||
onChange: function( val ) {
|
|
||||||
props.setAttributes( { limit: Number( val ) } );
|
|
||||||
},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
el(
|
|
||||||
wp.components.CheckboxControl,
|
|
||||||
{
|
|
||||||
label: __( 'unlimited', 'stklcode-liveticker' ),
|
|
||||||
checked: props.attributes.unlimited,
|
|
||||||
onChange: function( val ) {
|
|
||||||
props.setAttributes( { unlimited: val } );
|
|
||||||
},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
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 } );
|
|
||||||
},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return el(
|
|
||||||
'div',
|
|
||||||
{ className: props.className + ' components-placeholder' },
|
|
||||||
content
|
|
||||||
);
|
|
||||||
} ),
|
|
||||||
save: function( props ) {
|
|
||||||
return el(
|
|
||||||
'div',
|
|
||||||
{
|
|
||||||
className: 'sclt-ajax',
|
|
||||||
'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,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
} );
|
|
||||||
}() );
|
|
@ -1,265 +1,154 @@
|
|||||||
/**
|
/**
|
||||||
* Constructor of the scLiveticker object.
|
* Contructor of the scLiveticker object.
|
||||||
*
|
*
|
||||||
* @class
|
* @constructor
|
||||||
*/
|
*/
|
||||||
( function() {
|
function scLiveticker() {
|
||||||
var apiURL;
|
}
|
||||||
var pollInterval;
|
|
||||||
var ticker;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize iveticker JS component.
|
* Initialize iveticker JS component.
|
||||||
*
|
*
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
var init = function() {
|
scLiveticker.init = function() {
|
||||||
var updateNow = false;
|
|
||||||
var c = 0;
|
|
||||||
|
|
||||||
// Opt out if AJAX pobject not present.
|
// Opt out if AJAX pobject not present.
|
||||||
if ( 'undefined' === typeof scliveticker ) {
|
if ( 'undefined' === typeof sclivetickerAjax ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract settings.
|
// Extract AJAX settings.
|
||||||
apiURL = scliveticker.api + 'wp/v2/scliveticker_tick';
|
scLiveticker.ajaxURL = sclivetickerAjax.ajax_url;
|
||||||
pollInterval = scliveticker.poll_interval;
|
scLiveticker.nonce = sclivetickerAjax.nonce;
|
||||||
|
scLiveticker.pollInterval = sclivetickerAjax.poll_interval;
|
||||||
|
|
||||||
// Get ticker elements.
|
// Get ticker elements.
|
||||||
ticker = [].map.call(
|
scLiveticker.ticker = [].map.call(
|
||||||
document.querySelectorAll( 'div.wp-block-scliveticker-ticker.sclt-ajax' ),
|
document.querySelectorAll( 'ul.sclt-ticker-ajax' ),
|
||||||
function( elem ) {
|
function( elem ) {
|
||||||
var o = parseElement( elem, false, ++c );
|
return {
|
||||||
if ( '0' === o.lastPoll ) {
|
s: elem.getAttribute( 'data-sclt-ticker' ),
|
||||||
updateNow = true;
|
l: elem.getAttribute( 'data-sclt-limit' ),
|
||||||
}
|
t: elem.getAttribute( 'data-sclt-last' ),
|
||||||
return o;
|
e: elem
|
||||||
}
|
};
|
||||||
);
|
|
||||||
|
|
||||||
// Get widget elements.
|
|
||||||
ticker.concat(
|
|
||||||
[].map.call(
|
|
||||||
document.querySelectorAll( 'div.wp-widget-scliveticker-ticker.sclt-ajax' ),
|
|
||||||
function( elem ) {
|
|
||||||
var o = parseElement( elem, true, ++c );
|
|
||||||
if ( '0' === o.lastPoll ) {
|
|
||||||
updateNow = true;
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Trigger update, if necessary.
|
|
||||||
if ( ( 0 < ticker.length ) && 0 < pollInterval ) {
|
|
||||||
if ( updateNow ) {
|
|
||||||
update();
|
|
||||||
} else {
|
|
||||||
setTimeout( update, pollInterval );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse an HTML element containing a liveticker.
|
|
||||||
*
|
|
||||||
* @param {HTMLElement} elem The element.
|
|
||||||
* @param {boolean} widget Is the element a widget?
|
|
||||||
* @param {number} n Number of the container.
|
|
||||||
* @return {{ticker: string, lastPoll: string, ticks: any, limit: string, isWidget: *}} Ticker descriptor object.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
if ( ! list ) {
|
|
||||||
list = document.createElement( 'ul' );
|
|
||||||
elem.appendChild( list );
|
|
||||||
} else {
|
|
||||||
[].forEach.call(
|
|
||||||
elem.querySelectorAll( 'li.sclt-tick' ),
|
|
||||||
function( li ) {
|
|
||||||
var id = li.getAttribute( 'data-sclt-tick-id' );
|
|
||||||
if ( id ) {
|
|
||||||
li.id = 'sclt-' + n + '-' + id;
|
|
||||||
li.removeAttribute( 'data-sclt-tick-id' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update liveticker on current page via REST API call.
|
|
||||||
*
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
var update = function() {
|
|
||||||
// Iterate over available tickers.
|
|
||||||
ticker.forEach(
|
|
||||||
function( t ) {
|
|
||||||
var xhr, query;
|
|
||||||
|
|
||||||
if ( t.updating ) {
|
|
||||||
// Do not update twice.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
t.updating = true;
|
|
||||||
xhr = new XMLHttpRequest();
|
|
||||||
query = '?ticker=' + encodeURI( t.ticker ) +
|
|
||||||
'&limit=' + encodeURI( t.limit ) +
|
|
||||||
'&last=' + encodeURI( t.lastPoll );
|
|
||||||
xhr.open( 'GET', apiURL + query, true );
|
|
||||||
xhr.addEventListener(
|
|
||||||
'load',
|
|
||||||
function() {
|
|
||||||
var updateResp;
|
|
||||||
try {
|
|
||||||
updateResp = JSON.parse( this.responseText );
|
|
||||||
if ( updateResp ) {
|
|
||||||
updateResp.reverse();
|
|
||||||
updateResp.forEach(
|
|
||||||
function( u ) {
|
|
||||||
addTick( t, u );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
t.updating = false;
|
|
||||||
} catch ( e ) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.warn( 'Liveticker AJAX update failed, stopping automatic updates.' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Re-trigger update.
|
|
||||||
setTimeout( update, pollInterval );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do actual update of HTML code.
|
|
||||||
*
|
|
||||||
* @param {Object} t Ticker or Widget reference.
|
|
||||||
* @param {Object} u Update entity.
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
var addTick = function( t, u ) {
|
|
||||||
// Parse new DOM-part.
|
|
||||||
var li = document.createElement( 'li' );
|
|
||||||
var time = document.createElement( 'span' );
|
|
||||||
var title = document.createElement( 'span' );
|
|
||||||
var content = document.createElement( 'div' );
|
|
||||||
var cls = t.isWidget ? 'sclt-widget' : 'sclt-tick';
|
|
||||||
var old;
|
|
||||||
var scripts = [];
|
|
||||||
|
|
||||||
time.classList.add( cls + '-time' );
|
|
||||||
time.innerText = u.modified_rendered;
|
|
||||||
title.classList.add( cls + '-title' );
|
|
||||||
title.innerText = u.title.rendered;
|
|
||||||
content.classList.add( cls + '-content' );
|
|
||||||
content.innerHTML = u.content.rendered;
|
|
||||||
|
|
||||||
// Process embedded scripts, if any.
|
|
||||||
if ( scliveticker.embedded_script ) {
|
|
||||||
Array.prototype.forEach.call(
|
|
||||||
content.getElementsByTagName( 'script' ),
|
|
||||||
function( script ) {
|
|
||||||
var script2;
|
|
||||||
if ( script.src ) {
|
|
||||||
// Move referenced scripts to page head.
|
|
||||||
script.parentNode.removeChild( script );
|
|
||||||
script2 = document.createElement( 'script' );
|
|
||||||
Array.prototype.forEach.call( script.attributes, function( a ) {
|
|
||||||
script2.setAttribute( a.nodeName, a.nodeValue );
|
|
||||||
} );
|
|
||||||
document.head.appendChild( script2 );
|
|
||||||
} else {
|
|
||||||
scripts.push( script );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the actual tick element.
|
|
||||||
li.id = 'sclt-' + t.id + '-' + u.id;
|
|
||||||
li.classList.add( cls );
|
|
||||||
li.appendChild( time );
|
|
||||||
li.appendChild( title );
|
|
||||||
li.appendChild( content );
|
|
||||||
|
|
||||||
old = document.getElementById( 'sclt-' + t.id + '-' + u.id );
|
|
||||||
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.
|
|
||||||
t.ticks.insertBefore( li, t.ticks.firstChild );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update last poll time.
|
|
||||||
t.lastPoll = u.date_gmt;
|
|
||||||
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(
|
|
||||||
function( l ) {
|
|
||||||
l.remove();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate embedded inline scripts.
|
|
||||||
|
|
||||||
// Directly evaluate script otherwise.
|
|
||||||
scripts.forEach( function( script ) {
|
|
||||||
try {
|
|
||||||
// eslint-disable-next-line no-eval
|
|
||||||
eval( script.innerHTML );
|
|
||||||
} catch ( e ) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.warn( 'Failed to evaluate embedded script.' );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener(
|
|
||||||
'DOMContentLoaded',
|
|
||||||
function() {
|
|
||||||
init(); // Trigger periodic update of livetickers.
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}() );
|
|
||||||
|
// Get widget elements.
|
||||||
|
scLiveticker.widgets = [].map.call(
|
||||||
|
document.querySelectorAll( 'ul.sclt-widget-ajax' ),
|
||||||
|
function( elem ) {
|
||||||
|
return {
|
||||||
|
w: elem.getAttribute( 'data-sclt-ticker' ),
|
||||||
|
l: elem.getAttribute( 'data-sclt-limit' ),
|
||||||
|
t: elem.getAttribute( 'data-sclt-last' ),
|
||||||
|
e: elem
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Trigger update, if necessary.
|
||||||
|
if ( ( 0 < scLiveticker.ticker.length || scLiveticker.widgets.length ) && 0 < scLiveticker.pollInterval ) {
|
||||||
|
setTimeout( scLiveticker.update, scLiveticker.pollInterval );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update liveticker on current page via AJAX call.
|
||||||
|
*
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
scLiveticker.update = function() {
|
||||||
|
|
||||||
|
// Extract ticker-slug, limit and timestamp of last poll.
|
||||||
|
var updateReq = 'action=sclt_update-ticks&_ajax_nonce=' + scLiveticker.nonce;
|
||||||
|
var i, j;
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
|
for ( i = 0; i < scLiveticker.ticker.length; i++ ) {
|
||||||
|
updateReq = updateReq +
|
||||||
|
'&update[' + i + '][s]=' + scLiveticker.ticker[ i ].s +
|
||||||
|
'&update[' + i + '][l]=' + scLiveticker.ticker[ i ].l +
|
||||||
|
'&update[' + i + '][t]=' + scLiveticker.ticker[ i ].t;
|
||||||
|
}
|
||||||
|
for ( j = 0; j < scLiveticker.widgets.length; j++ ) {
|
||||||
|
updateReq = updateReq +
|
||||||
|
'&update[' + ( i + j ) + '][w]=' + scLiveticker.widgets[ j ].w +
|
||||||
|
'&update[' + ( i + j ) + '][l]=' + scLiveticker.widgets[ j ].l +
|
||||||
|
'&update[' + ( i + j ) + '][t]=' + scLiveticker.widgets[ j ].t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue AJAX request.
|
||||||
|
xhr.open( 'POST', scLiveticker.ajaxURL, true );
|
||||||
|
xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded;' );
|
||||||
|
xhr.onreadystatechange = function() {
|
||||||
|
var update;
|
||||||
|
if ( XMLHttpRequest.DONE === this.readyState && 200 === this.status ) {
|
||||||
|
try {
|
||||||
|
update = JSON.parse( this.responseText );
|
||||||
|
if ( update ) {
|
||||||
|
update.forEach(
|
||||||
|
function( u ) {
|
||||||
|
scLiveticker.ticker.forEach(
|
||||||
|
function( t ) {
|
||||||
|
if ( t.s === u.s ) {
|
||||||
|
t.t = u.t; // Update last poll timestamp.
|
||||||
|
scLiveticker.updateHTML( t, u ); // Update HTML markup.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
scLiveticker.widgets.forEach(
|
||||||
|
function( t ) {
|
||||||
|
if ( t.w === u.w ) {
|
||||||
|
t.t = u.t;
|
||||||
|
scLiveticker.updateHTML( t, u );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setTimeout( scLiveticker.update, scLiveticker.pollInterval ); // Re-trigger update.
|
||||||
|
} catch ( e ) {
|
||||||
|
console.warn( 'Liveticker AJAX update failed, stopping automatic updates.' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send( updateReq );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do actual update of HTML code.
|
||||||
|
*
|
||||||
|
* @param {Object} t Ticker or Widget reference.
|
||||||
|
* @param {number} t.l Limit of entries to display.
|
||||||
|
* @param {HTMLElement} t.e HTML element of the ticker/widget.
|
||||||
|
* @param {Object} u Update entity.
|
||||||
|
* @param {string} u.h HTML code to append.
|
||||||
|
* @param {number} u.t Timetsamp of last update.
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
scLiveticker.updateHTML = function( t, u ) {
|
||||||
|
|
||||||
|
// Prepend HTML of new ticks.
|
||||||
|
t.e.innerHTML = u.h + t.e.innerHTML;
|
||||||
|
t.e.setAttribute( 'data-sclt-last', u.t );
|
||||||
|
|
||||||
|
// Remove tail, if limit is set.
|
||||||
|
if ( 0 < t.l ) {
|
||||||
|
[].slice.call( t.e.getElementsByTagName( 'li' ), t.l ).forEach(
|
||||||
|
function( li ) {
|
||||||
|
li.remove();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener(
|
||||||
|
'DOMContentLoaded',
|
||||||
|
function() {
|
||||||
|
scLiveticker.init(); // Trigger periodic update of livetickers.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
* @wordpress-plugin
|
* @wordpress-plugin
|
||||||
* Plugin Name: Liveticker (by stklcode)
|
* Plugin Name: Liveticker (by stklcode)
|
||||||
* Description: A simple Liveticker for WordPress.
|
* Description: A simple Liveticker for WordPress.
|
||||||
* Version: 1.3.0
|
* Version: 1.0.0
|
||||||
* Author: Stefan Kalscheuer
|
* Author: Stefan Kalscheuer
|
||||||
* Author URI: https://www.stklcode.de
|
* Author URI: https://www.stklcode.de
|
||||||
* Text Domain: stklcode-liveticker
|
* Text Domain: stklcode-liveticker
|
||||||
@ -26,7 +26,7 @@
|
|||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* 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.
|
// Exit if accessed directly.
|
||||||
@ -41,22 +41,19 @@ define( 'SCLIVETICKER_BASE', plugin_dir_url( __FILE__ ) );
|
|||||||
define( 'SCLIVETICKER_BASENAME', plugin_basename( __FILE__ ) );
|
define( 'SCLIVETICKER_BASENAME', plugin_basename( __FILE__ ) );
|
||||||
|
|
||||||
// System Hooks.
|
// System Hooks.
|
||||||
add_action( 'init', array( 'SCLiveticker\\SCLiveticker', 'register_types' ) );
|
add_action( 'init', array( 'SCLiveticker', 'register_types' ) );
|
||||||
add_action( 'plugins_loaded', array( 'SCLiveticker\\SCLiveticker', 'init' ) );
|
add_action( 'plugins_loaded', array( 'SCLiveticker', 'init' ) );
|
||||||
register_activation_hook( SCLIVETICKER_FILE, array( 'SCLiveticker\\System', 'activate' ) );
|
register_activation_hook( SCLIVETICKER_FILE, array( 'SCLiveticker_System', 'activate' ) );
|
||||||
register_uninstall_hook( SCLIVETICKER_FILE, array( 'SCLiveticker\\System', 'uninstall' ) );
|
register_uninstall_hook( SCLIVETICKER_FILE, array( 'SCLiveticker_System', 'uninstall' ) );
|
||||||
|
|
||||||
// Allow shortcodes in widgets.
|
// Allow shortcodes in widgets.
|
||||||
add_filter( 'widget_text', 'do_shortcode' );
|
add_filter( 'widget_text', 'do_shortcode' );
|
||||||
|
|
||||||
// Add shortcode.
|
// Add shortcode.
|
||||||
add_shortcode( 'liveticker', array( 'SCLiveticker\\SCLiveticker', 'shortcode_ticker_show' ) );
|
add_shortcode( 'liveticker', array( 'SCLiveticker', 'shortcode_ticker_show' ) );
|
||||||
|
|
||||||
// Add Widget.
|
// Add Widget.
|
||||||
add_action( 'widgets_init', array( 'SCLiveticker\\Widget', 'register' ) );
|
add_action( 'widgets_init', array( 'SCLiveticker_Widget', 'register' ) );
|
||||||
|
|
||||||
// Add Gutenberg block.
|
|
||||||
add_action( 'enqueue_block_editor_assets', array( 'SCLiveticker\\Admin', 'register_block' ) );
|
|
||||||
|
|
||||||
// Autoload.
|
// Autoload.
|
||||||
spl_autoload_register( 'scliveticker_autoload' );
|
spl_autoload_register( 'scliveticker_autoload' );
|
||||||
@ -64,24 +61,22 @@ spl_autoload_register( 'scliveticker_autoload' );
|
|||||||
/**
|
/**
|
||||||
* Autoloader for Liveticker classes.
|
* 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
|
* @return void
|
||||||
*/
|
*/
|
||||||
function scliveticker_autoload( string $class_name ): void {
|
function scliveticker_autoload( $class ) {
|
||||||
$plugin_classes = array(
|
$plugin_classes = array(
|
||||||
'SCLiveticker\\SCLiveticker',
|
'SCLiveticker',
|
||||||
'SCLiveticker\\Admin',
|
'SCLiveticker_Admin',
|
||||||
'SCLiveticker\\Api',
|
'SCLiveticker_System',
|
||||||
'SCLiveticker\\Settings',
|
'SCLiveticker_Widget',
|
||||||
'SCLiveticker\\System',
|
|
||||||
'SCLiveticker\\Widget',
|
|
||||||
);
|
);
|
||||||
if ( in_array( $class_name, $plugin_classes, true ) ) {
|
if ( in_array( $class, $plugin_classes, true ) ) {
|
||||||
require_once sprintf(
|
require_once sprintf(
|
||||||
'%s/includes/class-%s.php',
|
'%s/includes/class-%s.php',
|
||||||
SCLIVETICKER_DIR,
|
SCLIVETICKER_DIR,
|
||||||
strtolower( str_replace( '_', '-', substr( $class_name, 13 ) ) )
|
strtolower( str_replace( '_', '-', $class ) )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
div.wp-block-scliveticker-ticker div.components-base-control:first-child label,
|
|
||||||
div.wp-block-scliveticker-ticker .label {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.wp-block-scliveticker-ticker .label > .dashicon,
|
|
||||||
div.wp-block-scliveticker-ticker div.components-base-control:first-child label > .dashicon {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
@ -1,10 +1,8 @@
|
|||||||
div.wp-block-scliveticker-ticker ul,
|
ul.sclt-ticker {
|
||||||
div.wp-block-scliveticker-ajax-ticker ul {
|
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.wp-block-scliveticker-ticker ul > li.sclt-tick,
|
ul.sclt-ticker > li.sclt-tick {
|
||||||
div.wp-block-scliveticker-ajax-ticker ul > li.sclt-tick {
|
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
margin: 0.1em;
|
margin: 0.1em;
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* PHPUnit bootstrap file.
|
|
||||||
*
|
|
||||||
* @package SCLiveticker
|
|
||||||
*/
|
|
||||||
|
|
||||||
use Yoast\WPTestUtils\WPIntegration;
|
|
||||||
|
|
||||||
require_once dirname( __DIR__ ) . '/vendor/yoast/wp-test-utils/src/WPIntegration/bootstrap-functions.php';
|
|
||||||
|
|
||||||
$_tests_dir = WPIntegration\get_path_to_wp_test_dir();
|
|
||||||
|
|
||||||
// Get access to tests_add_filter() function.
|
|
||||||
require_once $_tests_dir . 'includes/functions.php';
|
|
||||||
|
|
||||||
// Add plugin to active mu-plugins to make sure it gets loaded.
|
|
||||||
tests_add_filter(
|
|
||||||
'muplugins_loaded',
|
|
||||||
function() {
|
|
||||||
require dirname( __DIR__ ) . '/stklcode-liveticker.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.
|
|
||||||
*/
|
|
||||||
WPIntegration\bootstrap_it();
|
|
@ -1,157 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Liveticker: Plugin API tests.
|
|
||||||
*
|
|
||||||
* This file contains unit tests for the plugin's REST API extensions.
|
|
||||||
*
|
|
||||||
* @package SCLiveticker
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace SCLiveticker;
|
|
||||||
|
|
||||||
use DateInterval;
|
|
||||||
use DateTime;
|
|
||||||
use WP_REST_Request;
|
|
||||||
use WP_REST_Server;
|
|
||||||
use Yoast\WPTestUtils\WPIntegration\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class Test_API.
|
|
||||||
*/
|
|
||||||
class Test_API extends TestCase {
|
|
||||||
/**
|
|
||||||
* Initialize WP REST API for tests.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function set_up(): void {
|
|
||||||
parent::set_up();
|
|
||||||
global $wp_rest_server;
|
|
||||||
$wp_rest_server = new WP_REST_Server();
|
|
||||||
do_action( 'rest_api_init' );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test presence of registered routes for ticks and tickers.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function test_register_route(): void {
|
|
||||||
global $wp_rest_server;
|
|
||||||
|
|
||||||
$routes = $wp_rest_server->get_routes();
|
|
||||||
|
|
||||||
self::assertArrayHasKey( '/wp/v2/scliveticker_tick', $routes, 'Ticks not exposed in API' );
|
|
||||||
self::assertArrayHasKey( '/wp/v2/scliveticker_tick/(?P<id>[\d]+)', $routes, 'Specific ticks not exposed in API' );
|
|
||||||
self::assertArrayHasKey( '/wp/v2/scliveticker_ticker', $routes, 'Tickers not exposed in API' );
|
|
||||||
self::assertArrayHasKey( '/wp/v2/scliveticker_ticker/(?P<id>[\d]+)', $routes, 'Specific tickers not exposed in API' );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test fetching ticks and tickers via the REST API.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function test_get_ticks(): void {
|
|
||||||
global $wp_rest_server;
|
|
||||||
|
|
||||||
$request = new WP_REST_Request( 'GET', '/wp/v2/scliveticker_tick' );
|
|
||||||
$response = $wp_rest_server->dispatch( $request );
|
|
||||||
self::assertEquals( 200, $response->get_status(), 'Unexpected status code' );
|
|
||||||
self::assertEmpty( $response->get_data(), 'No data expected on empty database' );
|
|
||||||
|
|
||||||
// Create two tickers with 10 ticks each.
|
|
||||||
wp_set_current_user( 1 );
|
|
||||||
$ticker_id = array(
|
|
||||||
1 => self::factory()->term->create(
|
|
||||||
array(
|
|
||||||
'name' => 'Ticker 1',
|
|
||||||
'description' => 'Test Liveticker 1',
|
|
||||||
'slug' => 'ticker1',
|
|
||||||
'taxonomy' => 'scliveticker_ticker',
|
|
||||||
)
|
|
||||||
),
|
|
||||||
2 >= self::factory()->term->create(
|
|
||||||
array(
|
|
||||||
'name' => 'Ticker 2',
|
|
||||||
'description' => 'Test Liveticker 2',
|
|
||||||
'slug' => 'ticker2',
|
|
||||||
'taxonomy' => 'scliveticker_ticker',
|
|
||||||
)
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
$dt = new DateTime( '2021-05-22 16:17:18' );
|
|
||||||
foreach ( range( 1, 20 ) as $n ) {
|
|
||||||
$t = 0 === $n % 2 ? '1' : '2';
|
|
||||||
$i = ceil( $n / 2 );
|
|
||||||
$p = self::factory()->post->create(
|
|
||||||
array(
|
|
||||||
'post_type' => 'scliveticker_tick',
|
|
||||||
'post_date_gmt' => $dt->format( 'Y-m-d H_i_s' ),
|
|
||||||
'post_title' => 'Tick ' . $t . '.' . $i,
|
|
||||||
'post_status' => 'publish',
|
|
||||||
'post_content' => 'Content of Tick ' . $t . '.' . $i,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
wp_set_object_terms( $p, $ticker_id[ $t ], 'scliveticker_ticker' );
|
|
||||||
$dt->add( new DateInterval( 'PT1M' ) );
|
|
||||||
}
|
|
||||||
wp_set_current_user( 0 );
|
|
||||||
|
|
||||||
// Verify ticker presence via API.
|
|
||||||
$response = $wp_rest_server->dispatch( new WP_REST_Request( 'GET', '/wp/v2/scliveticker_ticker' ) );
|
|
||||||
self::assertEquals( 200, $response->get_status(), 'Unexpected status code' );
|
|
||||||
self::assertEquals( 2, count( $response->get_data() ), 'Unexpected number of tickers' );
|
|
||||||
|
|
||||||
// Query all entries. The "limit" parameter should overrule "per_page".
|
|
||||||
$request->set_param( 'limit', - 1 );
|
|
||||||
$response = $wp_rest_server->dispatch( $request );
|
|
||||||
self::assertEquals( 200, $response->get_status(), 'Unexpected status code' );
|
|
||||||
self::assertEquals( 20, count( $response->get_data() ), 'Unexpected number of ticks without filter' );
|
|
||||||
|
|
||||||
// Limit number of entries.
|
|
||||||
$request->set_param( 'limit', 12 );
|
|
||||||
$response = $wp_rest_server->dispatch( $request );
|
|
||||||
self::assertEquals( 200, $response->get_status(), 'Unexpected status code with limit' );
|
|
||||||
self::assertEquals( 12, count( $response->get_data() ), 'Unexpected number of ticks with limit' );
|
|
||||||
|
|
||||||
// Use built-in pagination.
|
|
||||||
$request->set_param( 'limit', null );
|
|
||||||
$request->set_param( 'per_page', 13 );
|
|
||||||
$response = $wp_rest_server->dispatch( $request );
|
|
||||||
self::assertEquals( 200, $response->get_status(), 'Unexpected status code for first page' );
|
|
||||||
self::assertEquals( 13, count( $response->get_data() ), 'Unexpected number of ticks for first page' );
|
|
||||||
self::assertEquals( 20, $response->get_headers()['X-WP-Total'], 'Unexpected total header' );
|
|
||||||
self::assertEquals( 2, $response->get_headers()['X-WP-TotalPages'], 'Unexpected pages header' );
|
|
||||||
$request->set_param( 'page', 2 );
|
|
||||||
$response = $wp_rest_server->dispatch( $request );
|
|
||||||
self::assertEquals( 200, $response->get_status(), 'Unexpected status code for second page' );
|
|
||||||
self::assertEquals( 7, count( $response->get_data() ), 'Unexpected number of ticks for second page' );
|
|
||||||
|
|
||||||
// Filter by time.
|
|
||||||
$request->set_param( 'limit', null );
|
|
||||||
$request->set_param( 'per_page', 10 );
|
|
||||||
$request->set_param( 'page', 1 );
|
|
||||||
$request->set_param( 'last', $dt->sub( new DateInterval( 'PT4M' ) )->format( 'Y-m-d H:i:s' ) );
|
|
||||||
$response = $wp_rest_server->dispatch( $request );
|
|
||||||
self::assertEquals( 200, $response->get_status(), 'Unexpected status code with time filter' );
|
|
||||||
self::assertEquals( 3, count( $response->get_data() ), 'Unexpected number of ticks with time filter' );
|
|
||||||
|
|
||||||
// Filter by ticker.
|
|
||||||
$request->set_param( 'last', null );
|
|
||||||
$request->set_param( 'ticker', 'ticker1' );
|
|
||||||
$response = $wp_rest_server->dispatch( $request );
|
|
||||||
self::assertEquals( 200, $response->get_status(), 'Unexpected status code with ticker filter' );
|
|
||||||
self::assertEquals( 10, count( $response->get_data() ), 'Unexpected number of ticks with ticker filter' );
|
|
||||||
self::assertEmpty(
|
|
||||||
array_filter(
|
|
||||||
$response->get_data(),
|
|
||||||
function ( $t ) use ( $ticker_id ) {
|
|
||||||
return 1 !== count( $t['scliveticker_ticker'] ) || ! in_array( $ticker_id[1], $t['scliveticker_ticker'], true );
|
|
||||||
}
|
|
||||||
),
|
|
||||||
'No tick from ticker 2 should be present filtering for ticker1'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
29
views/settings-page.php
Normal 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>
|
@ -14,7 +14,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<label for="<?php echo esc_html( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'stklcode-liveticker' ); ?></label>
|
<label for="<?php echo esc_html( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:' ); ?></label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
|
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
|
||||||
@ -27,12 +27,12 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
<td>
|
<td>
|
||||||
<select id="<?php echo esc_attr( $this->get_field_id( 'category' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'category' ) ); ?>">
|
<select id="<?php echo esc_attr( $this->get_field_id( 'category' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'category' ) ); ?>">
|
||||||
<?php
|
<?php
|
||||||
foreach ( $categories as $c ) {
|
foreach ( $categories as $cat ) {
|
||||||
echo '<option value="' . esc_attr( $c->slug ) . '"';
|
echo '<option value="' . esc_attr( $cat->slug ) . '"';
|
||||||
if ( $category === $c->slug ) {
|
if ( $category === $cat->slug ) {
|
||||||
echo ' selected="selected"';
|
echo ' selected="selected"';
|
||||||
}
|
}
|
||||||
echo '>' . esc_html( $c->name ) . '</option>';
|
echo '>' . esc_html( $cat->name ) . '</option>';
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</select>
|
</select>
|
||||||
@ -40,7 +40,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>"><?php esc_html_e( 'Number of Ticks', 'stklcode-liveticker' ); ?>:</label>
|
<label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>"><?php esc_html_e( 'Number of Ticks:', 'stklcode-liveticker' ); ?></label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'count' ) ); ?>">
|
<select id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'count' ) ); ?>">
|
||||||
@ -54,10 +54,10 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
<?php esc_html_e( 'all', 'stklcode-liveticker' ); ?>
|
<?php esc_html_e( 'all', 'stklcode-liveticker' ); ?>
|
||||||
</option>
|
</option>
|
||||||
<?php
|
<?php
|
||||||
for ( $i = 1; $i <= 10; $i++ ) {
|
for ( $i = 1; $i <= 10; $i ++ ) {
|
||||||
printf(
|
printf(
|
||||||
'<option value="%d"%s>%d</option>',
|
'<option value="%d"%s>%d</option>',
|
||||||
intval( $i ),
|
$i,
|
||||||
( $i === $count ) ? ' selected' : '',
|
( $i === $count ) ? ' selected' : '',
|
||||||
intval( $i )
|
intval( $i )
|
||||||
);
|
);
|
||||||
|