*/ public static function get_state() { $state = get_option( self::STATE_OPTION, array() ); return wp_parse_args( is_array( $state ) ? $state : array(), array( 'version' => '', 'status' => 'pending', 'projects_seeded' => false, 'contact_form_id' => 0, 'newsletter_form_id' => 0, 'crm_feeds' => false, 'message' => '', ) ); } /** * Complete integration setup when Fluent Forms and FluentCRM are ready. * * @return void */ public static function maybe_seed() { self::seed_site_configuration(); $state = self::get_state(); if ( self::VERSION === $state['version'] && 'complete' === $state['status'] ) { self::maybe_migrate_contact_form(); return; } if ( ! post_type_exists( GSO_Projects::POST_TYPE ) ) { GSO_Projects::register_content_types(); } self::seed_projects(); if ( ! self::fluent_is_ready() ) { $state['projects_seeded'] = true; $state['status'] = 'waiting'; $state['message'] = __( 'Aguardando Fluent Forms e FluentCRM ativos.', 'gustavoo-portfolio-core' ); update_option( self::STATE_OPTION, $state, false ); return; } if ( ! add_option( self::LOCK_OPTION, time(), '', false ) ) { return; } try { $contact_id = self::upsert_form( 'contact', __( 'Site — Contato e orçamento', 'gustavoo-portfolio-core' ), true ); $newsletter_id = self::upsert_form( 'newsletter', __( 'Site — Newsletter', 'gustavoo-portfolio-core' ), false ); self::upsert_crm_feed( $contact_id, 'contact' ); self::upsert_crm_feed( $newsletter_id, 'newsletter' ); self::save_form_ids( $contact_id, $newsletter_id ); update_option( self::STATE_OPTION, array( 'version' => self::VERSION, 'status' => 'complete', 'projects_seeded' => true, 'contact_form_id' => $contact_id, 'newsletter_form_id' => $newsletter_id, 'crm_feeds' => true, 'message' => __( 'Formulários e feeds do FluentCRM configurados.', 'gustavoo-portfolio-core' ), ), false ); } catch ( Throwable $error ) { $state['status'] = 'error'; $state['message'] = sanitize_text_field( $error->getMessage() ); update_option( self::STATE_OPTION, $state, false ); } finally { delete_option( self::LOCK_OPTION ); } } /** * Configure the WordPress pieces that make the bundled theme work on a * fresh installation. * * Existing sites are left untouched: each value is written only when the * corresponding WordPress setting still has its fresh-install value. * * @return void */ private static function seed_site_configuration() { $state = get_option( self::SITE_OPTION, array() ); if ( ! is_array( $state ) || empty( $state['pages'] ) ) { $home_id = self::ensure_seed_page( 'inicio', __( 'Início', 'gustavoo-portfolio-core' ) ); $blog_id = self::ensure_seed_page( 'blog', __( 'Blog', 'gustavoo-portfolio-core' ) ); if ( $home_id && $blog_id && 'posts' === get_option( 'show_on_front' ) ) { update_option( 'show_on_front', 'page' ); update_option( 'page_on_front', $home_id ); update_option( 'page_for_posts', $blog_id ); } if ( $home_id && $blog_id ) { $state = is_array( $state ) ? $state : array(); $state['pages'] = true; update_option( self::SITE_OPTION, $state, false ); } } if ( empty( $state['widgets'] ) ) { self::seed_theme_widgets(); $state = is_array( $state ) ? $state : array(); $state['widgets'] = true; update_option( self::SITE_OPTION, $state, false ); } } /** * Create a required empty page once and identify it by a private marker. * * @param string $slug Page slug. * @param string $title Page title. * @return int */ private static function ensure_seed_page( $slug, $title ) { $existing = get_posts( array( 'post_type' => 'page', 'post_status' => 'any', 'posts_per_page' => 1, 'fields' => 'ids', 'meta_key' => '_gso_seed_page', 'meta_value' => $slug, ) ); if ( $existing ) { return absint( $existing[0] ); } $page = get_page_by_path( $slug, OBJECT, 'page' ); if ( $page ) { update_post_meta( $page->ID, '_gso_seed_page', $slug ); return absint( $page->ID ); } $page_id = wp_insert_post( array( 'post_type' => 'page', 'post_status' => 'publish', 'post_title' => $title, 'post_name' => $slug, ), true ); if ( is_wp_error( $page_id ) ) { return 0; } update_post_meta( $page_id, '_gso_seed_page', $slug ); return absint( $page_id ); } /** * Reproduce the sidebar and footer widget arrangement from this site. * Widgets are added only to empty areas, so a user's arrangement wins. * * @return void */ private static function seed_theme_widgets() { $sidebars = wp_get_sidebars_widgets(); $sidebars = is_array( $sidebars ) ? $sidebars : array(); $blog_widgets = isset( $sidebars['sidebar-blog'] ) ? (array) $sidebars['sidebar-blog'] : array(); $can_seed_blog = empty( $blog_widgets ) || array( 'gustavoo_portfolio_newsletter-1' ) === $blog_widgets; if ( $can_seed_blog ) { $newsletter = get_option( 'widget_gustavoo_portfolio_newsletter', array() ); $newsletter = is_array( $newsletter ) ? $newsletter : array(); $newsletter[1] = array( 'title' => __( 'Newsletter', 'gustavoo-portfolio-core' ), 'text' => __( 'Receba novos artigos sobre desenvolvimento, infraestrutura e automação.', 'gustavoo-portfolio-core' ), 'form_id' => 0, ); $newsletter['_multiwidget'] = 1; update_option( 'widget_gustavoo_portfolio_newsletter', $newsletter, false ); $blocks = get_option( 'widget_block', array() ); $blocks = is_array( $blocks ) ? $blocks : array(); $blocks[2] = array( 'content' => '' ); $blocks[3] = array( 'content' => '

Posts recentes

' ); $blocks[4] = array( 'content' => '

Comentários

' ); $blocks[5] = array( 'content' => '

Arquivos

' ); $blocks[6] = array( 'content' => '

Categorias

' ); $blocks['_multiwidget'] = 1; update_option( 'widget_block', $blocks, false ); $sidebars['sidebar-blog'] = array( 'gustavoo_portfolio_newsletter-1', 'block-2', 'block-3', 'block-4' ); } if ( empty( $sidebars['footer-1'] ) ) { $sidebars['footer-1'] = array( 'block-5', 'block-6' ); } update_option( 'sidebars_widgets', $sidebars, false ); } /** * Repair the seeded contact form when an earlier migration did not persist. * * @return void */ private static function maybe_migrate_contact_form() { if ( ! self::fluent_is_ready() ) { return; } $form = self::find_seeded_form( 'contact' ); if ( ! $form ) { return; } $fields = json_decode( (string) $form->form_fields, true ); $has_message = false; foreach ( (array) ( $fields['fields'] ?? array() ) as $field ) { if ( 'message' === (string) ( $field['attributes']['name'] ?? '' ) && 'textarea' === (string) ( $field['element'] ?? '' ) ) { $has_message = true; break; } } if ( ! $has_message ) { try { self::upsert_form( 'contact', __( 'Site — Contato e orçamento', 'gustavoo-portfolio-core' ), true ); } catch ( Throwable $error ) { // Keep the front end available if Fluent Forms is temporarily unavailable. } } } /** * Check the optional integrations without triggering autoload errors. * * @return bool */ private static function fluent_is_ready() { return defined( 'FLUENTFORM' ) && defined( 'FLUENTCRM' ) && function_exists( 'fluentformLoadFile' ) && function_exists( 'FluentCrmApi' ) && class_exists( '\\FluentForm\\App\\Models\\Form' ) && class_exists( '\\FluentForm\\App\\Models\\FormMeta' ) && class_exists( '\\FluentForm\\App\\Services\\Form\\FormService' ) && class_exists( '\\FluentForm\\App\\Services\\Integrations\\FormIntegrationService' ); } /** * Create or reuse a seed-owned Fluent Form. * * @param string $key Deterministic form key. * @param string $title Form title. * @param bool $include_whatsapp Include the contact message field. * @return int * @throws Exception When Fluent Forms cannot create the form. */ private static function upsert_form( $key, $title, $include_whatsapp ) { $form = self::find_seeded_form( $key ); $defaults = fluentformLoadFile( 'Services/FormBuilder/DefaultElements.php' ); $blank = \FluentForm\App\Models\Form::resolvePredefinedForm( array( 'predefined' => 'blank_form', 'type' => 'form', ) ); $structure = json_decode( (string) $blank['form_fields'], true ); if ( ! is_array( $defaults ) || ! is_array( $structure ) ) { throw new Exception( 'Não foi possível carregar a estrutura padrão do Fluent Forms.' ); } $email = $defaults['general']['input_email']; $email['uniqElKey'] = 'el_gso_' . $key . '_email'; $email['attributes']['name'] = 'email'; $email['attributes']['placeholder'] = __( 'Seu melhor e-mail', 'gustavoo-portfolio-core' ); $email['settings']['label'] = __( 'E-mail', 'gustavoo-portfolio-core' ); $email['settings']['admin_field_label'] = __( 'E-mail', 'gustavoo-portfolio-core' ); $email['settings']['validation_rules']['required']['value'] = true; $fields = array( $email ); if ( $include_whatsapp ) { $whatsapp = $defaults['general']['input_mask']; $whatsapp['uniqElKey'] = 'el_gso_' . $key . '_whatsapp'; $whatsapp['attributes']['name'] = 'whatsapp'; $whatsapp['attributes']['placeholder'] = '(31) 99999-9999'; $whatsapp['attributes']['data-mask'] = '(00) 00000-0000'; $whatsapp['settings']['label'] = __( 'WhatsApp', 'gustavoo-portfolio-core' ); $whatsapp['settings']['admin_field_label'] = __( 'WhatsApp', 'gustavoo-portfolio-core' ); $whatsapp['settings']['mobile_keyboard_type'] = 'tel'; $whatsapp['settings']['temp_mask'] = 'custom'; $whatsapp['settings']['data-mask-reverse'] = 'no'; $whatsapp['settings']['validation_rules']['required']['value'] = true; $fields[] = $whatsapp; $message = $defaults['general']['textarea']; $message['uniqElKey'] = 'el_gso_' . $key . '_message'; $message['attributes']['name'] = 'message'; $message['attributes']['placeholder'] = __( 'Descreva o motivo do contato e o que você quer construir.', 'gustavoo-portfolio-core' ); $message['attributes']['rows'] = 5; $message['settings']['label'] = __( 'Como posso ajudar?', 'gustavoo-portfolio-core' ); $message['settings']['admin_field_label'] = __( 'Motivo do contato', 'gustavoo-portfolio-core' ); $message['settings']['validation_rules']['required']['value'] = true; $fields[] = $message; } $structure['fields'] = $fields; $structure['submitButton']['settings']['button_ui']['text'] = $include_whatsapp ? __( 'Solicitar contato', 'gustavoo-portfolio-core' ) : __( 'Quero receber', 'gustavoo-portfolio-core' ); $service = new \FluentForm\App\Services\Form\FormService(); if ( $form ) { $service->update( array( 'form_id' => $form->id, 'title' => $title, 'status' => 'published', 'formFields' => wp_json_encode( $structure, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ), ) ); self::localize_form_confirmation( $form->id, $include_whatsapp ); return absint( $form->id ); } $form = $service->store( array( 'predefined' => 'blank_form', 'type' => 'form', ) ); $form = $service->update( array( 'form_id' => $form->id, 'title' => $title, 'status' => 'published', 'formFields' => wp_json_encode( $structure, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ), ) ); \FluentForm\App\Models\FormMeta::persist( $form->id, self::FORM_META, $key ); self::localize_form_confirmation( $form->id, $include_whatsapp ); return absint( $form->id ); } /** * Locate a form owned by this seed. * * @param string $key Seed key. * @return object|null */ private static function find_seeded_form( $key ) { $markers = \FluentForm\App\Models\FormMeta::where( 'meta_key', self::FORM_META ) ->where( 'value', $key ) ->get(); foreach ( $markers as $marker ) { $form = \FluentForm\App\Models\Form::find( absint( $marker->form_id ) ); if ( $form ) { return $form; } } return null; } /** * Use a concise Portuguese success message. * * @param int $form_id Form ID. * @param bool $is_contact_form Whether this is the lead form. * @return void */ private static function localize_form_confirmation( $form_id, $is_contact_form ) { $settings = \FluentForm\App\Models\FormMeta::retrieve( 'formSettings', $form_id, array() ); $settings = is_array( $settings ) ? $settings : array(); $settings['confirmation'] = wp_parse_args( array( 'redirectTo' => 'samePage', 'messageToShow' => $is_contact_form ? __( 'Recebi seus dados. Entrarei em contato em breve.', 'gustavoo-portfolio-core' ) : __( 'Inscrição recebida. Confira seu e-mail para confirmar.', 'gustavoo-portfolio-core' ), 'samePageFormBehavior' => 'hide_form', ), isset( $settings['confirmation'] ) && is_array( $settings['confirmation'] ) ? $settings['confirmation'] : array() ); \FluentForm\App\Models\FormMeta::persist( $form_id, 'formSettings', $settings ); } /** * Create the FluentCRM feed for one seed-owned form. * * @param int $form_id Form ID. * @param string $context Contact or newsletter. * @return void */ private static function upsert_crm_feed( $form_id, $context ) { $existing_id = absint( \FluentForm\App\Models\FormMeta::retrieve( self::FEED_META, $form_id, 0 ) ); $defaults = apply_filters( 'fluentform/get_integration_defaults_fluentcrm', array(), $form_id ); $defaults = is_array( $defaults ) ? $defaults : array(); $is_contact = 'contact' === $context; $feed = array_replace( $defaults, array( 'name' => $is_contact ? 'Site / Contato' : 'Site / Newsletter', 'email' => 'email', 'enabled' => true, 'double_opt_in' => ! $is_contact, 'other_fields' => $is_contact ? array( array( 'label' => 'phone', 'item_value' => '{inputs.whatsapp}', ), ) : array(), 'conditionals' => array( 'status' => false, 'type' => 'all', 'conditions' => array(), ), ) ); $result = ( new \FluentForm\App\Services\Integrations\FormIntegrationService() )->update( array( 'form_id' => $form_id, 'integration_id' => $existing_id, 'integration_name' => 'fluentcrm', 'data_type' => 'array', 'status' => true, 'integration' => $feed, ) ); if ( ! empty( $result['integration_id'] ) ) { \FluentForm\App\Models\FormMeta::persist( $form_id, self::FEED_META, absint( $result['integration_id'] ) ); } } /** * Share form IDs with the theme settings option. * * @param int $contact_id Contact form ID. * @param int $newsletter_id Newsletter form ID. * @return void */ private static function save_form_ids( $contact_id, $newsletter_id ) { $settings = GSO_Portfolio_Settings::get_settings(); $settings['contact_form_id'] = absint( $contact_id ); $settings['newsletter_form_id'] = absint( $newsletter_id ); update_option( GSO_Portfolio_Settings::OPTION_NAME, $settings, false ); } /** * Add starter projects only when their deterministic markers are absent. * * @return void */ private static function seed_projects() { $projects = array( 'aurelia-online' => array( 'title' => 'Aurelia Online', 'excerpt' => __( 'Plataforma online desenvolvida com foco em performance, experiência do usuário e evolução contínua.', 'gustavoo-portfolio-core' ), 'type' => 'Plataforma web', 'technologies' => array( 'Web', 'APIs', 'Infraestrutura' ), 'featured' => true, ), 'lumenix-engine' => array( 'title' => 'Lumenix Engine', 'excerpt' => __( 'Engine e ecossistema técnico para experiências interativas e produtos digitais.', 'gustavoo-portfolio-core' ), 'type' => 'Games', 'technologies' => array( 'C++', 'Games', 'Performance' ), 'featured' => true, ), 'aurabet' => array( 'title' => 'AuraBet', 'excerpt' => __( 'Produto digital com arquitetura, integrações e infraestrutura preparadas para escala.', 'gustavoo-portfolio-core' ), 'type' => 'Produto digital', 'technologies' => array( 'Full Stack', 'Docker', 'APIs' ), 'featured' => true, ), 'visionforge' => array( 'title' => 'VisionForge', 'excerpt' => __( 'Solução criada para transformar processos complexos em uma experiência clara e eficiente.', 'gustavoo-portfolio-core' ), 'type' => 'Software', 'technologies' => array( 'Automação', 'Dados', 'Web' ), 'featured' => true, ), 'papel-e-cor' => array( 'title' => 'Papel & Cor', 'excerpt' => __( 'Experiência de e-commerce otimizada para catálogo, compra e conversão.', 'gustavoo-portfolio-core' ), 'type' => 'E-commerce', 'technologies' => array( 'WordPress', 'WooCommerce', 'UX' ), 'featured' => false, ), 'lumina-hub' => array( 'title' => 'Lumina Hub', 'excerpt' => __( 'Hub digital que reúne conteúdo, serviços e integrações em uma única plataforma.', 'gustavoo-portfolio-core' ), 'type' => 'Plataforma web', 'technologies' => array( 'WordPress', 'APIs', 'Automação' ), 'featured' => false, ), ); $order = 0; foreach ( $projects as $key => $project ) { $existing = get_posts( array( 'post_type' => GSO_Projects::POST_TYPE, 'post_status' => 'any', 'posts_per_page' => 1, 'fields' => 'ids', 'meta_key' => self::PROJECT_META, 'meta_value' => $key, ) ); if ( $existing ) { ++$order; continue; } $post_id = wp_insert_post( array( 'post_type' => GSO_Projects::POST_TYPE, 'post_status' => 'publish', 'post_title' => $project['title'], 'post_excerpt' => $project['excerpt'], 'menu_order' => $order, ), true ); if ( is_wp_error( $post_id ) ) { ++$order; continue; } update_post_meta( $post_id, self::PROJECT_META, $key ); update_post_meta( $post_id, GSO_Projects::META_URL, 'https://gustavoo.me/#projetos' ); update_post_meta( $post_id, GSO_Projects::META_CLIENT, __( 'Projeto selecionado', 'gustavoo-portfolio-core' ) ); update_post_meta( $post_id, GSO_Projects::META_YEAR, (int) gmdate( 'Y' ) ); update_post_meta( $post_id, GSO_Projects::META_LINK_LABEL, __( 'Conhecer projeto', 'gustavoo-portfolio-core' ) ); update_post_meta( $post_id, GSO_Projects::META_FEATURED, $project['featured'] ? '1' : '' ); wp_set_object_terms( $post_id, $project['type'], GSO_Projects::TAX_TYPE ); wp_set_object_terms( $post_id, $project['technologies'], GSO_Projects::TAX_TECH ); ++$order; } } }