loadHTML( $tzlist ); $elements = $doc->getElementsByTagName( 'option' ); $timezones = array(); if ( ! empty( $elements ) ) { foreach ( $elements as $element ) { $data = array( 'value' => $element->getAttribute( 'value' ), 'name' => $element->textContent, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase ); $timezones[] = $data; } } return $timezones; } } if ( ! function_exists( 'booktics_get_auth_redirect_uri' ) ) { /** * Get auth redirect uri * * @param string $auth * * @return string */ function booktics_get_auth_redirect_uri( $auth = '' ) { return site_url( 'booktics-integration/' . $auth ); } } if ( ! function_exists( 'booktics_get_google_auth' ) ) { /** * Get google auth * * @param integer $user_id * * @return array */ function booktics_get_google_auth( $user_id = 0 ) { return get_user_meta( $user_id, 'booktics_google_auth', true ); } } if ( ! function_exists( 'booktics_get_posts' ) ) { /** * Get posts with date range * * @param array $args * * @return WP_Query */ function booktics_get_posts( $args = array() ) { $defaults = array( 'post_type' => 'post', 'post_status' => 'publish', 'nopaging' => true, 'date_range' => '', ); $args = wp_parse_args( $args, $defaults ); // Date range found. if ( $args['date_range'] ) { $from_date = $args['date_range']['start']; $to_date = $args['date_range']['end']; $args['date_query'] = array( 'relation' => 'AND', array( 'before' => array( 'year' => gmdate( 'Y', strtotime( $to_date ) ), 'month' => gmdate( 'm', strtotime( $to_date ) ), 'day' => gmdate( 'd', strtotime( $to_date ) ), ), 'after' => array( 'year' => gmdate( 'Y', strtotime( $from_date ) ), 'month' => gmdate( 'm', strtotime( $from_date ) ), 'day' => gmdate( 'd', strtotime( $from_date ) ), ), 'inclusive' => true, ), ); } // The Query $posts = new WP_Query( $args ); return $posts; } } if ( ! function_exists( 'booktics_count_posts()' ) ) { /** * Count post with date range or without date range * * @param array $args Required query params * * @return integer */ function booktics_count_posts( $args = array() ) { $posts = booktics_get_posts( $args ); return $posts->post_count; } } if ( ! function_exists( 'booktics_count_users' ) ) { /** * Count user by role and date range * * @param array $args Required query params * * @return integer */ function booktics_count_users( $args = array() ) { $defaults = array( 'role' => '', 'date_range' => '', 'count_total' => true, ); $args = wp_parse_args( $args, $defaults ); // Date range found. if ( $args['date_range'] ) { $from_date = $args['date_range']['start']; $to_date = $args['date_range']['end']; $args['date_query'] = array( 'relation' => 'AND', array( 'before' => array( 'year' => gmdate( 'Y', strtotime( $to_date ) ), 'month' => gmdate( 'm', strtotime( $to_date ) ), 'day' => gmdate( 'd', strtotime( $to_date ) ), ), 'after' => array( 'year' => gmdate( 'Y', strtotime( $from_date ) ), 'month' => gmdate( 'm', strtotime( $from_date ) ), 'day' => gmdate( 'd', strtotime( $from_date ) ), ), 'inclusive' => true, ), ); } // The Query $user_query = new WP_User_Query( $args ); // Return total users. return $user_query->total_users; } } if ( ! function_exists( 'booktics_get_default_timezone' ) ) { /** * Get default timezone * * @return string */ function booktics_get_default_timezone() { $timezone = get_option( 'timezone_string' ); return $timezone; } } if ( ! function_exists( 'booktics_get_currencies' ) ) { /** * Get currency list * * @return array */ function booktics_get_currencies() { $currencies = require_once __DIR__ . '/currency.php'; return $currencies; } } if ( ! function_exists( 'booktics_update_default_settings' ) ) { /** * Update default settings * * @return void */ function booktics_update_default_settings() { $settings = array( 'google_auth_redirect_uri' => booktics_get_auth_redirect_uri( 'google-auth' ), 'default_booking_status' => 'pending', 'currency' => 'USD', 'primary_color' => '#3161F1', 'secondary_color' => '#6188ff', ); $settings = apply_filters( 'booktics_default_settings', $settings ); foreach ( $settings as $key => $value ) { booktics_update_option( $key, $value ); } } } if ( ! function_exists( 'booktics_get_post_status' ) ) { /** * Get post status * * @return array */ function booktics_get_post_status() { return array( 'approved', 'pending', 'cancel', 'completed', ); } } if ( ! function_exists( 'booktics_replace_placeholder' ) ) { /** * Replace string with placeholder * * @param array $placeholders * @param string $text * * @return string */ function booktics_replace_placeholder( $text, $placeholders = array() ) { if ( ! $placeholders ) { return $text; } foreach ( $placeholders as $placeholder => $replace_with ) { $text = str_replace( $placeholder, $replace_with, $text ); } return $text; } } if ( ! function_exists( 'booktics_register_cron' ) ) { /** * Register booktics cron * * @return void */ function booktics_register_cron() { wp_schedule_event( time(), 'daily', 'booktics_booking_clear_schedule' ); } } if ( ! function_exists( 'booktics_is_woocommerce_active' ) ) { /** * Check whether WooCommerce payments are usable. * * True only when WooCommerce itself is running, the module is enabled and * the payment setting is on. Any one of the three being false means the * gateway must not be offered. * * @return bool */ function booktics_is_woocommerce_active() { if ( ! class_exists( 'WooCommerce' ) ) { return false; } if ( ! booktics_extension()->is_enabled( 'woocommerce' ) ) { return false; } return (bool) booktics_get_option( 'enable_woocommerce_payment' ); } } if ( ! function_exists( 'booktics_is_valid_timezone' ) ) { /** * Check a timezone is valid or not * * @param string $timezone * * @return bool */ function booktics_is_valid_timezone( $timezone ) { try { new DateTimeZone( $timezone ); } catch ( Exception $e ) { return false; } return true; } } if ( ! function_exists( 'booktics_datetime' ) ) { /** * Booktics date time with timezone * * @param int | string $date * @param string $timezone * * @return string */ function booktics_datetime( $format, $date, $timezone = '' ) { $date = is_int( $date ) ? gmdate( 'Y-m-d g:ia', $date ) : $date; if ( ! $timezone ) { $timezone = 'UTC'; } // Create a DateTime object with the provided timestamp and time zone $datetime = new \DateTime( $date, new \DateTimeZone( $timezone ) ); // Get the converted timestamp return $datetime->format( $format ); } } if ( ! function_exists( 'booktics_convert_timezone' ) ) { /** * Convert date and time from timezone to another timezone * * @param string $format * @param string $date_time * @param string $from * @param string $to * * @return \DateTime */ function booktics_convert_timezone( $date_time_string, $from, $to ) { if ( empty( $from ) || empty( $to ) ) { return new DateTime( $date_time_string ); } $date_time_string = is_int( $date_time_string ) ? gmdate( 'Y-m-d g:ia', $date_time_string ) : gmdate( 'Y-m-d g:ia', strtotime( $date_time_string ) ); $datetime = new DateTime( $date_time_string, new DateTimeZone( $from ) ); $datetime->setTimezone( new DateTimeZone( $to ) ); return $datetime; } } if ( ! function_exists( 'booktics_generate_username' ) ) { /** * Generate unique username * * @param string $email * * @return string */ function booktics_generate_username( $email ) { $username = strtok( $email, '@' ); if ( username_exists( $username ) ) { $username = $username . wp_rand( 10, 100 ); } return $username; } } if ( ! function_exists( 'booktics_is_json' ) ) { /** * Check a string is valid json or not * * @param string $json_string * * @return bool */ function booktics_is_json( $json_string ) { if ( ! is_string( $json_string ) ) { return false; } $data = json_decode( $json_string, true ); return $data !== null && json_last_error() === JSON_ERROR_NONE; } } if ( ! function_exists( 'booktics_get_current_user' ) ) { /** * Get current user data * * @return array */ function booktics_get_current_user() { $user_id = get_current_user_id(); $user = get_userdata( $user_id ); $user_data = array( 'id' => $user->ID, 'username' => $user->user_login, 'email' => $user->user_email, 'roles' => $user->roles, ); return $user_data; } } if ( ! function_exists( 'booktics_validate' ) ) { /** * Validate user input * * @param array $request * @param array $rules * * @return bool | WP_Error */ function booktics_validate( $request, $rules ) { $validator = new \Booktics\Validation\Validator( $request ); $validator->set_rules( $rules ); if ( ! $validator->validate() ) { return $validator->get_error(); } return true; } } if ( ! function_exists( 'booktics_snake_case' ) ) { /** * Convert a string to snake_case. * * @param string $string * * @return string */ function booktics_snake_case( string $string ): string { $string = preg_replace( '/([a-z])([A-Z])/', '$1_$2', $string ); return strtolower( str_replace( array( '-', ' ' ), '_', $string ) ); } } if ( ! function_exists( 'booktics_kebab_case' ) ) { /** * Convert a string to kebab-case. * * @param string $string * * @return string */ function booktics_kebab_case( string $string ): string { $string = preg_replace( '/([a-z])([A-Z])/', '$1-$2', $string ); return strtolower( str_replace( array( '_', ' ' ), '-', $string ) ); } } if ( ! function_exists( 'booktics_camel_case' ) ) { /** * Convert a string to camelCase. * * @param string $string * * @return string */ function booktics_camel_case( string $string ): string { $string = str_replace( array( '-', '_' ), ' ', strtolower( $string ) ); $string = ucwords( $string ); $string = str_replace( ' ', '', $string ); return lcfirst( $string ); } } if ( ! function_exists( 'booktics_pascal_case' ) ) { /** * Convert a string to PascalCase. * * @param string $string * * @return string */ function booktics_pascal_case( string $string ): string { $string = str_replace( array( '-', '_' ), ' ', strtolower( $string ) ); $string = ucwords( $string ); return str_replace( ' ', '', $string ); } } if ( ! function_exists( 'booktics_date_range_loop' ) ) { /** * Make date range iterable array * * @param $start * @param $end * @param $step * @param $format * * @return array * @throws Exception */ function booktics_date_range_loop( $start, $end, $step = '+1 day', $format = 'Y-m-d' ) { $dates = array(); $current_date = new DateTime( $start ); $end_date = new DateTime( $end ); while ( $current_date <= $end_date ) { $dates[] = $current_date->format( $format ); $current_date->modify( $step ); } return $dates; } if ( ! function_exists( 'booktics_get_option' ) ) { /** * Get option for Booktics * * @param string $key Option key * @param mixed $default Default value to return if option doesn't exist * * @return mixed */ function booktics_get_option( $key = '', $default = false ) { return \Booktics\Settings\Settings::get( $key, $default ); } } if ( ! function_exists( 'booktics_update_option' ) ) { /** * Update Booktics option * * @param string $key Option key * @param mixed $value Option value * * @return void */ function booktics_update_option( $key, $value ) { \Booktics\Settings\Settings::update( $key, $value ); } } } if ( ! function_exists( 'booktics_is_pro_active' ) ) { /** * Check Booktics Pro plugin activate or deactivate * * @return bool */ function booktics_is_pro_active(): bool { return is_plugin_active( 'booktics-pro/booktics-pro.php' ); } } if ( ! function_exists( 'booktics_extension' ) ) { /** * Get Booktics extension object from tools-sdk */ function booktics_extension() { return ( new \Arraytics\ToolsSdk\Extension( 'booktics_available_modules', booktics_modules_list() ) ); } } if ( ! function_exists( 'booktics_get_enabled_modules' ) ) { /** * Get enabled modules * * @return array */ function booktics_get_enabled_modules(): array { $modules = get_option( 'booktics_available_modules', array() ); if ( empty( $modules ) || ! is_array( $modules ) ) { return array(); } $enabled = array(); foreach ( $modules as $module_slug => $module_data ) { if ( is_array( $module_data ) && isset( $module_data['status'] ) && $module_data['status'] === 'on' ) { $enabled[] = $module_slug; } elseif ( is_string( $module_data ) && $module_data === 'on' ) { $enabled[] = $module_slug; } } return $enabled; } if ( ! function_exists( 'get_booktics_modules_list' ) ) { /** * Get Booktics modules list * * @return array */ function booktics_modules_list(): array { $modules_list = array( 'stripe' => array( 'name' => 'stripe', 'slug' => 'stripe', 'type' => 'module', 'upgrade' => true, 'upgrade_link' => 'https://themewinter.com/purchase-history', 'status' => 'off', 'is_pro' => false, 'title' => __( 'Stripe', 'booktics' ), 'description' => __( 'It allows you to use stripe payment.', 'booktics' ), 'icon' => \Booktics\Extensions\Extension_Icon::get( 'stripe-addon' ), 'notice' => '', 'demo_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-stripe', 'settings_link' => '', 'doc_link' => 'https://docs.arraytics.com/docs/booktics/payment-type/how-to-configure-the-stripe-in-booktics/', ), 'woocommerce' => array( 'name' => 'woocommerce', 'slug' => 'woocommerce', 'type' => 'module', 'upgrade' => true, 'upgrade_link' => 'https://themewinter.com/purchase-history', 'status' => 'off', 'is_pro' => false, 'title' => __( 'WooCommerce', 'booktics' ), 'description' => __( 'Take booking payments through WooCommerce checkout.', 'booktics' ), 'icon' => \Booktics\Extensions\Extension_Icon::get( 'woocommerce-addon' ), 'notice' => '', 'demo_link' => '', 'settings_link' => '', 'doc_link' => 'https://arraytics.com/docs/docs/booktics/integration/woocommerce-payment-in-booktics-setup-guide/', ), 'fluentcrm' => array( 'name' => 'fluentcrm', 'slug' => 'fluentcrm', 'type' => 'integration', 'upgrade' => true, 'upgrade_link' => 'https://themewinter.com/purchase-history', 'status' => 'off', 'is_pro' => false, 'title' => __( 'FluentCRM', 'booktics' ), 'description' => __( 'It allows you to use FluentCRM.', 'booktics' ), 'icon' => \Booktics\Extensions\Extension_Icon::get( 'booktics-fluentcrm-addon' ), 'notice' => '', 'demo_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-fluentcrm', 'settings_link' => '', 'doc_link' => 'https://docs.arraytics.com/docs/booktics/integration/how-to-integrate-fluentcrm-with-booktics/', ), 'pabbly' => array( 'name' => 'pabbly', 'slug' => 'pabbly', 'type' => 'integration', 'upgrade' => true, 'upgrade_link' => 'https://themewinter.com/purchase-history', 'status' => 'off', 'is_pro' => false, 'title' => __( 'Pabbly', 'booktics' ), 'description' => __( 'Send booking data to Pabbly Connect via webhook.', 'booktics' ), 'icon' => \Booktics\Extensions\Extension_Icon::get( 'booktics-pabbly-addon' ), 'notice' => '', 'demo_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-pabbly', 'settings_link' => '', 'doc_link' => 'https://docs.arraytics.com/docs/booktics/integration/how-to-integrate-booktics-with-pabbly/', ), 'zapier' => array( 'name' => 'zapier', 'slug' => 'zapier', 'type' => 'integration', 'upgrade' => true, 'upgrade_link' => 'https://themewinter.com/purchase-history', 'status' => 'off', 'is_pro' => false, 'title' => __( 'Zapier', 'booktics' ), 'description' => __( 'Send booking data to Zapier via webhook.', 'booktics' ), 'icon' => \Booktics\Extensions\Extension_Icon::get( 'booktics-zapier-addon' ), 'notice' => '', 'demo_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-zapier', 'settings_link' => '', 'doc_link' => 'https://docs.arraytics.com/docs/booktics/integration/how-to-integrate-booktics-with-zapier/', ), 'zoho' => array( 'name' => 'zoho', 'slug' => 'zoho', 'type' => 'integration', 'upgrade' => true, 'upgrade_link' => 'https://themewinter.com/purchase-history', 'status' => 'off', 'is_pro' => false, 'title' => __( 'Zoho', 'booktics' ), 'description' => __( 'Send booking data to Zoho via webhook.', 'booktics' ), 'icon' => \Booktics\Extensions\Extension_Icon::get( 'booktics-zoho-addon' ), 'notice' => '', 'demo_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-zoho', 'settings_link' => '', 'doc_link' => 'https://docs.arraytics.com/docs/booktics/integration/how-to-integrate-booktics-with-zoho-crm/', ), 'mailpoet' => array( 'name' => 'mailpoet', 'slug' => 'mailpoet', 'type' => 'integration', 'upgrade' => true, 'upgrade_link' => 'https://themewinter.com/purchase-history', 'status' => 'off', 'is_pro' => false, 'plugin_slug' => 'mailpoet', 'title' => __( 'MailPoet', 'booktics' ), 'description' => __( 'Add booking customers to your MailPoet lists.', 'booktics' ), 'icon' => \Booktics\Extensions\Extension_Icon::get( 'booktics-mailpoet-addon' ), 'notice' => '', 'demo_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-mailpoet', 'settings_link' => '', 'doc_link' => 'https://docs.arraytics.com/docs/booktics/integration/how-to-integrate-booktics-with-mailpoet/', ), 'google-calendar' => array( 'name' => 'google-calendar', 'slug' => 'google-calendar', 'type' => 'module', 'upgrade' => true, 'upgrade_link' => 'https://themewinter.com/purchase-history', 'status' => 'off', 'is_pro' => false, 'title' => __( 'Booktics Google Calendar', 'booktics' ), 'description' => __( 'It allows you to use google calendar.', 'booktics' ), 'icon' => \Booktics\Extensions\Extension_Icon::get( 'booktics-google-calendar' ), 'notice' => '', 'demo_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-google-calendar', 'settings_link' => '', 'doc_link' => 'https://docs.arraytics.com/docs/booktics/integration/how-to-integrate-google-calendar-with-booktics/', ), 'outlook-calendar' => array( 'name' => 'outlook-calendar', 'slug' => 'outlook-calendar', 'type' => 'module', 'upgrade' => true, 'upgrade_link' => 'https://themewinter.com/purchase-history', 'status' => 'off', 'is_pro' => true, 'title' => __( 'Booktics Outlook Calendar', 'booktics' ), 'description' => __( 'It allows you to use outlook calendar.', 'booktics' ), 'icon' => \Booktics\Extensions\Extension_Icon::get( 'booktics-outlook-calendar' ), 'notice' => '', 'demo_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-outlook-calendar-addon', 'settings_link' => '', 'doc_link' => 'https://docs.arraytics.com/docs/booktics/integration/how-to-integrate-outlook-calendar-with-booktics/', ), 'paypal' => array( 'name' => 'paypal', 'slug' => 'paypal', 'type' => 'module', 'upgrade' => true, 'upgrade_link' => 'https://themewinter.com/purchase-history', 'status' => 'off', 'is_pro' => true, 'title' => __( 'PayPal', 'booktics' ), 'description' => __( 'It allows you to use PayPal.', 'booktics' ), 'icon' => \Booktics\Extensions\Extension_Icon::get( 'booktics-paypal-addon' ), 'notice' => '', 'demo_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-paypal-addon', 'settings_link' => '', 'doc_link' => 'https://docs.arraytics.com/docs/booktics/payment-type/how-to-configure-the-paypal-in-booktics-pro/', ), ); return $modules_list; } } } if ( ! function_exists( 'booktics_log' ) ) { /** * Write a debug line, but only when the site has debug logging switched on. * * @param string $message Message to log. * * @return void */ function booktics_log( $message ) { if ( ! defined( 'WP_DEBUG_LOG' ) || ! WP_DEBUG_LOG ) { return; } // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Guarded above; this is the plugin's only debug sink. error_log( 'Booktics: ' . $message ); } } if ( ! function_exists( 'booktics_get_multisite_table_name' ) ) { /** * Get multisite-safe table name * * @param string $table_name * * @return string */ function booktics_get_table_name( $table_name ) { global $wpdb; $prefix = $wpdb->prefix; if ( strpos( $table_name, $prefix ) === 0 ) { return $table_name; } return $wpdb->prefix . $table_name; } } if ( ! function_exists( 'booktics_handle_conflicting_plugins' ) ) { /** * Deactivate conflicting plugins if active and check if they exist. */ function booktics_handle_conflicting_plugins() { // Avoid during AJAX or REST requests if ( wp_doing_ajax() || defined( 'REST_REQUEST' ) ) { return; } // Only proceed if user is logged in and can manage plugins if ( ! is_user_logged_in() || ! current_user_can( 'activate_plugins' ) ) { return; } // Prevent running repeatedly on every page load using a transient if ( get_transient( 'booktics_conflict_check_done' ) ) { return; } $conflicting_plugins = array( 'booktics-google-calendar-addon/booktics-google-calendar.php', 'booktics-outlook-calendar-addon/booktics-outlook-calendar-addon.php', 'booktics-paypal-addon/booktics-paypal-addon.php', 'booktics-stripe-addon/booktics_stripe.php', 'booktics-fluentcrm-addon/booktics-fluentcrm-addon.php', ); $active_plugins = get_option( 'active_plugins', array() ); $deactivated_list = array(); foreach ( $conflicting_plugins as $plugin_file ) { $plugin_path = WP_PLUGIN_DIR . '/' . $plugin_file; if ( file_exists( $plugin_path ) ) { if ( in_array( $plugin_file, $active_plugins, true ) ) { deactivate_plugins( $plugin_file ); $plugin_data = get_plugin_data( $plugin_path ); $deactivated_list[] = $plugin_data['Name']; } } } if ( ! empty( $deactivated_list ) ) { // Store data in transient for 1 minute to show notice once set_transient( 'booktics_deactivated_plugins_notice', $deactivated_list, MINUTE_IN_SECONDS ); } // Set the conflict check as done (even if nothing was deactivated) set_transient( 'booktics_conflict_check_done', true, MINUTE_IN_SECONDS ); } } if ( ! function_exists( 'booktics_show_conflict_deactivation_notice' ) ) { /** * Show a one-time admin notice for deactivated conflicting plugins. */ function booktics_show_conflict_deactivation_notice() { if ( ! current_user_can( 'activate_plugins' ) ) { return; } $deactivated_list = get_transient( 'booktics_deactivated_plugins_notice' ); if ( ! empty( $deactivated_list ) ) { delete_transient( 'booktics_deactivated_plugins_notice' ); $plugin_names = implode( ', ', array_map( 'esc_html', $deactivated_list ) ); ?>


roles; if ( in_array( 'booktics_team_member', $roles, true ) ) { return true; } } return false; } } if ( ! function_exists( 'booktics_is_team_member' ) ) { function booktics_is_team_member() { if ( is_user_logged_in() ) { $roles = (array) wp_get_current_user()->roles; if ( in_array( 'booktics_team_member', $roles, true ) ) { return true; } } return false; } } if ( ! function_exists( 'booktics_time_from_gmt' ) ) { /** * Convert time from GMT/UTC to site timezone * * @param string $time Time string in UTC (e.g., "14:00:00") * @param string|int $context_date Date context (Y-m-d or 0 for regular schedules) * @return string Time in H:i:s format (site timezone) * @since 1.0.15 */ function booktics_time_from_gmt( string $time, $context_date = 0 ): string { // Skip '0' placeholder for holidays if ( $time === '0' || $time === 0 ) { return '0'; } $date = ( $context_date === 0 || $context_date === '0' || empty( $context_date ) ) ? gmdate( 'Y-m-d' ) : $context_date; $timestamp = strtotime( $time ); if ( $timestamp === false ) { return $time; } $formatted_time = gmdate( 'H:i:s', $timestamp ); $gmt_datetime_string = $date . ' ' . $formatted_time; $local_datetime = get_date_from_gmt( $gmt_datetime_string ); return gmdate( 'H:i:s', strtotime( $local_datetime ) ); } } if ( ! function_exists( 'booktics_safe_maybe_unserialize' ) ) { /** * Safely unserialize a value without ever instantiating PHP objects. * * @param mixed $value Possibly serialized value. * * @return mixed Unserialized value, or the original value when not serialized. */ function booktics_safe_maybe_unserialize( $value ) { if ( is_string( $value ) && is_serialized( $value ) ) { // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize -- allowed_classes => false prevents PHP Object Injection. return @unserialize( trim( $value ), array( 'allowed_classes' => false ) ); } return $value; } } if ( ! function_exists( 'booktics_sanitize_id_string' ) ) { /** * Sanitize a free-form identifier received from a request. * * Returns a plain-text string id (e.g. 'default' or a client-generated id such * as a uuid/nanoid). A legitimate identifier is never a PHP-serialized string, * so any value that looks serialized is dropped to '' — this neutralizes PHP * Object Injection payloads at the storage boundary while leaving every real id * untouched. Non-scalar input (arrays/objects) is rejected to ''. * * @param mixed $value Raw value from the request. * * @return string Sanitized identifier, or '' when missing, non-scalar, or serialized. */ function booktics_sanitize_id_string( $value ) { if ( ! is_scalar( $value ) ) { return ''; } $value = sanitize_text_field( (string) $value ); return is_serialized( $value ) ? '' : $value; } } if ( ! function_exists( 'booktics_aisentic_identity' ) ) { /** * Build the site identity offered to Aisentic when the user opts in. * * The consent UI and the send path both read this helper, so the email shown * on the consent checkbox is always the email that actually leaves the site. * * @return array{name: string, email: string, site_url: string} */ function booktics_aisentic_identity(): array { $name = booktics_get_option( 'business_name', get_bloginfo( 'name' ) ); $email = booktics_get_option( 'business_email', get_option( 'admin_email' ) ); return array( 'name' => sanitize_text_field( (string) $name ), 'email' => sanitize_email( (string) $email ), 'site_url' => esc_url_raw( site_url() ), ); } } if ( ! function_exists( 'booktics_aisentic_is_registered' ) ) { /** * Whether Aisentic already holds an API key. * * Reading Aisentic's own storage instead of our consent option means anyone * who connected from Aisentic's screens is never nagged by our banner. * * @return bool True when an Aisentic API key is present. */ function booktics_aisentic_is_registered(): bool { if ( function_exists( 'aisentic_get_option' ) ) { return ! empty( aisentic_get_option( 'llmProviders.aisentic.apiKey', '' ) ); } $settings = get_option( 'aisentic_settings', array() ); return ! empty( $settings['llmProviders']['aisentic']['apiKey'] ); } }