*/ private array $values; private Plugin_Settings $settings; private Settings_Storage $settings_storage; private Layout_Settings_Storage $layouts_settings_storage; private Selection_Settings_Storage $post_selections_settings_storage; private string $saved_message; private Git_Repository $git_repository; private State_Report $state_report; private Engines_Storage $engines_storage; public function __construct( Logger $logger, Plugin_Settings $settings, Settings_Storage $settings_storage, Layout_Settings_Storage $layouts_settings_storage, Selection_Settings_Storage $post_selections_settings_storage, Git_Repository $git_repository, State_Report $state_report, Engines_Storage $engines_storage ) { parent::__construct( $logger ); $this->values = array(); $this->settings = $settings; $this->settings_storage = $settings_storage; $this->layouts_settings_storage = $layouts_settings_storage; $this->post_selections_settings_storage = $post_selections_settings_storage; $this->saved_message = ''; $this->git_repository = $git_repository->getDeepClone(); $this->state_report = $state_report; $this->engines_storage = $engines_storage; } public static function has_route_hooks( Route_Detector $route_detector ): bool { return $route_detector->is_admin_route(); } public function set_route_hooks( Route_Detector $route_detector ): void { // init, not acf/init, as the method uses 'get_edit_post_link' which will be available only since this hook // (because we sign up the CPTs in this hook). self::add_action( 'init', array( $this, 'add_page' ) ); self::add_action( 'acf/save_post', array( $this, 'maybe_catch_values' ) ); // priority 20, as it's after the ACF's save_post hook. self::add_action( 'acf/save_post', array( $this, 'maybe_process' ), 20 ); self::add_action( 'acf/input/admin_head', array( $this, 'maybe_inject_values' ) ); $choices_callbacks = array( Plugin_Settings::FIELD_TEMPLATE_ENGINE => fn() => $this->engines_storage->get_choices(), ); Acf_Utils::bind_field_choices( Plugin_Settings::class, $choices_callbacks ); } public function add_page(): void { // do not use 'acf_add_options_page', as the global options-related functions may be unavailable // (in case of the manual include). if ( false === function_exists( 'acf_options_page' ) ) { return; } $result_message = Query_Arguments::get_string_for_non_action( 'resultMessage' ); $updated_message = '' === $result_message ? __( 'Settings successfully updated.', 'acf-views' ) : $result_message; acf_options_page()->add_page( array( 'slug' => self::SLUG, 'page_title' => __( 'Settings', 'acf-views' ), 'menu_title' => __( 'Settings', 'acf-views' ), 'parent_slug' => sprintf( 'edit.php?post_type=%s', Hard_Layout_Cpt::cpt_name() ), 'position' => 2, 'update_button' => __( 'Save changes', 'acf-views' ), 'updated_message' => $updated_message, ) ); } /** * @param mixed $post_id */ public function maybe_catch_values( $post_id ): void { if ( false === $this->is_my_source( $post_id ) ) { return; } self::add_filter( 'acf/pre_update_value', function ( $is_updated, $value, $post_id, array $field ): bool { // extra check, as probably it's about another post. if ( ! $this->is_my_source( $post_id ) ) { return $is_updated; } $field_name = (string) ( $field['name'] ?? '' ); // convert repeater format. don't check simply 'is_array(value)' as not every array is a repeater // also check to make sure it's array (can be empty string). if ( Plugin_Settings::getAcfFieldName( Plugin_Settings::FIELD_GIT_REPOSITORIES ) === $field_name && is_array( $value ) ) { $value = Group::convertRepeaterFieldValues( $field_name, $value ); } $this->values[ $field_name ] = $value; // avoid saving to the postmeta. return true; }, 10, 4 ); } public function maybe_inject_values(): void { if ( false === $this->is_my_source( 'options' ) ) { return; } $acf_field_values = $this->get_acf_field_values(); self::add_filter( 'acf/pre_load_value', function ( $value, $post_id, $field ) use ( $acf_field_values ) { // extra check, as probably it's about another post. if ( ! $this->is_my_source( $post_id ) ) { return $value; } $field_name = string( $field, 'name' ); if ( key_exists( $field_name, $acf_field_values ) ) { return $acf_field_values[ $field_name ]; } return $value; }, 10, 3 ); } /** * @param mixed $post_id * * @throws Exception */ public function maybe_process( $post_id ): void { if ( ! $this->is_my_source( $post_id ) || array() === $this->values ) { return; } $this->settings->load( false, '', $this->values ); $this->settings_storage->set_is_dev_mode( $this->settings->is_dev_mode ); $this->settings_storage->set_live_reload_interval_seconds( $this->settings->live_reload_interval_seconds ); $this->settings_storage->set_live_reload_inactive_delay_seconds( $this->settings->live_reload_inactive_delay_seconds ); $this->settings_storage->set_template_engine( $this->settings->template_engine ); $this->settings_storage->set_web_components_type( $this->settings->web_components_type ); $this->settings_storage->set_classes_generation( $this->settings->classes_generation ); $this->settings_storage->set_is_cpt_admin_optimization_enabled( $this->settings->is_cpt_admin_optimization_enabled ); $this->settings_storage->set_sass_template( $this->settings->sass_template ); $this->settings_storage->set_ts_template( $this->settings->ts_template ); $git_repositories = array(); foreach ( $this->settings->git_repositories as $git_repository ) { $git_repositories[] = array( 'id' => $git_repository->id, 'accessToken' => $git_repository->access_token, 'name' => $git_repository->name, ); } $this->settings_storage->set_git_repositories( $git_repositories ); $is_do_not_track_request_needed = ! $this->settings_storage->is_automatic_reports_disabled() && $this->settings->is_automatic_reports_disabled; $this->settings_storage->set_is_automatic_reports_disabled( $this->settings->is_automatic_reports_disabled ); // send only after the setting is updated. if ( $is_do_not_track_request_needed ) { $this->state_report->send_do_not_track_request(); } if ( $this->settings->is_file_system_storage && false === $this->layouts_settings_storage->get_file_system()->is_active() ) { $this->activate_fs_storage(); } if ( false === $this->settings->is_file_system_storage && $this->layouts_settings_storage->get_file_system()->is_active() ) { $this->deactivate_fs_storage(); } $this->settings_storage->save(); if ( '' === $this->saved_message ) { return; } wp_safe_redirect( add_query_arg( array( 'message' => 1, 'resultMessage' => $this->saved_message, ) ) ); exit; } /** * @return array */ protected function get_acf_field_values(): array { $acf_field_values = array(); foreach ( $this->get_field_values() as $field_name => $value ) { $acf_field_name = Plugin_Settings::getAcfFieldName( $field_name ); $acf_field_values[ $acf_field_name ] = $value; } return $acf_field_values; } /** * @return array */ protected function get_field_values(): array { return array( Plugin_Settings::FIELD_IS_DEV_MODE => $this->settings_storage->is_dev_mode(), Plugin_Settings::FIELD_IS_FILE_SYSTEM_STORAGE => strlen( $this->layouts_settings_storage->get_file_system()->get_base_folder() ) > 0, Plugin_Settings::FIELD_GIT_REPOSITORIES => $this->resolve_git_repositories(), Plugin_Settings::FIELD_IS_AUTOMATIC_REPORTS_DISABLED => $this->settings_storage->is_automatic_reports_disabled(), Plugin_Settings::FIELD_TEMPLATE_ENGINE => $this->settings_storage->get_template_engine(), Plugin_Settings::FIELD_WEB_COMPONENTS_TYPE => $this->settings_storage->get_web_component_type(), Plugin_Settings::FIELD_CLASSES_GENERATION => $this->settings_storage->get_classes_generation(), Plugin_Settings::FIELD_IS_CPT_ADMIN_OPTIMIZATION_ENABLED => $this->settings_storage->is_cpt_admin_optimization_enabled(), Plugin_Settings::FIELD_SASS_TEMPLATE => $this->settings_storage->get_sass_code(), Plugin_Settings::FIELD_TS_TEMPLATE => $this->settings_storage->get_ts_code(), Plugin_Settings::FIELD_LIVE_RELOAD_INTERVAL_SECONDS => $this->settings_storage->get_live_reload_interval_seconds(), Plugin_Settings::FIELD_LIVE_RELOAD_INACTIVE_DELAY_SECONDS => $this->settings_storage->get_live_reload_inactive_delay_seconds(), ); } /** * @return mixed[] */ protected function resolve_git_repositories(): array { $this->settings->git_repositories = array(); foreach ( $this->settings_storage->get_git_repositories() as $git_repository_data ) { $git_repository = $this->git_repository->getDeepClone(); $git_repository->id = string( $git_repository_data, 'id' ); $git_repository->access_token = string( $git_repository_data, 'accessToken' ); $git_repository->name = string( $git_repository_data, 'name' ); $this->settings->git_repositories[] = $git_repository; } $field_name = Plugin_Settings::getAcfFieldName( Plugin_Settings::FIELD_GIT_REPOSITORIES ); $value = $this->settings->getFieldValues()[ $field_name ] ?? array(); $value = is_array( $value ) ? Group::convertRepeaterFieldValues( $field_name, $value, false ) : array(); $this->settings->git_repositories = array(); return $value; } /** * @param mixed $post_id */ protected function is_my_source( $post_id ): bool { $screen = get_current_screen(); $settings_screen = sprintf( '%s_page_%s', Hard_Layout_Cpt::cpt_name(), self::SLUG ); return null !== $screen && $settings_screen === $screen->id && 'options' === $post_id; } protected function activate_fs_storage(): void { $wp_filesystem = $this->layouts_settings_storage->get_file_system()->get_wp_filesystem(); $target_base_folder = $this->layouts_settings_storage->get_file_system()->get_target_base_folder(); if ( false === $wp_filesystem->mkdir( $target_base_folder, 0755 ) ) { $this->saved_message = __( 'Fail to activate the file system storage. Check your FS permissions.', 'acf-views' ); return; } // set, as the folder was just created. $this->layouts_settings_storage->get_file_system()->set_base_folder(); $this->post_selections_settings_storage->get_file_system()->set_base_folder(); $this->layouts_settings_storage->activate_file_system_storage(); $this->post_selections_settings_storage->activate_file_system_storage(); } protected function deactivate_fs_storage(): void { $theme_templates_folder = $this->layouts_settings_storage->get_file_system()->get_base_folder(); $this->layouts_settings_storage->deactivate_file_system_storage(); $this->post_selections_settings_storage->deactivate_file_system_storage(); $is_removed = $this->layouts_settings_storage->get_file_system() ->get_wp_filesystem() ->rmdir( $theme_templates_folder, true ); if ( $is_removed ) { return; } $this->saved_message = __( 'Fail to deactivate the file system storage. Check your FS permissions.', 'acf-views' ); } }