* Class Meta helps to manage the tasks meta information
* between Action Scheduler and WPForms hooks arguments.
* We can't pass arguments longer than >191 chars in JSON to AS,
* so we need to store them somewhere (and clean from time to time).
class Meta extends WPForms_DB {
* Primary key (unique field) for the database table.
public $primary_key = 'id';
* Database type identifier.
public $type = 'tasks_meta';
* Primary class constructor.
public function __construct() {
$this->table_name = self::get_table_name();
public static function get_table_name() {
return $wpdb->prefix . 'wpforms_tasks_meta';
public function get_columns() {
public function get_column_defaults() {
'date' => gmdate( 'Y-m-d H:i:s' ),
* Create custom entry meta database table.
* Used in migration and on plugin activation.
* @noinspection UnusedFunctionResultInspection
public function create_table() {
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $this->table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
action varchar(255) NOT NULL,
* Remove queue records for a defined period of time in the past.
* Calling this method will remove queue records that are older than $period seconds.
* @param string $action Action that should be cleaned up.
* @param int $interval Number of seconds from now.
* @return int Number of removed tasks meta records.
public function clean_by( $action, $interval ) {
if ( empty( $action ) || empty( $interval ) ) {
$table = self::get_table_name();
$action = sanitize_key( $action );
$date = gmdate( 'Y-m-d H:i:s', time() - (int) $interval );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
return (int) $wpdb->query(
"DELETE FROM $table WHERE action = %s AND date < %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
* Inserts a new record into the database.
* @param array $data Column data.
* @param string $type Optional. Data type context.
* @return int ID for the newly inserted record. Zero otherwise.
public function add( $data, $type = '' ) {
if ( empty( $data['action'] ) || ! is_string( $data['action'] ) ) {
$data['action'] = sanitize_key( $data['action'] );
if ( isset( $data['data'] ) ) {
$data['data'] = $this->prepare_data( $data['data'] );
return parent::add( $data, $type );
* @param array $data Meta data.
private function prepare_data( $data ) {
$string = wp_json_encode( $data );
if ( $string === false ) {
* We are encoding the string representation of all the data to make sure that nothing can harm the database.
* This is not an encryption, and we need this data later "as is",
* so we are using one of the fastest ways to do that.
* This data is removed from DB daily.
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
return base64_encode( $string );
* Retrieve a row from the database based on a given row ID.
* @param int $meta_id Meta ID.
* @noinspection PhpParameterNameChangedDuringInheritanceInspection
public function get( $meta_id ) {
$meta = parent::get( $meta_id );
if ( empty( $meta ) || empty( $meta->data ) ) {
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
$decoded = base64_decode( $meta->data );
if ( $decoded === false || ! is_string( $decoded ) ) {
$meta->data = json_decode( $decoded, true );
* Get meta ID by action name and params.
* @param string $action Action name.
* @param array $params Action params.
public function get_meta_id( $action, $params ) {
$table = self::get_table_name();
$action = sanitize_key( $action );
$data = $this->prepare_data( array_values( $params ) );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
"SELECT id FROM $table WHERE action = %s AND data = %s LIMIT 1", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared