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