Edit File by line
/home/zeestwma/richards.../wp-conte.../plugins/wpforms-.../src/Admin/Notifica...
File: EventDriven.php
<?php
[0] Fix | Delete
[1] Fix | Delete
namespace WPForms\Admin\Notifications;
[2] Fix | Delete
[3] Fix | Delete
/**
[4] Fix | Delete
* Class EventDriven.
[5] Fix | Delete
*
[6] Fix | Delete
* @since 1.7.5
[7] Fix | Delete
*/
[8] Fix | Delete
class EventDriven {
[9] Fix | Delete
[10] Fix | Delete
/**
[11] Fix | Delete
* WPForms version when the Event Driven feature has been introduced.
[12] Fix | Delete
*
[13] Fix | Delete
* @since 1.7.5
[14] Fix | Delete
*
[15] Fix | Delete
* @var string
[16] Fix | Delete
*/
[17] Fix | Delete
const FEATURE_INTRODUCED = '1.7.5';
[18] Fix | Delete
[19] Fix | Delete
/**
[20] Fix | Delete
* Expected date format for notifications.
[21] Fix | Delete
*
[22] Fix | Delete
* @since 1.7.5
[23] Fix | Delete
*
[24] Fix | Delete
* @var string
[25] Fix | Delete
*/
[26] Fix | Delete
const DATE_FORMAT = 'Y-m-d H:i:s';
[27] Fix | Delete
[28] Fix | Delete
/**
[29] Fix | Delete
* Common UTM parameters.
[30] Fix | Delete
*
[31] Fix | Delete
* @since 1.7.5
[32] Fix | Delete
*
[33] Fix | Delete
* @var array
[34] Fix | Delete
*/
[35] Fix | Delete
const UTM_PARAMS = [
[36] Fix | Delete
'utm_source' => 'WordPress',
[37] Fix | Delete
'utm_medium' => 'Event Notification',
[38] Fix | Delete
];
[39] Fix | Delete
[40] Fix | Delete
/**
[41] Fix | Delete
* Common targets for date logic.
[42] Fix | Delete
*
[43] Fix | Delete
* Available items:
[44] Fix | Delete
* - upgraded (upgraded to a latest version)
[45] Fix | Delete
* - activated
[46] Fix | Delete
* - forms_first_created
[47] Fix | Delete
* - X.X.X.X (upgraded to a specific version)
[48] Fix | Delete
* - pro (activated/installed)
[49] Fix | Delete
* - lite (activated/installed)
[50] Fix | Delete
*
[51] Fix | Delete
* @since 1.7.5
[52] Fix | Delete
*
[53] Fix | Delete
* @var array
[54] Fix | Delete
*/
[55] Fix | Delete
const DATE_LOGIC = [ 'upgraded', 'activated', 'forms_first_created' ];
[56] Fix | Delete
[57] Fix | Delete
/**
[58] Fix | Delete
* Timestamps.
[59] Fix | Delete
*
[60] Fix | Delete
* @since 1.7.5
[61] Fix | Delete
*
[62] Fix | Delete
* @var array
[63] Fix | Delete
*/
[64] Fix | Delete
private $timestamps = [];
[65] Fix | Delete
[66] Fix | Delete
/**
[67] Fix | Delete
* Initialize class.
[68] Fix | Delete
*
[69] Fix | Delete
* @since 1.7.5
[70] Fix | Delete
*/
[71] Fix | Delete
public function init() {
[72] Fix | Delete
[73] Fix | Delete
if ( ! $this->allow_load() ) {
[74] Fix | Delete
return;
[75] Fix | Delete
}
[76] Fix | Delete
[77] Fix | Delete
$this->hooks();
[78] Fix | Delete
}
[79] Fix | Delete
[80] Fix | Delete
/**
[81] Fix | Delete
* Indicate if this is allowed to load.
[82] Fix | Delete
*
[83] Fix | Delete
* @since 1.7.5
[84] Fix | Delete
*
[85] Fix | Delete
* @return bool
[86] Fix | Delete
*/
[87] Fix | Delete
private function allow_load() {
[88] Fix | Delete
[89] Fix | Delete
return wpforms()->obj( 'notifications' )->has_access() || wp_doing_cron();
[90] Fix | Delete
}
[91] Fix | Delete
[92] Fix | Delete
/**
[93] Fix | Delete
* Hooks.
[94] Fix | Delete
*
[95] Fix | Delete
* @since 1.7.5
[96] Fix | Delete
*/
[97] Fix | Delete
private function hooks() {
[98] Fix | Delete
[99] Fix | Delete
add_filter( 'wpforms_admin_notifications_update_data', [ $this, 'update_events' ] );
[100] Fix | Delete
}
[101] Fix | Delete
[102] Fix | Delete
/**
[103] Fix | Delete
* Add Event Driven notifications before saving them in database.
[104] Fix | Delete
*
[105] Fix | Delete
* @since 1.7.5
[106] Fix | Delete
*
[107] Fix | Delete
* @param array $data Notification data.
[108] Fix | Delete
*
[109] Fix | Delete
* @return array
[110] Fix | Delete
*/
[111] Fix | Delete
public function update_events( $data ) {
[112] Fix | Delete
[113] Fix | Delete
$updated = [];
[114] Fix | Delete
[115] Fix | Delete
/**
[116] Fix | Delete
* Allow developers to turn on debug mode: store all notifications and then show all of them.
[117] Fix | Delete
*
[118] Fix | Delete
* @since 1.7.5
[119] Fix | Delete
*
[120] Fix | Delete
* @param bool $is_debug True if it's a debug mode. Default: false.
[121] Fix | Delete
*/
[122] Fix | Delete
$is_debug = (bool) apply_filters( 'wpforms_admin_notifications_event_driven_update_events_debug', false );
[123] Fix | Delete
[124] Fix | Delete
$wpforms_notifications = wpforms()->obj( 'notifications' );
[125] Fix | Delete
[126] Fix | Delete
foreach ( $this->get_notifications() as $slug => $notification ) {
[127] Fix | Delete
[128] Fix | Delete
$is_processed = ! empty( $data['events'][ $slug ]['start'] );
[129] Fix | Delete
$is_conditional_ok = ! ( isset( $notification['condition'] ) && $notification['condition'] === false );
[130] Fix | Delete
[131] Fix | Delete
// If it's a debug mode OR valid notification has been already processed - skip running logic checks and save it.
[132] Fix | Delete
if (
[133] Fix | Delete
$is_debug ||
[134] Fix | Delete
( $is_processed && $is_conditional_ok && $wpforms_notifications->is_valid( $data['events'][ $slug ] ) )
[135] Fix | Delete
) {
[136] Fix | Delete
unset( $notification['date_logic'], $notification['offset'], $notification['condition'] );
[137] Fix | Delete
[138] Fix | Delete
// phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
[139] Fix | Delete
$notification['start'] = $is_debug ? date( self::DATE_FORMAT ) : $data['events'][ $slug ]['start'];
[140] Fix | Delete
$updated[ $slug ] = $notification;
[141] Fix | Delete
[142] Fix | Delete
continue;
[143] Fix | Delete
}
[144] Fix | Delete
[145] Fix | Delete
// Ignore if a condition is not passed conditional checks.
[146] Fix | Delete
if ( ! $is_conditional_ok ) {
[147] Fix | Delete
continue;
[148] Fix | Delete
}
[149] Fix | Delete
[150] Fix | Delete
$timestamp = $this->get_timestamp_by_date_logic(
[151] Fix | Delete
$this->prepare_date_logic( $notification )
[152] Fix | Delete
);
[153] Fix | Delete
[154] Fix | Delete
if ( empty( $timestamp ) ) {
[155] Fix | Delete
continue;
[156] Fix | Delete
}
[157] Fix | Delete
[158] Fix | Delete
// Probably, notification should be visible after some time.
[159] Fix | Delete
$offset = empty( $notification['offset'] ) ? 0 : absint( $notification['offset'] );
[160] Fix | Delete
[161] Fix | Delete
// Set a start date when notification will be shown.
[162] Fix | Delete
// phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
[163] Fix | Delete
$notification['start'] = date( self::DATE_FORMAT, $timestamp + $offset );
[164] Fix | Delete
[165] Fix | Delete
// Ignore if notification data is not valid.
[166] Fix | Delete
if ( ! $wpforms_notifications->is_valid( $notification ) ) {
[167] Fix | Delete
continue;
[168] Fix | Delete
}
[169] Fix | Delete
[170] Fix | Delete
// Remove unnecessary values, mark notification as active, and save it.
[171] Fix | Delete
unset( $notification['date_logic'], $notification['offset'], $notification['condition'] );
[172] Fix | Delete
$updated[ $slug ] = $notification;
[173] Fix | Delete
}
[174] Fix | Delete
[175] Fix | Delete
$data['events'] = $updated;
[176] Fix | Delete
[177] Fix | Delete
return $data;
[178] Fix | Delete
}
[179] Fix | Delete
[180] Fix | Delete
/**
[181] Fix | Delete
* Prepare and retrieve date logic.
[182] Fix | Delete
*
[183] Fix | Delete
* @since 1.7.5
[184] Fix | Delete
*
[185] Fix | Delete
* @param array $notification Notification data.
[186] Fix | Delete
*
[187] Fix | Delete
* @return array
[188] Fix | Delete
*/
[189] Fix | Delete
private function prepare_date_logic( $notification ) {
[190] Fix | Delete
[191] Fix | Delete
$date_logic = empty( $notification['date_logic'] ) || ! is_array( $notification['date_logic'] ) ? self::DATE_LOGIC : $notification['date_logic'];
[192] Fix | Delete
[193] Fix | Delete
return array_filter( array_filter( $date_logic, 'is_string' ) );
[194] Fix | Delete
}
[195] Fix | Delete
[196] Fix | Delete
/**
[197] Fix | Delete
* Retrieve a notification timestamp based on date logic.
[198] Fix | Delete
*
[199] Fix | Delete
* @since 1.7.5
[200] Fix | Delete
*
[201] Fix | Delete
* @param array $args Date logic.
[202] Fix | Delete
*
[203] Fix | Delete
* @return int
[204] Fix | Delete
*/
[205] Fix | Delete
private function get_timestamp_by_date_logic( $args ) {
[206] Fix | Delete
[207] Fix | Delete
foreach ( $args as $target ) {
[208] Fix | Delete
[209] Fix | Delete
if ( ! empty( $this->timestamps[ $target ] ) ) {
[210] Fix | Delete
return $this->timestamps[ $target ];
[211] Fix | Delete
}
[212] Fix | Delete
[213] Fix | Delete
$timestamp = call_user_func(
[214] Fix | Delete
$this->get_timestamp_callback( $target ),
[215] Fix | Delete
$target
[216] Fix | Delete
);
[217] Fix | Delete
[218] Fix | Delete
if ( ! empty( $timestamp ) ) {
[219] Fix | Delete
$this->timestamps[ $target ] = $timestamp;
[220] Fix | Delete
[221] Fix | Delete
return $timestamp;
[222] Fix | Delete
}
[223] Fix | Delete
}
[224] Fix | Delete
[225] Fix | Delete
return 0;
[226] Fix | Delete
}
[227] Fix | Delete
[228] Fix | Delete
/**
[229] Fix | Delete
* Retrieve a callback that determines needed timestamp.
[230] Fix | Delete
*
[231] Fix | Delete
* @since 1.7.5
[232] Fix | Delete
*
[233] Fix | Delete
* @param string $target Date logic target.
[234] Fix | Delete
*
[235] Fix | Delete
* @return callable
[236] Fix | Delete
*/
[237] Fix | Delete
private function get_timestamp_callback( $target ) {
[238] Fix | Delete
[239] Fix | Delete
$raw_target = $target;
[240] Fix | Delete
[241] Fix | Delete
// As $target should be a part of name for callback method,
[242] Fix | Delete
// this regular expression allow lowercase characters, numbers, and underscore.
[243] Fix | Delete
$target = strtolower( preg_replace( '/[^a-z0-9_]/', '', $target ) );
[244] Fix | Delete
[245] Fix | Delete
// Basic callback.
[246] Fix | Delete
$callback = [ $this, 'get_timestamp_' . $target ];
[247] Fix | Delete
[248] Fix | Delete
// Determine if a special version number is passed.
[249] Fix | Delete
// Uses the regular expression to check a SemVer string.
[250] Fix | Delete
// @link https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string.
[251] Fix | Delete
if ( preg_match( '/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\.([1-9\d*]))?(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/', $raw_target ) ) {
[252] Fix | Delete
$callback = [ $this, 'get_timestamp_upgraded' ];
[253] Fix | Delete
}
[254] Fix | Delete
[255] Fix | Delete
// If callback is callable, return it. Otherwise, return fallback.
[256] Fix | Delete
return is_callable( $callback ) ? $callback : '__return_zero';
[257] Fix | Delete
}
[258] Fix | Delete
[259] Fix | Delete
/**
[260] Fix | Delete
* Retrieve a timestamp when WPForms was upgraded.
[261] Fix | Delete
*
[262] Fix | Delete
* @since 1.7.5
[263] Fix | Delete
*
[264] Fix | Delete
* @param string $version WPForms version.
[265] Fix | Delete
*
[266] Fix | Delete
* @return int|false Unix timestamp. False on failure.
[267] Fix | Delete
*/
[268] Fix | Delete
private function get_timestamp_upgraded( $version ) {
[269] Fix | Delete
[270] Fix | Delete
if ( $version === 'upgraded' ) {
[271] Fix | Delete
$version = WPFORMS_VERSION;
[272] Fix | Delete
}
[273] Fix | Delete
[274] Fix | Delete
$timestamp = wpforms_get_upgraded_timestamp( $version );
[275] Fix | Delete
[276] Fix | Delete
if ( $timestamp === false ) {
[277] Fix | Delete
return false;
[278] Fix | Delete
}
[279] Fix | Delete
[280] Fix | Delete
// Return a current timestamp if no luck to return a migration's timestamp.
[281] Fix | Delete
return $timestamp <= 0 ? time() : $timestamp;
[282] Fix | Delete
}
[283] Fix | Delete
[284] Fix | Delete
/**
[285] Fix | Delete
* Retrieve a timestamp when WPForms was first installed/activated.
[286] Fix | Delete
*
[287] Fix | Delete
* @since 1.7.5
[288] Fix | Delete
*
[289] Fix | Delete
* @return int|false Unix timestamp. False on failure.
[290] Fix | Delete
*/
[291] Fix | Delete
private function get_timestamp_activated() {
[292] Fix | Delete
[293] Fix | Delete
return wpforms_get_activated_timestamp();
[294] Fix | Delete
}
[295] Fix | Delete
[296] Fix | Delete
/**
[297] Fix | Delete
* Retrieve a timestamp when Lite was first installed.
[298] Fix | Delete
*
[299] Fix | Delete
* @since 1.7.5
[300] Fix | Delete
*
[301] Fix | Delete
* @return int|false Unix timestamp. False on failure.
[302] Fix | Delete
*/
[303] Fix | Delete
private function get_timestamp_lite() {
[304] Fix | Delete
[305] Fix | Delete
$activated = (array) get_option( 'wpforms_activated', [] );
[306] Fix | Delete
[307] Fix | Delete
return ! empty( $activated['lite'] ) ? absint( $activated['lite'] ) : false;
[308] Fix | Delete
}
[309] Fix | Delete
[310] Fix | Delete
/**
[311] Fix | Delete
* Retrieve a timestamp when Pro was first installed.
[312] Fix | Delete
*
[313] Fix | Delete
* @since 1.7.5
[314] Fix | Delete
*
[315] Fix | Delete
* @return int|false Unix timestamp. False on failure.
[316] Fix | Delete
*/
[317] Fix | Delete
private function get_timestamp_pro() {
[318] Fix | Delete
[319] Fix | Delete
$activated = (array) get_option( 'wpforms_activated', [] );
[320] Fix | Delete
[321] Fix | Delete
return ! empty( $activated['pro'] ) ? absint( $activated['pro'] ) : false;
[322] Fix | Delete
}
[323] Fix | Delete
[324] Fix | Delete
/**
[325] Fix | Delete
* Retrieve a timestamp when a first form was created.
[326] Fix | Delete
*
[327] Fix | Delete
* @since 1.7.5
[328] Fix | Delete
*
[329] Fix | Delete
* @return int|false Unix timestamp. False on failure.
[330] Fix | Delete
*/
[331] Fix | Delete
private function get_timestamp_forms_first_created() {
[332] Fix | Delete
[333] Fix | Delete
$timestamp = get_option( 'wpforms_forms_first_created' );
[334] Fix | Delete
[335] Fix | Delete
return ! empty( $timestamp ) ? absint( $timestamp ) : false;
[336] Fix | Delete
}
[337] Fix | Delete
[338] Fix | Delete
/**
[339] Fix | Delete
* Retrieve a number of entries.
[340] Fix | Delete
*
[341] Fix | Delete
* @since 1.7.5
[342] Fix | Delete
*
[343] Fix | Delete
* @return int
[344] Fix | Delete
*/
[345] Fix | Delete
private function get_entry_count() {
[346] Fix | Delete
[347] Fix | Delete
static $count;
[348] Fix | Delete
[349] Fix | Delete
if ( is_int( $count ) ) {
[350] Fix | Delete
return $count;
[351] Fix | Delete
}
[352] Fix | Delete
[353] Fix | Delete
global $wpdb;
[354] Fix | Delete
[355] Fix | Delete
$count = 0;
[356] Fix | Delete
$entry_handler = wpforms()->obj( 'entry' );
[357] Fix | Delete
$entry_meta_handler = wpforms()->obj( 'entry_meta' );
[358] Fix | Delete
[359] Fix | Delete
if ( ! $entry_handler || ! $entry_meta_handler ) {
[360] Fix | Delete
return $count;
[361] Fix | Delete
}
[362] Fix | Delete
[363] Fix | Delete
$query = "SELECT COUNT( $entry_handler->primary_key )
[364] Fix | Delete
FROM $entry_handler->table_name
[365] Fix | Delete
WHERE $entry_handler->primary_key
[366] Fix | Delete
NOT IN (
[367] Fix | Delete
SELECT entry_id
[368] Fix | Delete
FROM $entry_meta_handler->table_name
[369] Fix | Delete
WHERE type = 'backup_id'
[370] Fix | Delete
);";
[371] Fix | Delete
[372] Fix | Delete
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
[373] Fix | Delete
$count = (int) $wpdb->get_var( $query );
[374] Fix | Delete
[375] Fix | Delete
return $count;
[376] Fix | Delete
}
[377] Fix | Delete
[378] Fix | Delete
/**
[379] Fix | Delete
* Retrieve forms.
[380] Fix | Delete
*
[381] Fix | Delete
* @since 1.7.5
[382] Fix | Delete
*
[383] Fix | Delete
* @param int $posts_per_page Number of form to return.
[384] Fix | Delete
*
[385] Fix | Delete
* @return array
[386] Fix | Delete
*/
[387] Fix | Delete
private function get_forms( $posts_per_page ) {
[388] Fix | Delete
[389] Fix | Delete
$forms = wpforms()->obj( 'form' )->get(
[390] Fix | Delete
'',
[391] Fix | Delete
[
[392] Fix | Delete
'posts_per_page' => (int) $posts_per_page,
[393] Fix | Delete
'nopaging' => false,
[394] Fix | Delete
'update_post_meta_cache' => false,
[395] Fix | Delete
'update_post_term_cache' => false,
[396] Fix | Delete
'cap' => false,
[397] Fix | Delete
]
[398] Fix | Delete
);
[399] Fix | Delete
[400] Fix | Delete
return ! empty( $forms ) ? (array) $forms : [];
[401] Fix | Delete
}
[402] Fix | Delete
[403] Fix | Delete
/**
[404] Fix | Delete
* Determine if the user has at least 1 form.
[405] Fix | Delete
*
[406] Fix | Delete
* @since 1.7.5
[407] Fix | Delete
*
[408] Fix | Delete
* @return bool
[409] Fix | Delete
*/
[410] Fix | Delete
private function has_form() {
[411] Fix | Delete
[412] Fix | Delete
return ! empty( $this->get_forms( 1 ) );
[413] Fix | Delete
}
[414] Fix | Delete
[415] Fix | Delete
/**
[416] Fix | Delete
* Determine if it is a new user.
[417] Fix | Delete
*
[418] Fix | Delete
* @since 1.7.5
[419] Fix | Delete
*
[420] Fix | Delete
* @return bool
[421] Fix | Delete
*/
[422] Fix | Delete
private function is_new_user() {
[423] Fix | Delete
[424] Fix | Delete
// Check if this is an update or first install.
[425] Fix | Delete
return ! get_option( 'wpforms_version_upgraded_from' );
[426] Fix | Delete
}
[427] Fix | Delete
[428] Fix | Delete
/**
[429] Fix | Delete
* Determine if it's an English site.
[430] Fix | Delete
*
[431] Fix | Delete
* @since 1.7.5
[432] Fix | Delete
*
[433] Fix | Delete
* @return bool
[434] Fix | Delete
*/
[435] Fix | Delete
private function is_english_site() {
[436] Fix | Delete
[437] Fix | Delete
static $result;
[438] Fix | Delete
[439] Fix | Delete
if ( is_bool( $result ) ) {
[440] Fix | Delete
return $result;
[441] Fix | Delete
}
[442] Fix | Delete
[443] Fix | Delete
$locales = array_unique(
[444] Fix | Delete
array_map(
[445] Fix | Delete
[ $this, 'language_to_iso' ],
[446] Fix | Delete
[ get_locale(), get_user_locale() ]
[447] Fix | Delete
)
[448] Fix | Delete
);
[449] Fix | Delete
$result = count( $locales ) === 1 && $locales[0] === 'en';
[450] Fix | Delete
[451] Fix | Delete
return $result;
[452] Fix | Delete
}
[453] Fix | Delete
[454] Fix | Delete
/**
[455] Fix | Delete
* Convert language to ISO.
[456] Fix | Delete
*
[457] Fix | Delete
* @since 1.7.5
[458] Fix | Delete
*
[459] Fix | Delete
* @param string $lang Language value.
[460] Fix | Delete
*
[461] Fix | Delete
* @return string
[462] Fix | Delete
*/
[463] Fix | Delete
private function language_to_iso( $lang ) {
[464] Fix | Delete
[465] Fix | Delete
return $lang === '' ? $lang : explode( '_', $lang )[0];
[466] Fix | Delete
}
[467] Fix | Delete
[468] Fix | Delete
/**
[469] Fix | Delete
* Retrieve a modified URL query string.
[470] Fix | Delete
*
[471] Fix | Delete
* @since 1.7.5
[472] Fix | Delete
*
[473] Fix | Delete
* @param array $args An associative array of query variables.
[474] Fix | Delete
* @param string $url A URL to act upon.
[475] Fix | Delete
*
[476] Fix | Delete
* @return string
[477] Fix | Delete
*/
[478] Fix | Delete
private function add_query_arg( $args, $url ) {
[479] Fix | Delete
[480] Fix | Delete
return add_query_arg(
[481] Fix | Delete
array_merge( $this->get_utm_params(), array_map( 'rawurlencode', $args ) ),
[482] Fix | Delete
$url
[483] Fix | Delete
);
[484] Fix | Delete
}
[485] Fix | Delete
[486] Fix | Delete
/**
[487] Fix | Delete
* Retrieve UTM parameters for Event Driven notifications links.
[488] Fix | Delete
*
[489] Fix | Delete
* @since 1.7.5
[490] Fix | Delete
*
[491] Fix | Delete
* @return array
[492] Fix | Delete
*/
[493] Fix | Delete
private function get_utm_params() {
[494] Fix | Delete
[495] Fix | Delete
static $utm_params;
[496] Fix | Delete
[497] Fix | Delete
if ( ! $utm_params ) {
[498] Fix | Delete
$utm_params = [
[499] Fix | Delete
12
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function