| @@ -511,8 +511,9 @@ | ||
| 511 | 511 | 'default_booking_status' => 'pending', |
| 512 | 512 | 'currency' => 'USD', |
| 513 | 513 | 'primary_color' => '#3161F1', |
| 514 | 514 | 'secondary_color' => '#6188ff', |
| 515 | + 'unpaid_booking_expiry_minutes' => 5, | |
| 515 | 516 | ]; |
| 516 | 517 | |
| 517 | 518 | $settings = apply_filters( 'timetics_default_settings', $settings ); |
| 518 | 519 | |
| @@ -614,8 +615,14 @@ | ||
| 614 | 615 | * @return void |
| 615 | 616 | */ |
| 616 | 617 | function timetics_register_cron() { |
| 617 | 618 | wp_schedule_event( time(), 'daily', 'timetics_booking_clear_schedule' ); |
| 619 | + | |
| 620 | + // Guarded: Hooks::maybe_schedule_cleanup_cron() also calls this on | |
| 621 | + // every 'init', so without the guard it'd stack duplicate events. | |
| 622 | + if ( ! wp_next_scheduled( 'timetics_cleanup_unpaid_bookings' ) ) { | |
| 623 | + wp_schedule_event( time(), 'timetics_five_minutes', 'timetics_cleanup_unpaid_bookings' ); | |
| 624 | + } | |
| 618 | 625 | } |
| 619 | 626 | } |
| 620 | 627 | |
| 621 | 628 | if ( ! function_exists( 'timetics_is_woocommerce_active' ) ) { |
| @@ -945,8 +952,25 @@ | ||
| 945 | 952 | 'demo_link' => '', |
| 946 | 953 | 'settings_link' => '', |
| 947 | 954 | 'doc_link' => 'https://support.themewinter.com/docs/plugins/docs/aisentic/', |
| 948 | 955 | ], |
| 956 | + 'optiontics' => [ | |
| 957 | + 'name' => 'optiontics', | |
| 958 | + 'slug' => 'optiontics', | |
| 959 | + 'type' => 'plugin', | |
| 960 | + 'upgrade' => false, | |
| 961 | + 'upgrade_link' => '', | |
| 962 | + 'status' => 'on', | |
| 963 | + 'is_pro' => false, | |
| 964 | + 'title' => __( 'Optiontics', 'timetics' ), | |
| 965 | + 'description' => __( 'Offer paid add-ons and extra options with every booking — services, extras, packages or custom upgrades that customers can pick during checkout.', 'timetics' ), | |
| 966 | + 'icon' => \Timetics\Core\Addon\Extension_Icon::get( 'optiontics' ), | |
| 967 | + 'notice' => '', | |
| 968 | + 'demo_link' => '', | |
| 969 | + 'settings_link' => '', | |
| 970 | + 'doc_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/optiontics/how-to-create-product-options/', | |
| 971 | + 'download_url' => 'https://github.com/themewinter/optiontics-public/releases/download/release/optiontics.zip', | |
| 972 | + ], | |
| 949 | 973 | ]; |
| 950 | 974 | } |
| 951 | 975 | } |
| 952 | 976 | |
| @@ -1069,16 +1093,19 @@ | ||
| 1069 | 1093 | * The consent UI shows these exact values before anything leaves the site, |
| 1070 | 1094 | * so the connect request must read them from here too. Showing one email |
| 1071 | 1095 | * and sending another would break the consent. |
| 1072 | 1096 | * |
| 1073 | - * Timetics has no business name/email setting of its own, so the site name | |
| 1074 | - * and administrator email are the only sources. | |
| 1097 | + * The account belongs to the person who opts in, so it is the logged-in | |
| 1098 | + * user's name and email. The Ask AI setup dialog lets them edit the email, | |
| 1099 | + * which arrives here as $email. The site admin email is the last fallback. | |
| 1075 | 1100 | * |
| 1101 | + * @param string $email Optional email the user typed in the consent UI. | |
| 1076 | 1102 | * @return array{name:string,email:string,site_url:string} |
| 1077 | 1103 | */ |
| 1078 | - function timetics_aisentic_identity() { | |
| 1079 | - $name = sanitize_text_field( (string) get_bloginfo( 'name' ) ); | |
| 1080 | - $email = sanitize_email( (string) get_option( 'admin_email', '' ) ); | |
| 1104 | + function timetics_aisentic_identity( $email = '' ) { | |
| 1105 | + $user = wp_get_current_user(); | |
| 1106 | + $name = sanitize_text_field( (string) $user->display_name ); | |
| 1107 | + $email = sanitize_email( (string) ( $email ?: $user->user_email ?: get_option( 'admin_email', '' ) ) ); | |
| 1081 | 1108 | |
| 1082 | 1109 | return [ |
| 1083 | 1110 | 'name' => $name, |
| 1084 | 1111 | 'email' => $email, |