Plugin Updates
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
@@ -290,8 +290,8 @@ to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{{description}}
|
||||
Copyright (C) {{year}} {{fullname}}
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -329,7 +329,7 @@ necessary. Here is a sample; alter the names:
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
{signature of Ty Coon}, 1 April 1989
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "johnbillion/wp-crontrol",
|
||||
"description": "WP Crontrol lets you view and control what's happening in the WP-Cron system.",
|
||||
"homepage": "https://github.com/johnbillion/wp-crontrol/",
|
||||
"homepage": "https://wp-crontrol.com",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"type": "wordpress-plugin",
|
||||
"authors": [
|
||||
|
||||
@@ -69,6 +69,7 @@ table.wp-list-table {
|
||||
color: #d63638;
|
||||
}
|
||||
|
||||
.status-crontrol-check .dashicons,
|
||||
.status-crontrol-paused .dashicons {
|
||||
background: #646970;
|
||||
border-radius: 50%;
|
||||
|
||||
@@ -1,26 +1,39 @@
|
||||
/**
|
||||
* Functionality related to Crontrol.
|
||||
* Functionality related to WP Crontrol.
|
||||
*/
|
||||
|
||||
jQuery(function($){
|
||||
$('#crontrol_next_run_date_local_custom_date,#crontrol_next_run_date_local_custom_time').on('change', function() {
|
||||
$('#crontrol_next_run_date_local_custom').prop('checked',true);
|
||||
});
|
||||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
const checkCustom = () => {
|
||||
document.getElementById( 'crontrol_next_run_date_local_custom' ).checked = true;
|
||||
};
|
||||
|
||||
if ( $('input[value="new_php_cron"]').length ) {
|
||||
$('input[value="new_cron"]').on('click',function(){
|
||||
$('.crontrol-edit-event').removeClass('crontrol-edit-event-php').addClass('crontrol-edit-event-standard');
|
||||
$('#crontrol_hookname').attr('required',true);
|
||||
});
|
||||
$('input[value="new_php_cron"]').on('click',function(){
|
||||
$('.crontrol-edit-event').removeClass('crontrol-edit-event-standard').addClass('crontrol-edit-event-php');
|
||||
$('#crontrol_hookname').attr('required',false);
|
||||
if ( ! $('#crontrol_hookcode').hasClass('crontrol-editor-initialized') ) {
|
||||
const customDateElement = document.getElementById( 'crontrol_next_run_date_local_custom_date' );
|
||||
const customTimeElement = document.getElementById( 'crontrol_next_run_date_local_custom_time' );
|
||||
const newCronElement = document.querySelector( 'input[value="new_cron"]' );
|
||||
const newPHPCronElement = document.querySelector( 'input[value="new_php_cron"]' );
|
||||
const hookCodeElement = document.getElementById( 'crontrol_hookcode' );
|
||||
const hookNameElement = document.getElementById( 'crontrol_hookname' );
|
||||
const editEventElement = document.querySelector( '.crontrol-edit-event' );
|
||||
|
||||
customDateElement && customDateElement.addEventListener( 'change', checkCustom );
|
||||
customTimeElement && customTimeElement.addEventListener( 'change', checkCustom );
|
||||
|
||||
if ( newPHPCronElement ) {
|
||||
newCronElement.addEventListener( 'click', () => {
|
||||
editEventElement.classList.remove( 'crontrol-edit-event-php' );
|
||||
editEventElement.classList.add( 'crontrol-edit-event-standard' );
|
||||
hookNameElement.setAttribute( 'required', true );
|
||||
} );
|
||||
newPHPCronElement.addEventListener( 'click', () => {
|
||||
editEventElement.classList.remove( 'crontrol-edit-event-standard' );
|
||||
editEventElement.classList.add( 'crontrol-edit-event-php' );
|
||||
hookNameElement.removeAttribute( 'required' );
|
||||
if ( ! hookCodeElement.classList.contains( 'crontrol-editor-initialized' ) ) {
|
||||
wp.codeEditor.initialize( 'crontrol_hookcode', window.wpCrontrol.codeEditor );
|
||||
}
|
||||
$('#crontrol_hookcode').addClass('crontrol-editor-initialized');
|
||||
});
|
||||
} else if ( $('#crontrol_hookcode').length ) {
|
||||
hookCodeElement.classList.add( 'crontrol-editor-initialized' );
|
||||
} );
|
||||
} else if ( hookCodeElement ) {
|
||||
wp.codeEditor.initialize( 'crontrol_hookcode', window.wpCrontrol.codeEditor );
|
||||
}
|
||||
});
|
||||
} );
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
Contributors: johnbillion, scompt
|
||||
Tags: cron, wp-cron, crontrol, debug
|
||||
Tested up to: 6.4
|
||||
Stable tag: 1.16.1
|
||||
Tested up to: 6.5
|
||||
Stable tag: 1.16.2
|
||||
Donate link: https://github.com/sponsors/johnbillion
|
||||
|
||||
WP Crontrol enables you to view and control what's happening in the WP-Cron system.
|
||||
WP Crontrol enables you to take control of the cron events on your WordPress website.
|
||||
|
||||
## Description
|
||||
|
||||
WP Crontrol enables you to view and control what's happening in the WP-Cron system. From the admin screens you can:
|
||||
WP Crontrol enables you to take control of the cron events on your WordPress website. From the admin screens you can:
|
||||
|
||||
* View all cron events along with their arguments, recurrence, callback functions, and when they are next due.
|
||||
* Edit, delete, pause, resume, and immediately run cron events.
|
||||
@@ -35,15 +35,11 @@ I maintain several other plugins for developers. Check them out:
|
||||
|
||||
### Privacy Statement
|
||||
|
||||
WP Crontrol is private by default and always will be. It does not send data to any third party, nor does it include any third party resources.
|
||||
|
||||
[WP Crontrol's full privacy statement can be found here](https://github.com/johnbillion/wp-crontrol/wiki/Privacy-statement).
|
||||
WP Crontrol is private by default and always will be. It does not send data to any third party, nor does it include any third party resources. [WP Crontrol's full privacy statement can be found here](https://wp-crontrol.com/privacy/).
|
||||
|
||||
### Accessibility Statement
|
||||
|
||||
WP Crontrol aims to be fully accessible to all of its users. It implements best practices for web accessibility, outputs semantic and structured markup, adheres to the default styles and accessibility guidelines of WordPress, uses the accessibility APIs provided by WordPress and web browsers where appropriate, and is fully accessible via keyboard and via mobile devices.
|
||||
|
||||
WP Crontrol should adhere to Web Content Accessibility Guidelines (WCAG) 2.0 at level AA when used with a recent version of WordPress where its admin area itself adheres to these guidelines. If you've experienced or identified an accessibility issue in WP Crontrol, please open a thread in [the WP Crontrol plugin support forum](https://wordpress.org/support/plugin/wp-crontrol/) and I'll address it swiftly.
|
||||
WP Crontrol aims to be fully accessible to all of its users. [WP Crontrol's full accessibility statement can be found here](https://wp-crontrol.com/accessibility/).
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
@@ -53,11 +49,11 @@ Yes, it's actively tested and working up to PHP 8.2.
|
||||
|
||||
### I get the error "There was a problem spawning a call to the WP-Cron system on your site". How do I fix this?
|
||||
|
||||
[You can read all about problems spawning WP-Cron on the WP Crontrol wiki](https://github.com/johnbillion/wp-crontrol/wiki/Problems-with-spawning-a-call-to-the-WP-Cron-system).
|
||||
[You can read all about problems spawning WP-Cron on the WP Crontrol website](https://wp-crontrol.com/help/problems-spawning-wp-cron/).
|
||||
|
||||
### Why do some cron events miss their schedule?
|
||||
|
||||
[You can read all about cron events that miss their schedule on the WP Crontrol wiki](https://github.com/johnbillion/wp-crontrol/wiki/Cron-events-that-have-missed-their-schedule).
|
||||
[You can read all about cron events that miss their schedule on the WP Crontrol website](https://wp-crontrol.com/help/missed-cron-events/).
|
||||
|
||||
### Why do some cron events reappear shortly after I delete them?
|
||||
|
||||
@@ -99,13 +95,15 @@ You can change the time and recurrence of a cron event by clicking the "Edit" li
|
||||
|
||||
From the Tools → Cron Events → Add New screen, create a PHP cron event that includes PHP that fetches the URL using the WordPress HTTP API. For example:
|
||||
|
||||
wp_remote_get( 'http://example.com' );
|
||||
~~~php
|
||||
wp_remote_get( 'http://example.com' );
|
||||
~~~
|
||||
|
||||
[You can read all about the features and security of PHP cron events on the WP Crontrol wiki](https://github.com/johnbillion/wp-crontrol/wiki/PHP-cron-events).
|
||||
[You can read all about the features and security of PHP cron events on the WP Crontrol website](https://wp-crontrol.com/docs/php-cron-events/).
|
||||
|
||||
### Why do changes that I make to some cron events not get saved?
|
||||
|
||||
[You can read all about problems with editing cron events on the WP Crontrol wiki](https://github.com/johnbillion/wp-crontrol/wiki/Problems-adding-or-editing-WP-Cron-events).
|
||||
[You can read all about problems with editing cron events on the WP Crontrol website](https://wp-crontrol.com/help/problems-managing-events/).
|
||||
|
||||
### Can I export a list of cron events?
|
||||
|
||||
@@ -135,19 +133,23 @@ In the Tools → Cron Events admin panel, click on "Add New" and enter the detai
|
||||
|
||||
This part takes place in PHP code (for example, in the `functions.php` file from your theme). To execute your hook, WordPress runs an action. For this reason, we need to tell WordPress which function to execute when this action is run. The following line accomplishes that:
|
||||
|
||||
add_action( 'my_hookname', 'my_function' );
|
||||
~~~php
|
||||
add_action( 'my_hookname', 'my_function' );
|
||||
~~~
|
||||
|
||||
The next step is to write your function. Here's a simple example:
|
||||
|
||||
function my_function() {
|
||||
wp_mail( 'hello@example.com', 'WP Crontrol', 'WP Crontrol rocks!' );
|
||||
}
|
||||
~~~php
|
||||
function my_function() {
|
||||
wp_mail( 'hello@example.com', 'WP Crontrol', 'WP Crontrol rocks!' );
|
||||
}
|
||||
~~~
|
||||
|
||||
### How do I create a new PHP cron event?
|
||||
|
||||
In the Tools → Cron Events admin panel, click on "Add New". In the form that appears, select "PHP Cron Event" and enter the schedule and next run time. The event schedule is how often your event will be executed. If you don't see a good interval, then add one in the Settings → Cron Schedules admin panel. In the "Hook code" area, enter the PHP code that should be run when your cron event is executed. You don't need to provide the PHP opening tag (`<?php`).
|
||||
In the Tools → Cron Events admin panel, click on "Add New". In the form that appears, select "PHP Cron Event" and enter the schedule and next run time. The event schedule is how often your event will be executed. If you don't see a good interval, then add one in the Settings → Cron Schedules admin panel. In the "PHP Code" area, enter the PHP code that should be run when your cron event is executed. You don't need to provide the PHP opening tag (`<?php`).
|
||||
|
||||
[You can read all about the features and security of PHP cron events on the WP Crontrol wiki](https://github.com/johnbillion/wp-crontrol/wiki/PHP-cron-events).
|
||||
Creating, editing, and running PHP cron events is subject to restrictive security permissions. [You can read all about the features and security of PHP cron events on the WP Crontrol website](https://wp-crontrol.com/docs/php-cron-events/).
|
||||
|
||||
### Which users can manage cron events and schedules?
|
||||
|
||||
@@ -161,7 +163,7 @@ If file editing has been disabled via the `DISALLOW_FILE_MODS` or `DISALLOW_FILE
|
||||
|
||||
Therefore, the user access level required to execute arbitrary PHP code does not change with WP Crontrol activated.
|
||||
|
||||
[You can read all about the features and security of PHP cron events on the WP Crontrol wiki](https://github.com/johnbillion/wp-crontrol/wiki/PHP-cron-events).
|
||||
[You can read all about the features and security of PHP cron events on the WP Crontrol website](https://wp-crontrol.com/docs/php-cron-events/).
|
||||
|
||||
### Are any WP-CLI commands available?
|
||||
|
||||
@@ -169,7 +171,11 @@ The cron commands which were previously included in WP Crontrol are now part of
|
||||
|
||||
### What happens when I deactivate the WP Crontrol plugin?
|
||||
|
||||
[You can read all about what happens when you deactivate the plugin on the WP Crontrol wiki](https://github.com/johnbillion/wp-crontrol/wiki/What-happens-when-I-deactivate-the-WP-Crontrol-plugin%3F).
|
||||
[You can read all about what happens when you deactivate the plugin on the WP Crontrol website](https://wp-crontrol.com/docs/deactivation/).
|
||||
|
||||
### How can I report a security bug?
|
||||
|
||||
You can report security bugs through the Patchstack Vulnerability Disclosure Program. The Patchstack team helps validate, triage, and handle any security vulnerabilities. [Report a security vulnerability here](https://patchstack.com/database/vdp/wp-crontrol).
|
||||
|
||||
### Who took the photo in the plugin header image?
|
||||
|
||||
@@ -185,9 +191,17 @@ The photo was taken by <a href="https://www.flickr.com/photos/michaelpardo/21453
|
||||
|
||||
## Changelog ##
|
||||
|
||||
### 1.16.2 ###
|
||||
|
||||
* Security hardening: [An anti-tampering mechanism has been introduced for PHP cron events](https://wp-crontrol.com/help/check-php-cron-events/)
|
||||
* Improvements to accessibility and internationalisation
|
||||
* Removes the dependency on jQuery
|
||||
* Confirms support for WordPress 6.5
|
||||
|
||||
|
||||
### 1.16.1 ###
|
||||
|
||||
* Confirm support for WordPress 6.4
|
||||
* Confirms support for WordPress 6.4
|
||||
|
||||
### 1.16.0 ###
|
||||
|
||||
@@ -353,10 +367,3 @@ The photo was taken by <a href="https://www.flickr.com/photos/michaelpardo/21453
|
||||
* Improvements to help text.
|
||||
* Remove usage of `create_function()`.
|
||||
* Fix some translator comments, improve i18n, improve coding standards.
|
||||
|
||||
### 1.5.0 ###
|
||||
|
||||
* Show the hooked actions for each cron event.
|
||||
* Don't show the `Delete` link for core's built-in cron events, as they get re-populated immediately.
|
||||
* Correct the success message after adding or editing PHP cron events.
|
||||
* Correct the translations directory name.
|
||||
|
||||
@@ -9,6 +9,8 @@ use Crontrol\Event\Table;
|
||||
use stdClass;
|
||||
use WP_Error;
|
||||
|
||||
use function Crontrol\Event\check_integrity;
|
||||
|
||||
const TRANSIENT = 'crontrol-message-%d';
|
||||
const PAUSED_OPTION = 'wp_crontrol_paused';
|
||||
|
||||
@@ -136,7 +138,7 @@ function action_handle_posts() {
|
||||
|
||||
$cr = $request->init( wp_unslash( $_POST ) );
|
||||
|
||||
if ( 'crontrol_cron_job' === $cr->hookname && ! current_user_can( 'edit_files' ) ) {
|
||||
if ( 'crontrol_cron_job' === $cr->hookname ) {
|
||||
wp_die( esc_html__( 'You are not allowed to add new PHP cron events.', 'wp-crontrol' ), 401 );
|
||||
}
|
||||
$args = json_decode( $cr->args, true );
|
||||
@@ -195,9 +197,13 @@ function action_handle_posts() {
|
||||
$cr = $request->init( wp_unslash( $_POST ) );
|
||||
|
||||
$next_run_local = ( 'custom' === $cr->next_run_date_local ) ? $cr->next_run_date_local_custom_date . ' ' . $cr->next_run_date_local_custom_time : $cr->next_run_date_local;
|
||||
$args = array(
|
||||
'code' => $cr->hookcode,
|
||||
'name' => $cr->eventname,
|
||||
|
||||
$args = array(
|
||||
array(
|
||||
'code' => $cr->hookcode,
|
||||
'name' => $cr->eventname,
|
||||
'hash' => wp_hash( $cr->hookcode ),
|
||||
),
|
||||
);
|
||||
|
||||
add_filter( 'schedule_event', function( $event ) {
|
||||
@@ -340,9 +346,13 @@ function action_handle_posts() {
|
||||
$cr = $request->init( wp_unslash( $_POST ) );
|
||||
|
||||
check_admin_referer( "crontrol-edit-cron_{$cr->original_hookname}_{$cr->original_sig}_{$cr->original_next_run_utc}" );
|
||||
|
||||
$args = array(
|
||||
'code' => $cr->hookcode,
|
||||
'name' => $cr->eventname,
|
||||
array(
|
||||
'code' => $cr->hookcode,
|
||||
'name' => $cr->eventname,
|
||||
'hash' => wp_hash( $cr->hookcode ),
|
||||
),
|
||||
);
|
||||
$hookname = ( ! empty( $cr->eventname ) ) ? $cr->eventname : __( 'PHP Cron', 'wp-crontrol' );
|
||||
$redirect = array(
|
||||
@@ -637,6 +647,11 @@ function action_handle_posts() {
|
||||
}
|
||||
|
||||
$hook = wp_unslash( $_GET['crontrol_id'] );
|
||||
|
||||
if ( 'crontrol_cron_job' === $hook ) {
|
||||
wp_die( esc_html__( 'You are not allowed to pause or resume cron events.', 'wp-crontrol' ), 401 );
|
||||
}
|
||||
|
||||
check_admin_referer( "crontrol-pause-hook_{$hook}" );
|
||||
|
||||
$paused = Event\pause( $hook );
|
||||
@@ -679,6 +694,11 @@ function action_handle_posts() {
|
||||
}
|
||||
|
||||
$hook = wp_unslash( $_GET['crontrol_id'] );
|
||||
|
||||
if ( 'crontrol_cron_job' === $hook ) {
|
||||
wp_die( esc_html__( 'You are not allowed to pause or resume cron events.', 'wp-crontrol' ), 401 );
|
||||
}
|
||||
|
||||
check_admin_referer( "crontrol-resume-hook_{$hook}" );
|
||||
|
||||
$resumed = Event\resume( $hook );
|
||||
@@ -766,7 +786,7 @@ function action_handle_posts() {
|
||||
}
|
||||
|
||||
if ( 'crontrol_cron_job' === $event->hook ) {
|
||||
$action = __( 'WP Crontrol', 'wp-crontrol' );
|
||||
$action = 'WP Crontrol';
|
||||
} else {
|
||||
$callbacks = array();
|
||||
|
||||
@@ -844,27 +864,48 @@ function admin_help_tab() {
|
||||
return;
|
||||
}
|
||||
|
||||
$content = '<p>' . __( 'There are several places to get help with issues relating to WP-Cron:', 'wp-crontrol' ) . '</p>';
|
||||
$content = '<p>' . esc_html__( 'There are several places to get help with issues relating to WP-Cron:', 'wp-crontrol' ) . '</p>';
|
||||
$content .= '<ul>';
|
||||
$content .= '<li>';
|
||||
$content .= sprintf(
|
||||
/* translators: %s: URL to the documentation */
|
||||
__( '<a href="%s">Read the WP Crontrol wiki</a> which contains information about events that have missed their schedule, problems with spawning a call to the WP-Cron system, and much more.', 'wp-crontrol' ),
|
||||
'https://github.com/johnbillion/wp-crontrol/wiki'
|
||||
$content .= wp_kses(
|
||||
sprintf(
|
||||
/* translators: %s: URL to the documentation */
|
||||
__( '<a href="%s">Read the WP Crontrol website</a> which contains information about events that have missed their schedule, problems with spawning a call to the WP-Cron system, and much more.', 'wp-crontrol' ),
|
||||
'https://wp-crontrol.com'
|
||||
),
|
||||
array(
|
||||
'a' => array(
|
||||
'href' => array(),
|
||||
),
|
||||
)
|
||||
);
|
||||
$content .= '</li>';
|
||||
$content .= '<li>';
|
||||
$content .= sprintf(
|
||||
/* translators: %s: URL to the documentation */
|
||||
__( '<a href="%s">Read the Frequently Asked Questions (FAQ)</a> which cover many common questions and answers.', 'wp-crontrol' ),
|
||||
'https://wordpress.org/plugins/wp-crontrol/faq/'
|
||||
$content .= wp_kses(
|
||||
sprintf(
|
||||
/* translators: %s: URL to the documentation */
|
||||
__( '<a href="%s">Read the Frequently Asked Questions (FAQ)</a> which cover many common questions and answers.', 'wp-crontrol' ),
|
||||
'https://wordpress.org/plugins/wp-crontrol/faq/'
|
||||
),
|
||||
array(
|
||||
'a' => array(
|
||||
'href' => array(),
|
||||
),
|
||||
)
|
||||
);
|
||||
$content .= '</li>';
|
||||
$content .= '<li>';
|
||||
$content .= sprintf(
|
||||
/* translators: %s: URL to the documentation */
|
||||
__( '<a href="%s">Read the WordPress.org documentation on WP-Cron</a> for more technical details about the WP-Cron system for developers.', 'wp-crontrol' ),
|
||||
'https://developer.wordpress.org/plugins/cron/'
|
||||
$content .= wp_kses(
|
||||
sprintf(
|
||||
/* translators: %s: URL to the documentation */
|
||||
__( '<a href="%s">Read the WordPress.org documentation on WP-Cron</a> for more technical details about the WP-Cron system for developers.', 'wp-crontrol' ),
|
||||
'https://developer.wordpress.org/plugins/cron/'
|
||||
),
|
||||
array(
|
||||
'a' => array(
|
||||
'href' => array(),
|
||||
),
|
||||
)
|
||||
);
|
||||
$content .= '</ul>';
|
||||
|
||||
@@ -900,7 +941,7 @@ function plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
|
||||
),
|
||||
'crontrol-help' => sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
'https://github.com/johnbillion/wp-crontrol/wiki',
|
||||
'https://wp-crontrol.com',
|
||||
esc_html__( 'Help', 'wp-crontrol' )
|
||||
),
|
||||
);
|
||||
@@ -918,7 +959,7 @@ function network_plugin_action_links( $actions ) {
|
||||
$new = array(
|
||||
'crontrol-help' => sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
'https://github.com/johnbillion/wp-crontrol/wiki',
|
||||
'https://wp-crontrol.com',
|
||||
esc_html__( 'Help', 'wp-crontrol' )
|
||||
),
|
||||
);
|
||||
@@ -952,12 +993,12 @@ function filter_cron_schedules( array $scheds ) {
|
||||
function admin_options_page() {
|
||||
$messages = array(
|
||||
'2' => array(
|
||||
/* translators: 1: The name of the cron schedule. */
|
||||
/* translators: %s: The name of the cron schedule. */
|
||||
__( 'Deleted the cron schedule %s.', 'wp-crontrol' ),
|
||||
'success',
|
||||
),
|
||||
'3' => array(
|
||||
/* translators: 1: The name of the cron schedule. */
|
||||
/* translators: %s: The name of the cron schedule. */
|
||||
__( 'Added the cron schedule %s.', 'wp-crontrol' ),
|
||||
'success',
|
||||
),
|
||||
@@ -1083,7 +1124,7 @@ function test_cron_spawn( $cache = true ) {
|
||||
foreach ( $cron_runner_plugins as $class => $plugin ) {
|
||||
if ( class_exists( $class ) ) {
|
||||
return new WP_Error( 'crontrol_info', sprintf(
|
||||
/* translators: 1: The name of the plugin that controls the running of cron events. */
|
||||
/* translators: %s: The name of the plugin that controls the running of cron events. */
|
||||
__( 'WP-Cron spawning is being managed by the %s plugin.', 'wp-crontrol' ),
|
||||
$plugin
|
||||
) );
|
||||
@@ -1092,7 +1133,7 @@ function test_cron_spawn( $cache = true ) {
|
||||
|
||||
if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) {
|
||||
return new WP_Error( 'crontrol_info', sprintf(
|
||||
/* translators: 1: The name of the PHP constant that is set. */
|
||||
/* translators: %s: The name of the PHP constant that is set. */
|
||||
__( 'The %s constant is set to true. WP-Cron spawning is disabled.', 'wp-crontrol' ),
|
||||
'DISABLE_WP_CRON'
|
||||
) );
|
||||
@@ -1100,7 +1141,7 @@ function test_cron_spawn( $cache = true ) {
|
||||
|
||||
if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
|
||||
return new WP_Error( 'crontrol_info', sprintf(
|
||||
/* translators: 1: The name of the PHP constant that is set. */
|
||||
/* translators: %s: The name of the PHP constant that is set. */
|
||||
__( 'The %s constant is set to true.', 'wp-crontrol' ),
|
||||
'ALTERNATE_WP_CRON'
|
||||
) );
|
||||
@@ -1133,7 +1174,7 @@ function test_cron_spawn( $cache = true ) {
|
||||
return $result;
|
||||
} elseif ( wp_remote_retrieve_response_code( $result ) >= 300 ) {
|
||||
return new WP_Error( 'unexpected_http_response_code', sprintf(
|
||||
/* translators: 1: The HTTP response code. */
|
||||
/* translators: %s: The HTTP response code. */
|
||||
__( 'Unexpected HTTP response code: %s', 'wp-crontrol' ),
|
||||
intval( wp_remote_retrieve_response_code( $result ) )
|
||||
) );
|
||||
@@ -1166,9 +1207,8 @@ function show_cron_status( $tab ) {
|
||||
<?php
|
||||
printf(
|
||||
'<p>%1$s</p><p><a href="%2$s">%3$s</a></p>',
|
||||
/* translators: %s: Help page URL. */
|
||||
esc_html__( 'PHP default timezone is not set to UTC. This may cause issues with cron event timings.', 'wp-crontrol' ),
|
||||
'https://github.com/johnbillion/wp-crontrol/wiki/PHP-default-timezone-is-not-set-to-UTC',
|
||||
'https://wp-crontrol.com/help/php-default-timezone/',
|
||||
esc_html__( 'More information', 'wp-crontrol' )
|
||||
);
|
||||
?>
|
||||
@@ -1192,11 +1232,11 @@ function show_cron_status( $tab ) {
|
||||
printf(
|
||||
'<p>%1$s</p><p><a href="%2$s">%3$s</a></p>',
|
||||
sprintf(
|
||||
/* translators: 1: Error message text. */
|
||||
/* translators: %s: Error message text. */
|
||||
esc_html__( 'There was a problem spawning a call to the WP-Cron system on your site. This means WP-Cron events on your site may not work. The problem was: %s', 'wp-crontrol' ),
|
||||
'</p><p><strong>' . esc_html( $status->get_error_message() ) . '</strong>'
|
||||
),
|
||||
'https://github.com/johnbillion/wp-crontrol/wiki/Problems-with-spawning-a-call-to-the-WP-Cron-system',
|
||||
'https://wp-crontrol.com/help/problems-spawning-wp-cron/',
|
||||
esc_html__( 'More information', 'wp-crontrol' )
|
||||
);
|
||||
?>
|
||||
@@ -1309,7 +1349,7 @@ function show_cron_form( $editing ) {
|
||||
$helper_text = esc_html__( 'Cron events trigger actions in your code. Enter the schedule of the event, as well as the PHP code to execute when the action is triggered.', 'wp-crontrol' );
|
||||
} else {
|
||||
$helper_text = sprintf(
|
||||
/* translators: %s: A file name */
|
||||
/* translators: %1$s: A file name */
|
||||
esc_html__( 'Cron events trigger actions in your code. A cron event needs a corresponding action hook somewhere in code, e.g. the %1$s file in your theme.', 'wp-crontrol' ),
|
||||
'<code>functions.php</code>'
|
||||
);
|
||||
@@ -1351,13 +1391,15 @@ function show_cron_form( $editing ) {
|
||||
$next_run_time_local = '';
|
||||
}
|
||||
|
||||
if ( $is_editing_php ) {
|
||||
if ( ! isset( $existing['args']['code'] ) ) {
|
||||
$existing['args']['code'] = '';
|
||||
}
|
||||
if ( ! isset( $existing['args']['name'] ) ) {
|
||||
$existing['args']['name'] = '';
|
||||
}
|
||||
if ( $is_editing_php && isset( $existing['args']['code'] ) ) {
|
||||
// Support the args array format used prior to WP Crontrol 1.16.2
|
||||
$existing['args'] = array(
|
||||
array(
|
||||
'code' => $existing['args']['code'],
|
||||
'name' => $existing['args']['name'] ?? '',
|
||||
'hash' => null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$can_add_php = current_user_can( 'edit_files' ) && ! $editing;
|
||||
@@ -1378,6 +1420,7 @@ function show_cron_form( $editing ) {
|
||||
'<h1>%s</h1>',
|
||||
esc_html( $heading )
|
||||
);
|
||||
|
||||
printf(
|
||||
'<p>%s</p>',
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
@@ -1400,12 +1443,27 @@ function show_cron_form( $editing ) {
|
||||
} elseif ( $can_add_php ) {
|
||||
?>
|
||||
<tr class="hide-if-no-js">
|
||||
<th valign="top" scope="row">
|
||||
<th scope="row">
|
||||
<?php esc_html_e( 'Event Type', 'wp-crontrol' ); ?>
|
||||
</th>
|
||||
<td>
|
||||
<p><label><input type="radio" name="crontrol_action" value="new_cron" checked>Standard cron event</label></p>
|
||||
<p><label><input type="radio" name="crontrol_action" value="new_php_cron">PHP cron event</label></p>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text">
|
||||
<?php esc_html_e( 'Event Type', 'wp-crontrol' ); ?>
|
||||
</legend>
|
||||
<p>
|
||||
<label>
|
||||
<input type="radio" name="crontrol_action" value="new_cron" checked>
|
||||
<?php esc_html_e( 'Standard cron event', 'wp-crontrol' ); ?>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="radio" name="crontrol_action" value="new_php_cron">
|
||||
<?php esc_html_e( 'PHP cron event', 'wp-crontrol' ); ?>
|
||||
</label>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
@@ -1418,12 +1476,22 @@ function show_cron_form( $editing ) {
|
||||
if ( $is_editing_php || $can_add_php ) {
|
||||
?>
|
||||
<tr class="crontrol-event-php">
|
||||
<th valign="top" scope="row">
|
||||
<th scope="row">
|
||||
<label for="crontrol_hookcode">
|
||||
<?php esc_html_e( 'PHP Code', 'wp-crontrol' ); ?>
|
||||
</label>
|
||||
</th>
|
||||
<td>
|
||||
<?php
|
||||
if ( $is_editing_php && ! check_integrity( $existing['args'][0]['code'], $existing['args'][0]['hash'] ) ) {
|
||||
printf(
|
||||
'<div class="notice notice-error inline"><p>%1$s</p><p><a href="%2$s">%3$s</a></p></div>',
|
||||
esc_html__( 'The PHP code in this event needs to be checked for integrity. This event will not run until you re-save it.', 'wp-crontrol' ),
|
||||
'https://wp-crontrol.com/help/check-php-cron-events/',
|
||||
esc_html__( 'Read what to do', 'wp-crontrol' )
|
||||
);
|
||||
}
|
||||
?>
|
||||
<p class="description">
|
||||
<?php
|
||||
printf(
|
||||
@@ -1433,18 +1501,18 @@ function show_cron_form( $editing ) {
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<p><textarea class="large-text code" rows="10" cols="50" id="crontrol_hookcode" name="crontrol_hookcode"><?php echo esc_textarea( $editing ? $existing['args']['code'] : '' ); ?></textarea></p>
|
||||
<p><textarea class="large-text code" rows="10" cols="50" id="crontrol_hookcode" name="crontrol_hookcode"><?php echo esc_textarea( $editing ? $existing['args'][0]['code'] : '' ); ?></textarea></p>
|
||||
<?php do_action( 'crontrol/manage/hookcode', $existing ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="crontrol-event-php">
|
||||
<th valign="top" scope="row">
|
||||
<th scope="row">
|
||||
<label for="crontrol_eventname">
|
||||
<?php esc_html_e( 'Event Name (optional)', 'wp-crontrol' ); ?>
|
||||
</label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" class="regular-text" id="crontrol_eventname" name="crontrol_eventname" value="<?php echo esc_attr( $editing ? $existing['args']['name'] : '' ); ?>"/>
|
||||
<input type="text" class="regular-text" id="crontrol_eventname" name="crontrol_eventname" value="<?php echo esc_attr( $editing ? $existing['args'][0]['name'] : '' ); ?>"/>
|
||||
<?php do_action( 'crontrol/manage/eventname', $existing ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -1454,7 +1522,7 @@ function show_cron_form( $editing ) {
|
||||
if ( ! $is_editing_php ) {
|
||||
?>
|
||||
<tr class="crontrol-event-standard">
|
||||
<th valign="top" scope="row">
|
||||
<th scope="row">
|
||||
<label for="crontrol_hookname">
|
||||
<?php esc_html_e( 'Hook Name', 'wp-crontrol' ); ?>
|
||||
</label>
|
||||
@@ -1465,15 +1533,15 @@ function show_cron_form( $editing ) {
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="crontrol-event-standard">
|
||||
<th valign="top" scope="row">
|
||||
<th scope="row">
|
||||
<label for="crontrol_args">
|
||||
<?php esc_html_e( 'Arguments (optional)', 'wp-crontrol' ); ?>
|
||||
</label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" autocorrect="off" autocapitalize="off" spellcheck="false" class="regular-text code" id="crontrol_args" name="crontrol_args" value="<?php echo esc_attr( $display_args ); ?>"/>
|
||||
<input type="text" autocorrect="off" autocapitalize="off" spellcheck="false" class="regular-text code" id="crontrol_args" name="crontrol_args" value="<?php echo esc_attr( $display_args ); ?>" aria-describedby="crontrol_args_description"/>
|
||||
<?php do_action( 'crontrol/manage/args', $existing ); ?>
|
||||
<p class="description">
|
||||
<p class="description" id="crontrol_args_description">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: 1, 2, and 3: Example values for an input field. */
|
||||
@@ -1490,34 +1558,37 @@ function show_cron_form( $editing ) {
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<th valign="top" scope="row">
|
||||
<th scope="row">
|
||||
<label for="crontrol_next_run_date_local">
|
||||
<?php esc_html_e( 'Next Run', 'wp-crontrol' ); ?>
|
||||
</label>
|
||||
</th>
|
||||
<td>
|
||||
<ul>
|
||||
<li>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text">
|
||||
<?php esc_html_e( 'Next Run', 'wp-crontrol' ); ?>
|
||||
</legend>
|
||||
<p>
|
||||
<label>
|
||||
<input type="radio" name="crontrol_next_run_date_local" value="now" checked>
|
||||
<?php esc_html_e( 'Now', 'wp-crontrol' ); ?>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="radio" name="crontrol_next_run_date_local" value="+1 day">
|
||||
<?php esc_html_e( 'Tomorrow', 'wp-crontrol' ); ?>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="radio" name="crontrol_next_run_date_local" value="custom" id="crontrol_next_run_date_local_custom" <?php checked( $editing ); ?>>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: An input field for specifying a date and time */
|
||||
esc_html__( 'At: %s', 'wp-crontrol' ),
|
||||
esc_html__( 'At this time: %s', 'wp-crontrol' ),
|
||||
sprintf(
|
||||
'<br>
|
||||
'<br><br>
|
||||
<input type="date" autocorrect="off" autocapitalize="off" spellcheck="false" name="crontrol_next_run_date_local_custom_date" id="crontrol_next_run_date_local_custom_date" value="%1$s" placeholder="yyyy-mm-dd" pattern="\d{4}-\d{2}-\d{2}" />
|
||||
<input type="time" autocorrect="off" autocapitalize="off" spellcheck="false" name="crontrol_next_run_date_local_custom_time" id="crontrol_next_run_date_local_custom_time" value="%2$s" step="1" placeholder="hh:mm:ss" pattern="\d{2}:\d{2}:\d{2}" />',
|
||||
esc_attr( $next_run_date_local ),
|
||||
@@ -1526,8 +1597,8 @@ function show_cron_form( $editing ) {
|
||||
);
|
||||
?>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
</fieldset>
|
||||
|
||||
<?php do_action( 'crontrol/manage/next_run', $existing ); ?>
|
||||
|
||||
@@ -1543,7 +1614,7 @@ function show_cron_form( $editing ) {
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th valign="top" scope="row">
|
||||
<th scope="row">
|
||||
<label for="crontrol_schedule">
|
||||
<?php esc_html_e( 'Recurrence', 'wp-crontrol' ); ?>
|
||||
</label>
|
||||
@@ -1585,42 +1656,42 @@ function show_cron_form( $editing ) {
|
||||
function admin_manage_page() {
|
||||
$messages = array(
|
||||
'1' => array(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Scheduled the cron event %s to run now. The original event will not be affected.', 'wp-crontrol' ),
|
||||
'success',
|
||||
),
|
||||
'2' => array(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Deleted all %s cron events.', 'wp-crontrol' ),
|
||||
'success',
|
||||
),
|
||||
'3' => array(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'There are no %s cron events to delete.', 'wp-crontrol' ),
|
||||
'info',
|
||||
),
|
||||
'4' => array(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Saved the cron event %s.', 'wp-crontrol' ),
|
||||
'success',
|
||||
),
|
||||
'5' => array(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Created the cron event %s.', 'wp-crontrol' ),
|
||||
'success',
|
||||
),
|
||||
'6' => array(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Deleted the cron event %s.', 'wp-crontrol' ),
|
||||
'success',
|
||||
),
|
||||
'7' => array(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Failed to the delete the cron event %s.', 'wp-crontrol' ),
|
||||
'error',
|
||||
),
|
||||
'8' => array(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Failed to the execute the cron event %s.', 'wp-crontrol' ),
|
||||
'error',
|
||||
),
|
||||
@@ -1629,17 +1700,17 @@ function admin_manage_page() {
|
||||
'success',
|
||||
),
|
||||
'10' => array(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Failed to save the cron event %s.', 'wp-crontrol' ),
|
||||
'error',
|
||||
),
|
||||
'11' => array(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Paused the %s hook.', 'wp-crontrol' ),
|
||||
'success',
|
||||
),
|
||||
'12' => array(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Resumed the %s hook.', 'wp-crontrol' ),
|
||||
'success',
|
||||
),
|
||||
@@ -1693,7 +1764,7 @@ function admin_manage_page() {
|
||||
|
||||
<form id="posts-filter" method="get" action="tools.php">
|
||||
<input type="hidden" name="page" value="crontrol_admin_manage_page" />
|
||||
<?php $table->search_box( __( 'Search Hook Names', 'wp-crontrol' ), 'cron-event' ); ?>
|
||||
<?php $table->search_box( esc_html__( 'Search Hook Names', 'wp-crontrol' ), 'cron-event' ); ?>
|
||||
</form>
|
||||
|
||||
<form method="post" action="tools.php?page=crontrol_admin_manage_page">
|
||||
@@ -1970,19 +2041,19 @@ function time_since( $older_date, $newer_date ) {
|
||||
function interval( $since ) {
|
||||
// Array of time period chunks.
|
||||
$chunks = array(
|
||||
/* translators: 1: The number of years in an interval of time. */
|
||||
/* translators: %s: The number of years in an interval of time. */
|
||||
array( YEAR_IN_SECONDS, _n_noop( '%s year', '%s years', 'wp-crontrol' ) ),
|
||||
/* translators: 1: The number of months in an interval of time. */
|
||||
/* translators: %s: The number of months in an interval of time. */
|
||||
array( MONTH_IN_SECONDS, _n_noop( '%s month', '%s months', 'wp-crontrol' ) ),
|
||||
/* translators: 1: The number of weeks in an interval of time. */
|
||||
/* translators: %s: The number of weeks in an interval of time. */
|
||||
array( WEEK_IN_SECONDS, _n_noop( '%s week', '%s weeks', 'wp-crontrol' ) ),
|
||||
/* translators: 1: The number of days in an interval of time. */
|
||||
/* translators: %s: The number of days in an interval of time. */
|
||||
array( DAY_IN_SECONDS, _n_noop( '%s day', '%s days', 'wp-crontrol' ) ),
|
||||
/* translators: 1: The number of hours in an interval of time. */
|
||||
/* translators: %s: The number of hours in an interval of time. */
|
||||
array( HOUR_IN_SECONDS, _n_noop( '%s hour', '%s hours', 'wp-crontrol' ) ),
|
||||
/* translators: 1: The number of minutes in an interval of time. */
|
||||
/* translators: %s: The number of minutes in an interval of time. */
|
||||
array( MINUTE_IN_SECONDS, _n_noop( '%s minute', '%s minutes', 'wp-crontrol' ) ),
|
||||
/* translators: 1: The number of seconds in an interval of time. */
|
||||
/* translators: %s: The number of seconds in an interval of time. */
|
||||
array( 1, _n_noop( '%s second', '%s seconds', 'wp-crontrol' ) ),
|
||||
);
|
||||
|
||||
@@ -2060,10 +2131,7 @@ function enqueue_assets( $hook_suffix ) {
|
||||
wp_enqueue_script(
|
||||
'wp-crontrol',
|
||||
plugin_dir_url( PLUGIN_FILE ) . 'js/wp-crontrol.js',
|
||||
array(
|
||||
'jquery',
|
||||
'wp-a11y',
|
||||
),
|
||||
array(),
|
||||
WP_CRONTROL_VERSION,
|
||||
true
|
||||
);
|
||||
@@ -2195,10 +2263,67 @@ function json_output( $input, $pretty = true ) {
|
||||
*
|
||||
* Therefore, the user access level required to execute arbitrary PHP code does not change with WP Crontrol activated.
|
||||
*
|
||||
* @param string $code The PHP code to evaluate.
|
||||
* The PHP code that's saved in a PHP cron event is protected with an integrity check which prevents it from being executed
|
||||
* if the code is tampered with.
|
||||
*
|
||||
* PHP cron events are secured via an integrity check that makes use of an HMAC to store a hash of the PHP code alongside
|
||||
* the code when the event is saved. When the event runs, the hash is checked to ensure the integrity of the PHP code and
|
||||
* confirm that it has not been tampered with. WP Crontrol will not execute the PHP code if the hashes do not match or if
|
||||
* a stored hash is not present.
|
||||
*
|
||||
* If an attacker with database-level access were to modify the PHP code in an event in an attempt to execute arbitrary
|
||||
* code, the code would no longer execute.
|
||||
*
|
||||
* @link https://wp-crontrol.com/docs/php-cron-events/
|
||||
*
|
||||
* @param array<string,string>|string $args The event args array, or a string containing the PHP code to evaluate.
|
||||
* @phpstan-param array{
|
||||
* code?: string,
|
||||
* name?: string,
|
||||
* hash?: string,
|
||||
* }|string $args
|
||||
* @return void
|
||||
*/
|
||||
function action_php_cron_event( $code ) {
|
||||
function action_php_cron_event( $args ) {
|
||||
if ( is_string( $args ) ) {
|
||||
// Prior to WP Crontrol 1.16.2, PHP cron events were saved with the associative arguments array at the top
|
||||
// level. This means arguments are passed as individual parameters to this function and the first parameter
|
||||
// contains the PHP code.
|
||||
$code = $args;
|
||||
$hash = null;
|
||||
} else {
|
||||
// Since WP Crontrol 1.16.2, PHP cron events are stored with the associative arguments array as the first element
|
||||
// in the args list. This means arguments are passed as a single associative array parameter to this function.
|
||||
$code = $args['code'] ?? null;
|
||||
$hash = $args['hash'] ?? null;
|
||||
}
|
||||
|
||||
if ( empty( $hash ) ) {
|
||||
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
|
||||
trigger_error(
|
||||
sprintf(
|
||||
'The stored hash is missing for a PHP cron event; for more information see %s',
|
||||
esc_url_raw( admin_url( 'tools.php?page=crontrol_admin_manage_page&crontrol_hooks_type=php' ) ),
|
||||
),
|
||||
E_USER_WARNING
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the integrity of the PHP code.
|
||||
if ( ! check_integrity( $code, $hash ) ) {
|
||||
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
|
||||
trigger_error(
|
||||
sprintf(
|
||||
'The stored hash for a PHP cron event is not valid; for more information see %s',
|
||||
esc_url_raw( admin_url( 'tools.php?page=crontrol_admin_manage_page&crontrol_hooks_type=php' ) ),
|
||||
),
|
||||
E_USER_WARNING
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Please see the function description above for information about the safety of this code.
|
||||
// phpcs:ignore Squiz.PHP.Eval.Discouraged
|
||||
eval( $code );
|
||||
}
|
||||
|
||||
@@ -90,15 +90,24 @@ class Table extends \WP_List_Table {
|
||||
|
||||
$this->items = array_slice( $events, $offset, $per_page );
|
||||
|
||||
$has_integrity_failures = (bool) array_filter( array_map( __NAMESPACE__ . '\\integrity_failed', $this->items ) );
|
||||
$has_late = (bool) array_filter( array_map( __NAMESPACE__ . '\\is_late', $this->items ) );
|
||||
|
||||
if ( $has_late ) {
|
||||
if ( $has_integrity_failures && empty( $_GET['crontrol_action'] ) ) {
|
||||
add_action( 'admin_notices', function() {
|
||||
printf(
|
||||
'<div id="crontrol-integrity-failures-message" class="notice notice-error"><p>%1$s</p><p><a href="%2$s">%3$s</a></p></div>',
|
||||
esc_html__( 'The PHP code in one or more of your PHP cron events needs to be checked for integrity. These events will not run until you check and re-save them.', 'wp-crontrol' ),
|
||||
'https://wp-crontrol.com/help/check-php-cron-events/',
|
||||
esc_html__( 'Read what to do', 'wp-crontrol' )
|
||||
);
|
||||
} );
|
||||
} elseif ( $has_late && empty( $_GET['crontrol_action'] ) ) {
|
||||
add_action( 'admin_notices', function() {
|
||||
printf(
|
||||
'<div id="crontrol-late-message" class="notice notice-warning"><p>%1$s</p><p><a href="%2$s">%3$s</a></p></div>',
|
||||
/* translators: %s: Help page URL. */
|
||||
esc_html__( 'One or more cron events have missed their schedule.', 'wp-crontrol' ),
|
||||
'https://github.com/johnbillion/wp-crontrol/wiki/Cron-events-that-have-missed-their-schedule',
|
||||
'https://wp-crontrol.com/help/missed-cron-events/',
|
||||
esc_html__( 'More information', 'wp-crontrol' )
|
||||
);
|
||||
} );
|
||||
@@ -136,13 +145,13 @@ class Table extends \WP_List_Table {
|
||||
return ( ! in_array( $event->hook, $all_core_hooks, true ) );
|
||||
} );
|
||||
|
||||
$paused = array_filter( $events, function( $event ) {
|
||||
return ( is_paused( $event ) );
|
||||
$filtered['php'] = array_filter( $events, function( $event ) {
|
||||
return ( 'crontrol_cron_job' === $event->hook );
|
||||
} );
|
||||
|
||||
if ( count( $paused ) > 0 ) {
|
||||
$filtered['paused'] = $paused;
|
||||
}
|
||||
$filtered['paused'] = array_filter( $events, function( $event ) {
|
||||
return ( is_paused( $event ) );
|
||||
} );
|
||||
|
||||
/**
|
||||
* Filters the available filtered events on the cron event listing screen.
|
||||
@@ -167,15 +176,17 @@ class Table extends \WP_List_Table {
|
||||
public function get_columns() {
|
||||
return array(
|
||||
'cb' => '<input type="checkbox" />',
|
||||
'crontrol_hook' => __( 'Hook', 'wp-crontrol' ),
|
||||
'crontrol_args' => __( 'Arguments', 'wp-crontrol' ),
|
||||
'crontrol_next' => sprintf(
|
||||
/* translators: %s: UTC offset */
|
||||
__( 'Next Run (%s)', 'wp-crontrol' ),
|
||||
\Crontrol\get_utc_offset()
|
||||
'crontrol_hook' => esc_html__( 'Hook', 'wp-crontrol' ),
|
||||
'crontrol_args' => esc_html__( 'Arguments', 'wp-crontrol' ),
|
||||
'crontrol_next' => esc_html(
|
||||
sprintf(
|
||||
/* translators: %s: UTC offset */
|
||||
__( 'Next Run (%s)', 'wp-crontrol' ),
|
||||
\Crontrol\get_utc_offset()
|
||||
),
|
||||
),
|
||||
'crontrol_actions' => __( 'Action', 'wp-crontrol' ),
|
||||
'crontrol_recurrence' => __( 'Recurrence', 'wp-crontrol' ),
|
||||
'crontrol_actions' => esc_html__( 'Action', 'wp-crontrol' ),
|
||||
'crontrol_recurrence' => esc_html__( 'Recurrence', 'wp-crontrol' ),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -238,6 +249,7 @@ class Table extends \WP_List_Table {
|
||||
'noaction' => __( 'Events with no action', 'wp-crontrol' ),
|
||||
'core' => __( 'WordPress core events', 'wp-crontrol' ),
|
||||
'custom' => __( 'Custom events', 'wp-crontrol' ),
|
||||
'php' => __( 'PHP events', 'wp-crontrol' ),
|
||||
'paused' => __( 'Paused events', 'wp-crontrol' ),
|
||||
);
|
||||
|
||||
@@ -263,6 +275,12 @@ class Table extends \WP_List_Table {
|
||||
continue;
|
||||
}
|
||||
|
||||
$count = count( $filtered[ $key ] );
|
||||
|
||||
if ( ! $count ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$link = ( 'all' === $key ) ? $url : add_query_arg( 'crontrol_hooks_type', $key, $url );
|
||||
|
||||
$views[ $key ] = sprintf(
|
||||
@@ -270,7 +288,7 @@ class Table extends \WP_List_Table {
|
||||
esc_url( $link ),
|
||||
$hooks_type === $key ? ' class="current"' : '',
|
||||
esc_html( $type ),
|
||||
number_format_i18n( count( $filtered[ $key ] ) )
|
||||
esc_html( number_format_i18n( $count ) )
|
||||
);
|
||||
}
|
||||
|
||||
@@ -309,7 +327,11 @@ class Table extends \WP_List_Table {
|
||||
public function single_row( $event ) {
|
||||
$classes = array();
|
||||
|
||||
if ( ( 'crontrol_cron_job' === $event->hook ) && ! empty( $event->args['syntax_error_message'] ) ) {
|
||||
if ( ( 'crontrol_cron_job' === $event->hook ) && isset( $event->args[0]['syntax_error_message'] ) ) {
|
||||
$classes[] = 'crontrol-error';
|
||||
}
|
||||
|
||||
if ( integrity_failed( $event ) ) {
|
||||
$classes[] = 'crontrol-error';
|
||||
}
|
||||
|
||||
@@ -374,10 +396,20 @@ class Table extends \WP_List_Table {
|
||||
);
|
||||
$link = add_query_arg( $link, admin_url( 'tools.php' ) );
|
||||
|
||||
$links[] = "<a href='" . esc_url( $link ) . "'>" . esc_html__( 'Edit', 'wp-crontrol' ) . '</a>';
|
||||
if ( integrity_failed( $event ) ) {
|
||||
$label = __( 'Check and edit', 'wp-crontrol' );
|
||||
} else {
|
||||
$label = __( 'Edit', 'wp-crontrol' );
|
||||
}
|
||||
|
||||
$links[] = sprintf(
|
||||
'<a href="%1$s">%2$s</a>',
|
||||
esc_url( $link ),
|
||||
esc_html( $label )
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! is_paused( $event ) ) {
|
||||
if ( ! is_paused( $event ) && ! integrity_failed( $event ) ) {
|
||||
$link = array(
|
||||
'page' => 'crontrol_admin_manage_page',
|
||||
'crontrol_action' => 'run-cron',
|
||||
@@ -483,7 +515,7 @@ class Table extends \WP_List_Table {
|
||||
);
|
||||
} elseif ( ( 'crontrol_cron_job' !== $event->hook ) || self::$can_manage_php_crons ) {
|
||||
return sprintf(
|
||||
'<label class="screen-reader-text" for="%1$s">%2$s</label>
|
||||
'<label for="%1$s"><span class="screen-reader-text">%2$s</span></label>
|
||||
<input type="checkbox" name="crontrol_delete[%3$s][%4$s]" value="%5$s" id="%1$s">',
|
||||
esc_attr( $id ),
|
||||
esc_html__( 'Select this row', 'wp-crontrol' ),
|
||||
@@ -505,11 +537,20 @@ class Table extends \WP_List_Table {
|
||||
protected function column_crontrol_hook( $event ) {
|
||||
if ( 'crontrol_cron_job' === $event->hook ) {
|
||||
if ( ! empty( $event->args['name'] ) ) {
|
||||
/* translators: 1: The name of the PHP cron event. */
|
||||
return '<em>' . esc_html( sprintf( __( 'PHP Cron (%s)', 'wp-crontrol' ), $event->args['name'] ) ) . '</em>';
|
||||
/* translators: %s: The name of the PHP cron event. */
|
||||
$output = esc_html( sprintf( __( 'PHP Cron (%s)', 'wp-crontrol' ), $event->args['name'] ) );
|
||||
} else {
|
||||
return '<em>' . esc_html__( 'PHP Cron', 'wp-crontrol' ) . '</em>';
|
||||
$output = esc_html__( 'PHP Cron', 'wp-crontrol' );
|
||||
}
|
||||
|
||||
if ( integrity_failed( $event ) ) {
|
||||
$output .= sprintf(
|
||||
' — <strong class="status-crontrol-check post-state"><span class="dashicons dashicons-warning" aria-hidden="true"></span> %s</strong>',
|
||||
esc_html__( 'Needs checking', 'wp-crontrol' )
|
||||
);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
$output = esc_html( $event->hook );
|
||||
@@ -535,19 +576,25 @@ class Table extends \WP_List_Table {
|
||||
if ( 'crontrol_cron_job' === $event->hook ) {
|
||||
$return = '<em>' . esc_html__( 'PHP Code', 'wp-crontrol' ) . '</em>';
|
||||
|
||||
if ( ! empty( $event->args['syntax_error_message'] ) ) {
|
||||
if ( isset( $event->args['code'] ) ) {
|
||||
$args = $event->args;
|
||||
} else {
|
||||
$args = $event->args[0];
|
||||
}
|
||||
|
||||
if ( isset( $args['syntax_error_message'], $args['syntax_error_line'] ) ) {
|
||||
$return .= '<br><span class="status-crontrol-error"><span class="dashicons dashicons-warning" aria-hidden="true"></span> ';
|
||||
$return .= sprintf(
|
||||
/* translators: 1: Line number, 2: Error message text */
|
||||
esc_html__( 'Line %1$s: %2$s', 'wp-crontrol' ),
|
||||
esc_html( number_format_i18n( $event->args['syntax_error_line'] ) ),
|
||||
esc_html( $event->args['syntax_error_message'] )
|
||||
esc_html( number_format_i18n( $args['syntax_error_line'] ) ),
|
||||
esc_html( $args['syntax_error_message'] )
|
||||
);
|
||||
$return .= '</span>';
|
||||
}
|
||||
|
||||
if ( ! empty( $event->args['code'] ) ) {
|
||||
$lines = explode( "\n", trim( $event->args['code'] ) );
|
||||
if ( ! empty( $args['code'] ) ) {
|
||||
$lines = explode( "\n", trim( $args['code'] ) );
|
||||
$code = reset( $lines );
|
||||
$code = substr( $code, 0, 50 );
|
||||
|
||||
@@ -584,7 +631,7 @@ class Table extends \WP_List_Table {
|
||||
$hook_callbacks = \Crontrol\get_hook_callbacks( $event->hook );
|
||||
|
||||
if ( 'crontrol_cron_job' === $event->hook ) {
|
||||
return '<em>' . esc_html__( 'WP Crontrol', 'wp-crontrol' ) . '</em>';
|
||||
return 'WP Crontrol';
|
||||
} elseif ( ! empty( $hook_callbacks ) ) {
|
||||
$callbacks = array();
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ function run( $hookname, $sig ) {
|
||||
return new WP_Error(
|
||||
'not_found',
|
||||
sprintf(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'The cron event %s could not be found.', 'wp-crontrol' ),
|
||||
$hookname
|
||||
)
|
||||
@@ -109,7 +109,7 @@ function force_schedule_single_event( $hook, $args = array() ) {
|
||||
return new WP_Error(
|
||||
'could_not_add',
|
||||
sprintf(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Failed to schedule the cron event %s.', 'wp-crontrol' ),
|
||||
$hook
|
||||
)
|
||||
@@ -126,6 +126,7 @@ function force_schedule_single_event( $hook, $args = array() ) {
|
||||
* @param string $schedule The recurrence of the cron event.
|
||||
* @param string $hook The name of the hook to execute.
|
||||
* @param mixed[] $args Arguments to add to the cron event.
|
||||
* @phpstan-param list<mixed> $args
|
||||
* @return true|WP_error True if the addition was successful, WP_Error otherwise.
|
||||
*/
|
||||
function add( $next_run_local, $schedule, $hook, array $args ) {
|
||||
@@ -144,21 +145,25 @@ function add( $next_run_local, $schedule, $hook, array $args ) {
|
||||
|
||||
$next_run_utc = (int) get_gmt_from_date( gmdate( 'Y-m-d H:i:s', $next_run_local ), 'U' );
|
||||
|
||||
if ( ! is_array( $args ) ) {
|
||||
$args = array();
|
||||
}
|
||||
|
||||
if ( 'crontrol_cron_job' === $hook && ! empty( $args['code'] ) && class_exists( '\ParseError' ) ) {
|
||||
if ( 'crontrol_cron_job' === $hook && ! empty( $args[0]['code'] ) && class_exists( '\ParseError' ) ) {
|
||||
try {
|
||||
/**
|
||||
* The call to `eval()` below checks the syntax of the PHP code provided in the cron event. This is done to
|
||||
* add a flag to a cron event that contains invalid PHP code, so that the user can be informed of the syntax
|
||||
* error when viewing the event in the list table.
|
||||
*
|
||||
* Security: The code is not executed due to the early return statement that precedes it. The code is only
|
||||
* checked for syntax correctness.
|
||||
*/
|
||||
// phpcs:ignore Squiz.PHP.Eval.Discouraged
|
||||
eval( sprintf(
|
||||
'return true; %s',
|
||||
$args['code']
|
||||
$args[0]['code']
|
||||
) );
|
||||
// phpcs:ignore PHPCompatibility.Classes.NewClasses.parseerrorFound
|
||||
} catch ( \ParseError $e ) {
|
||||
$args['syntax_error_message'] = $e->getMessage();
|
||||
$args['syntax_error_line'] = $e->getLine();
|
||||
$args[0]['syntax_error_message'] = $e->getMessage();
|
||||
$args[0]['syntax_error_line'] = $e->getLine();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +241,7 @@ function delete( $hook, $sig, $next_run_utc ) {
|
||||
return new WP_Error(
|
||||
'could_not_delete',
|
||||
sprintf(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Failed to the delete the cron event %s.', 'wp-crontrol' ),
|
||||
$hook
|
||||
)
|
||||
@@ -267,7 +272,7 @@ function pause( $hook ) {
|
||||
return new WP_Error(
|
||||
'could_not_pause',
|
||||
sprintf(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Failed to pause the cron event %s.', 'wp-crontrol' ),
|
||||
$hook
|
||||
)
|
||||
@@ -298,7 +303,7 @@ function resume( $hook ) {
|
||||
return new WP_Error(
|
||||
'could_not_resume',
|
||||
sprintf(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'Failed to resume the cron event %s.', 'wp-crontrol' ),
|
||||
$hook
|
||||
)
|
||||
@@ -372,7 +377,7 @@ function get_single( $hook, $sig, $next_run_utc ) {
|
||||
return new WP_Error(
|
||||
'not_found',
|
||||
sprintf(
|
||||
/* translators: 1: The name of the cron event. */
|
||||
/* translators: %s: The name of the cron event. */
|
||||
__( 'The cron event %s could not be found.', 'wp-crontrol' ),
|
||||
$hook
|
||||
)
|
||||
@@ -471,6 +476,47 @@ function is_paused( stdClass $event ) {
|
||||
return array_key_exists( $event->hook, $paused );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the integrity check of a PHP cron event has failed.
|
||||
*
|
||||
* @param stdClass $event The event.
|
||||
* @return bool Whether the event integrity check has failed.
|
||||
*/
|
||||
function integrity_failed( stdClass $event ): bool {
|
||||
// Only check PHP cron events.
|
||||
if ( 'crontrol_cron_job' !== $event->hook ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is a PHP cron event saved prior to WP Crontrol 1.16.2.
|
||||
if ( isset( $event->args['code'] ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$args = $event->args[0] ?? array();
|
||||
|
||||
return ! check_integrity( $args['code'] ?? null, $args['hash'] ?? null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the integrity of a code string compared to its stored hash.
|
||||
*
|
||||
* @param string|null $code The code string.
|
||||
* @param string|null $stored_hash The stored HMAC of the code.
|
||||
* @return bool
|
||||
*/
|
||||
function check_integrity( $code, $stored_hash ): bool {
|
||||
// If there's no code or hash then the integrity check is not ok.
|
||||
if ( empty( $code ) || empty( $stored_hash ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$code_hash = wp_hash( $code );
|
||||
|
||||
// If the hashes match then the integrity check is ok.
|
||||
return hash_equals( $stored_hash, $code_hash );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises and returns the list table for events.
|
||||
*
|
||||
|
||||
@@ -76,9 +76,9 @@ class Schedule_List_Table extends \WP_List_Table {
|
||||
public function get_columns() {
|
||||
return array(
|
||||
'crontrol_icon' => '',
|
||||
'crontrol_name' => __( 'Internal Name', 'wp-crontrol' ),
|
||||
'crontrol_interval' => __( 'Interval', 'wp-crontrol' ),
|
||||
'crontrol_display' => __( 'Display Name', 'wp-crontrol' ),
|
||||
'crontrol_name' => esc_html__( 'Internal Name', 'wp-crontrol' ),
|
||||
'crontrol_interval' => esc_html__( 'Interval', 'wp-crontrol' ),
|
||||
'crontrol_display' => esc_html__( 'Display Name', 'wp-crontrol' ),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ class Schedule_List_Table extends \WP_List_Table {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output for the schdule name cell of a table row.
|
||||
* Returns the output for the schedule name cell of a table row.
|
||||
*
|
||||
* @phpstan-param array{
|
||||
* interval: int,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
'name' => 'johnbillion/wp-crontrol',
|
||||
'pretty_version' => 'dev-release',
|
||||
'version' => 'dev-release',
|
||||
'reference' => 'dd6e69045b04417660f3d207bedfc605c1877e40',
|
||||
'reference' => 'a52f6b3fb76b62d7d87ce10696807014a92f373d',
|
||||
'type' => 'wordpress-plugin',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@@ -13,7 +13,7 @@
|
||||
'johnbillion/wp-crontrol' => array(
|
||||
'pretty_version' => 'dev-release',
|
||||
'version' => 'dev-release',
|
||||
'reference' => 'dd6e69045b04417660f3d207bedfc605c1877e40',
|
||||
'reference' => 'a52f6b3fb76b62d7d87ce10696807014a92f373d',
|
||||
'type' => 'wordpress-plugin',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: WP Crontrol
|
||||
* Plugin URI: https://wordpress.org/plugins/wp-crontrol/
|
||||
* Plugin URI: https://wp-crontrol.com
|
||||
* Description: WP Crontrol enables you to view and control what's happening in the WP-Cron system.
|
||||
* Author: John Blackbourn & crontributors
|
||||
* Author URI: https://github.com/johnbillion/wp-crontrol/graphs/contributors
|
||||
* Version: 1.16.1
|
||||
* Author: John Blackbourn
|
||||
* Author URI: https://wp-crontrol.com
|
||||
* Version: 1.16.2
|
||||
* Text Domain: wp-crontrol
|
||||
* Domain Path: /languages/
|
||||
* Requires at least: 5.6
|
||||
@@ -28,7 +28,7 @@
|
||||
*
|
||||
* @package wp-crontrol
|
||||
* @author John Blackbourn & Edward Dale
|
||||
* @copyright Copyright 2008 Edward Dale, 2012-2023 John Blackbourn
|
||||
* @copyright Copyright 2008 Edward Dale, 2012-2024 John Blackbourn
|
||||
* @license https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt GPL 2.0
|
||||
* @link https://github.com/johnbillion/wp-crontrol/
|
||||
*/
|
||||
@@ -36,7 +36,7 @@
|
||||
namespace Crontrol;
|
||||
|
||||
const PLUGIN_FILE = __FILE__;
|
||||
const WP_CRONTROL_VERSION = '1.16.1';
|
||||
const WP_CRONTROL_VERSION = '1.16.2';
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
|
||||
Reference in New Issue
Block a user