get();$id=(int)$page['reservation_page_id'];$post=$id?get_post($id):null; $pageState=!$id?'missing':(!$post||$post->post_status==='trash'?'deleted':($post->post_status!=='publish'?'unpublished':(!$page['shortcode_present']?'shortcode_missing':'ready'))); $paid=(new PaymentSettingsService(new \ABeCe\Booking\Repository\PaymentSettingsRepository()))->get();$payments=$paid['enable_credit']||$paid['enable_pay_on_site']||(($paid['enable_bank_transfer']||$paid['enable_qr_payment'])&&array_filter((array)get_option('abece_booking_bank_payment_profiles',[]),static fn($p)=>!empty($p['active']))); $steps=[ ['timezone',__('Check the time zone','abece-booking'),get_option('timezone_string')!==''?'ok':'warning',admin_url('options-general.php')], ['sports',__('Create a sport','abece-booking'),$this->repository->exists('sports','is_active=1')?'ok':'warning',admin_url('admin.php?page=abece-booking')], ['resources',__('Create a resource','abece-booking'),$this->repository->exists('resources','is_active=1 AND is_bookable=1')?'ok':'warning',admin_url('admin.php?page=abece-booking-resources')], ['hours',__('Set opening hours','abece-booking'),$this->repository->exists('opening_hours')?'ok':'warning',admin_url('admin.php?page=abece-booking-operations')], ['prices',__('Set public prices','abece-booking'),$this->repository->hasPublicPrices()?'ok':'warning',admin_url('admin.php?page=abece-booking-price-lists')], ['payments',__('Set payment methods','abece-booking'),$payments?'ok':'warning',admin_url('admin.php?page=abece-booking-settings&tab=payments')], ['membership',__('Set up membership (optional)','abece-booking'),MembershipModeService::enabled()&&$this->repository->exists('memberships')?'ok':'optional',admin_url('admin.php?page=abece-booking-settings&tab=membership')], ['page',__('Set the booking page','abece-booking'),$pageState==='ready'?'ok':'warning',admin_url('admin.php?page=abece-booking-settings&tab=integrations')], ['test',__('Make a test booking','abece-booking'),'info',$pageState==='ready'?$page['url']:null], ]; if(!\ABeCe\Booking\Edition\Entitlements::current()->has('memberships'))$steps=array_values(array_filter($steps,static fn($step)=>$step[0]!=='membership')); return ['steps'=>array_map(static fn($s)=>array_combine(['key','label','status','url'],$s),$steps),'page_state'=>$pageState,'booking_url'=>$page['url'],'dismissed'=>(bool)get_user_meta(get_current_user_id(),'abece_booking_onboarding_dismissed',true)]; } public function dismiss(array $input): array {BookingValidator::fields($input,['dismissed']);$this->repository->dismiss(CatalogValidator::boolean($input['dismissed']??null,'dismissed'));return $this->onboarding();} public function createPage(array $input): array { if(!current_user_can('manage_options'))throw new CatalogException('abece_booking_forbidden',__('You do not have permission to use these tools.','abece-booking'),403); BookingValidator::fields($input,[]); if(!current_user_can('publish_pages'))throw new CatalogException('abece_booking_forbidden',__('You do not have permission to create a booking page.','abece-booking'),403); global $wpdb;$lock=\ABeCe\Booking\Infrastructure\Database\Tables::lock($wpdb,'page'); if((string)$wpdb->get_var($wpdb->prepare('SELECT GET_LOCK(%s,5)',$lock))!=='1')throw new CatalogException('abece_booking_page_busy',__('Another maintenance operation is running. Try again later.','abece-booking'),409); try{ $selected=get_post((int)get_option('abece_booking_reservation_page_id',0));$candidates=$selected?[$selected]:[]; $candidates=array_merge($candidates,get_posts(['post_type'=>'page','post_status'=>'publish','numberposts'=>-1]));$id=0; foreach($candidates as $p)if($p->post_type==='page'&&$p->post_status==='publish'&&(has_shortcode($p->post_content,'abece_booking')||has_shortcode($p->post_content,'sports_booking'))){$id=$p->ID;break;} if(!$id){$id=wp_insert_post(['post_type'=>'page','post_status'=>'publish','post_title'=>__('Bookings','abece-booking'),'post_content'=>'[abece_booking]'],true);if(is_wp_error($id))throw new CatalogException('abece_booking_page_failed',__('The booking page could not be created. Try again.','abece-booking'),500);} update_option('abece_booking_reservation_page_id',$id,false);return $this->onboarding(); }finally{$wpdb->get_var($wpdb->prepare('SELECT RELEASE_LOCK(%s)',$lock));} } public function status(): array { $checks=[];$add=static function($key,$label,$level,$value)use(&$checks){$checks[]=['key'=>$key,'label'=>$label,'status'=>$level,'value'=>$value];};$health=$this->repository->health(); $edition=\ABeCe\Booking\Edition\Entitlements::current();$add('edition',__('Build','abece-booking'),'info',ucfirst($edition->edition()));$add('plan',__('Plan','abece-booking'),'info',ucfirst($edition->plan()));$resources=new \ABeCe\Booking\Repository\ResourcesRepository($GLOBALS['wpdb']);$add('resource_limit',__('Active bookable resources','abece-booking'),'info',$resources->activeBookableCount().' / '.($edition->limit('resources')??'∞')); $add('plugin',__('Plugin version','abece-booking'),'ok',\ABeCe\Booking\Plugin::VERSION); $add('wordpress',__('WordPress version','abece-booking'),'info',get_bloginfo('version')); $add('site',__('Site domain','abece-booking'),'info',(string)wp_parse_url(home_url(),PHP_URL_HOST)); $add('locale',__('Site / administrator language','abece-booking'),'info',(get_option('WPLANG')?:'en_US').' / '.get_user_locale()); $add('timezone',__('Time zone','abece-booking'),get_option('timezone_string')!==''?'ok':'warning',wp_timezone()->getName()); $add('formats',__('Date / time format','abece-booking'),'info',get_option('date_format').' / '.get_option('time_format')); $add('permalinks',__('Permalinks','abece-booking'),'info',get_option('permalink_structure')?__('Pretty URLs','abece-booking'):__('Plain URLs','abece-booking')); $add('multisite',__('Multisite','abece-booking'),is_multisite()?'error':'ok',is_multisite()?__('Not supported','abece-booking'):__('Single site','abece-booking')); $add('php',__('PHP version','abece-booking'),'info',PHP_VERSION); $add('limits',__('Memory / execution / upload / post limits','abece-booking'),'info',implode(' / ',array_map('ini_get',['memory_limit','max_execution_time','upload_max_filesize','post_max_size']))); $errors=RuntimeRequirements::errors(false,dirname(__DIR__,2));$add('requirements',__('Runtime requirements','abece-booking'),$errors?'error':'ok',$errors?implode(' ',$errors):__('Requirements met','abece-booking')); $add('extensions',__('PHP extensions','abece-booking'),'info',implode(', ',array_filter([...RuntimeRequirements::EXTENSIONS,'intl'], 'extension_loaded'))); $add('database',__('Database server','abece-booking'),'info',$health['server']); $add('schema',__('Database schema / expected schema','abece-booking'),(int)get_option(Installer::VERSION_OPTION)===Installer::LATEST_VERSION?'ok':'error',(string)get_option(Installer::VERSION_OPTION).' / '.Installer::LATEST_VERSION); $add('tables',__('Plugin tables / expected tables','abece-booking'),$health['missing']?'error':'ok',$health['actual'].' / '.$health['expected']); $add('prefix',__('Table prefix','abece-booking'),'info',$health['prefix']); $add('collation',__('Storage engine / collation','abece-booking'),$health['unsafe_engines']?'error':'info',implode(', ',$health['collations'])); $add('missing',__('Missing plugin tables','abece-booking'),$health['missing']?'error':'ok',implode(', ',$health['missing'])); $routes=rest_get_server()->get_routes();$expected=['/abece-booking/v1/calendar','/abece-booking/v1/bookings','/abece-booking/v1/admin/statistics/overview','/abece-booking/v1/admin/tools/status'];$registered=count(array_filter($expected,static fn($p)=>isset($routes[$p]))); $add('rest',__('REST registration','abece-booking'),$registered===count($expected)?'ok':'error','abece-booking/v1: '.$registered.' / '.count($expected)); $add('translations',__('Current translation / supported languages','abece-booking'),'info',LocaleContext::current().' / '.implode(', ',LocaleContext::SUPPORTED)); $add('cron',__('Import cleanup scheduling','abece-booking'),'info',(defined('DISABLE_WP_CRON')&&DISABLE_WP_CRON?__('WP-Cron is disabled.','abece-booking').' ':__('WP-Cron is enabled.','abece-booking').' ').'abece_booking_member_import_expire'); $add('temp',__('Temporary storage','abece-booking'),is_writable(sys_get_temp_dir())?'ok':'error',__('Private expiring import staging; temporary downloads are not public files.','abece-booking')); $add('mail',__('Email transport','abece-booking'),'info',__('WordPress can submit email; delivery must be verified with the recipient.','abece-booking')); $onboarding=$this->onboarding();$add('page',__('Booking page','abece-booking'),$onboarding['page_state']==='ready'?'ok':'warning',$onboarding['page_state']); $add('membership',__('Membership mode','abece-booking'),'info',MembershipModeService::enabled()?__('Enabled','abece-booking'):__('Disabled','abece-booking')); if(\ABeCe\Booking\Edition\Entitlements::current()->has('bank_transfer')){$bank=\ABeCe\Booking\Edition\Modules::current()->bankStatus((array)get_option('abece_booking_bank_payment_profiles',[]));$add('bank',__('Bank payment profiles','abece-booking'),$bank['status'],$bank['value']);} $rules=(new BookingRulesService(new \ABeCe\Booking\Repository\SettingsRepository()))->get();$add('bookings',__('Booking settings','abece-booking'),'info',__('Configured','abece-booking').' / '.(int)$rules['max_daily_customer_bookings']); $buildFile=dirname(__DIR__,2).'/assets/build/release.json';$build=is_readable($buildFile)?json_decode(file_get_contents($buildFile),true):[];$add('build',__('Build identifier','abece-booking'),'info',is_string($build['source_sha256']??null)?$build['source_sha256']:__('Development checkout','abece-booking')); return ['checks'=>$checks,'report'=>__('ABeCe Booking system report','abece-booking')."\n".implode("\n",array_map(static fn($c)=>'['.strtoupper($c['status']).'] '.$c['label'].': '.$c['value'],$checks))]; } public function testEmail(array $input): array { if(!current_user_can('manage_options'))throw new CatalogException('abece_booking_forbidden',__('You do not have permission to use these tools.','abece-booking'),403); BookingValidator::fields($input,['recipient']);$recipient=$input['recipient']??null; if(!is_string($recipient)||preg_match('/[\r\n]/',$recipient)||!is_email($recipient)||strlen($recipient)>254)CatalogValidator::invalid('recipient',__('Enter a valid email address.','abece-booking')); $recipient=sanitize_email($recipient);$key='abece_booking_test_email_'.get_current_user_id();if(get_transient($key))throw new CatalogException('abece_booking_mail_rate_limit',__('Wait one minute before sending another test email.','abece-booking'),429); set_transient($key,true,60);$ok=wp_mail($recipient,__('ABeCe Booking test email','abece-booking'),__('This is a diagnostic email from your WordPress site. It contains no booking or customer data.','abece-booking')); return ['submitted'=>$ok,'message'=>$ok?__('WordPress accepted the email for sending. Confirm delivery with the recipient.','abece-booking'):__('WordPress could not submit the email. Check your site mail configuration.','abece-booking')]; } public function deleteData(array $input): array { if(!current_user_can('manage_options'))throw new CatalogException('abece_booking_forbidden',__('You do not have permission to use these tools.','abece-booking'),403); BookingValidator::fields($input,['confirmation']); if(!is_string($input['confirmation']??null)||!hash_equals(__('DELETE DATA','abece-booking'),$input['confirmation']))CatalogValidator::invalid('confirmation',__('Type the exact confirmation text to remove plugin data.','abece-booking')); return $this->repository->delete(); } }