first commit: gustavoo-portfolio theme + gustavoo-portfolio-core plugin

This commit is contained in:
gustavooth
2026-07-23 21:06:39 -03:00
commit aff10f7880
60 changed files with 9778 additions and 0 deletions
@@ -0,0 +1,212 @@
<?php
/**
* Native WordPress Customizer integration and selective-refresh shortcuts.
*
* @package Gustavo_Portfolio
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/** Sanitize a URL or an in-page anchor used by theme calls to action. */
function gustavoo_portfolio_customize_link( $value ) {
$value = trim( sanitize_text_field( (string) $value ) );
if ( preg_match( '/^#[A-Za-z][A-Za-z0-9_:.-]*$/', $value ) ) {
return $value;
}
return esc_url_raw( $value, array( 'http', 'https', 'mailto', 'tel' ) );
}
/** Render a template part for a selective-refresh partial. */
function gustavoo_portfolio_customize_render_part( $slug ) {
ob_start();
get_template_part( $slug );
return (string) ob_get_clean();
}
/** Register the portfolio content controls in Appearance > Customize. */
function gustavoo_portfolio_customize_register( $wp_customize ) {
$wp_customize->add_panel(
'gustavoo_portfolio_content',
array(
'title' => __( 'Conteúdo do tema', 'gustavoo-portfolio' ),
'description' => __( 'Edite os conteúdos exibidos no site e use os lápis na prévia para ir direto à seção desejada.', 'gustavoo-portfolio' ),
'priority' => 30,
)
);
$sections = array(
'hero' => __( 'Hero', 'gustavoo-portfolio' ),
'about' => __( 'Sobre', 'gustavoo-portfolio' ),
'services' => __( 'Serviços', 'gustavoo-portfolio' ),
'projects' => __( 'Projetos', 'gustavoo-portfolio' ),
'blog' => __( 'Blog', 'gustavoo-portfolio' ),
'contact' => __( 'Contato', 'gustavoo-portfolio' ),
'newsletter' => __( 'Newsletter', 'gustavoo-portfolio' ),
'social' => __( 'Redes sociais', 'gustavoo-portfolio' ),
);
foreach ( $sections as $id => $title ) {
$wp_customize->add_section(
'gustavoo_portfolio_' . $id,
array(
'title' => $title,
'panel' => 'gustavoo_portfolio_content',
'priority' => 10,
)
);
}
$fields = array(
'hero_eyebrow' => array( 'hero', __( 'Sobretítulo', 'gustavoo-portfolio' ), 'text' ),
'hero_title' => array( 'hero', __( 'Título', 'gustavoo-portfolio' ), 'text' ),
'hero_description' => array( 'hero', __( 'Descrição', 'gustavoo-portfolio' ), 'textarea' ),
'hero_primary_label' => array( 'hero', __( 'Botão principal — texto', 'gustavoo-portfolio' ), 'text' ),
'hero_primary_url' => array( 'hero', __( 'Botão principal — link', 'gustavoo-portfolio' ), 'link' ),
'hero_secondary_label' => array( 'hero', __( 'Botão secundário — texto', 'gustavoo-portfolio' ), 'text' ),
'hero_secondary_url' => array( 'hero', __( 'Botão secundário — link', 'gustavoo-portfolio' ), 'link' ),
'about_eyebrow' => array( 'about', __( 'Sobretítulo', 'gustavoo-portfolio' ), 'text' ),
'about_title' => array( 'about', __( 'Título', 'gustavoo-portfolio' ), 'text' ),
'about_text' => array( 'about', __( 'Texto principal', 'gustavoo-portfolio' ), 'textarea' ),
'about_secondary_text' => array( 'about', __( 'Texto complementar', 'gustavoo-portfolio' ), 'textarea' ),
'services_eyebrow' => array( 'services', __( 'Sobretítulo', 'gustavoo-portfolio' ), 'text' ),
'services_title' => array( 'services', __( 'Título', 'gustavoo-portfolio' ), 'text' ),
'services_description' => array( 'services', __( 'Descrição', 'gustavoo-portfolio' ), 'textarea' ),
'projects_eyebrow' => array( 'projects', __( 'Sobretítulo', 'gustavoo-portfolio' ), 'text' ),
'projects_title' => array( 'projects', __( 'Título', 'gustavoo-portfolio' ), 'text' ),
'projects_text' => array( 'projects', __( 'Descrição', 'gustavoo-portfolio' ), 'textarea' ),
'projects_limit' => array( 'projects', __( 'Quantidade de projetos', 'gustavoo-portfolio' ), 'number' ),
'blog_eyebrow' => array( 'blog', __( 'Sobretítulo', 'gustavoo-portfolio' ), 'text' ),
'blog_title' => array( 'blog', __( 'Título', 'gustavoo-portfolio' ), 'text' ),
'blog_text' => array( 'blog', __( 'Descrição', 'gustavoo-portfolio' ), 'textarea' ),
'blog_limit' => array( 'blog', __( 'Quantidade de posts', 'gustavoo-portfolio' ), 'number' ),
'contact_eyebrow' => array( 'contact', __( 'Sobretítulo', 'gustavoo-portfolio' ), 'text' ),
'contact_heading' => array( 'contact', __( 'Título', 'gustavoo-portfolio' ), 'text' ),
'contact_text' => array( 'contact', __( 'Descrição', 'gustavoo-portfolio' ), 'textarea' ),
'email' => array( 'contact', __( 'E-mail', 'gustavoo-portfolio' ), 'email' ),
'whatsapp' => array( 'contact', __( 'WhatsApp — número', 'gustavoo-portfolio' ), 'text' ),
'whatsapp_message' => array( 'contact', __( 'WhatsApp — mensagem inicial', 'gustavoo-portfolio' ), 'textarea' ),
'newsletter_eyebrow' => array( 'newsletter', __( 'Sobretítulo', 'gustavoo-portfolio' ), 'text' ),
'newsletter_heading' => array( 'newsletter', __( 'Título', 'gustavoo-portfolio' ), 'text' ),
'newsletter_text' => array( 'newsletter', __( 'Descrição', 'gustavoo-portfolio' ), 'textarea' ),
'github_url' => array( 'social', __( 'GitHub', 'gustavoo-portfolio' ), 'url' ),
'linkedin_url' => array( 'social', __( 'LinkedIn', 'gustavoo-portfolio' ), 'url' ),
'instagram_url' => array( 'social', __( 'Instagram', 'gustavoo-portfolio' ), 'url' ),
'availability_label' => array( 'social', __( 'Status de disponibilidade', 'gustavoo-portfolio' ), 'text' ),
);
foreach ( $fields as $key => $field ) {
$setting_id = 'gustavoo_portfolio_' . $key;
$sanitize = 'textarea' === $field[2] ? 'sanitize_textarea_field' : ( 'number' === $field[2] ? 'absint' : ( in_array( $field[2], array( 'url', 'link' ), true ) ? 'gustavoo_portfolio_customize_link' : ( 'email' === $field[2] ? 'sanitize_email' : 'sanitize_text_field' ) ) );
$wp_customize->add_setting(
$setting_id,
array(
'default' => gustavoo_portfolio_get_setting( $key ),
'sanitize_callback' => $sanitize,
// Each front-page section is refreshed by its native Customizer
// partial, allowing WordPress to expose its own edit shortcut.
'transport' => 'postMessage',
)
);
$control_args = array(
'label' => $field[1],
'section' => 'gustavoo_portfolio_' . $field[0],
'type' => in_array( $field[2], array( 'textarea', 'number', 'email', 'url' ), true ) ? $field[2] : 'text',
);
if ( 'number' === $field[2] ) {
$control_args['input_attrs'] = array( 'min' => 1, 'max' => 24 );
}
$wp_customize->add_control( $setting_id, $control_args );
}
if ( ! isset( $wp_customize->selective_refresh ) ) {
return;
}
$partials = array(
'hero' => array( '.hero-stage', 'template-parts/front/hero', array( 'hero_eyebrow', 'hero_title', 'hero_description', 'hero_primary_label', 'hero_primary_url', 'hero_secondary_label', 'hero_secondary_url' ) ),
'about' => array( '#sobre', 'template-parts/front/about', array( 'about_eyebrow', 'about_title', 'about_text', 'about_secondary_text' ) ),
'services' => array( '#servicos', 'template-parts/front/services', array( 'services_eyebrow', 'services_title', 'services_description' ) ),
'projects' => array( '#projetos', 'template-parts/front/projects', array( 'projects_eyebrow', 'projects_title', 'projects_text', 'projects_limit' ) ),
'blog' => array( '#blog', 'template-parts/front/posts', array( 'blog_eyebrow', 'blog_title', 'blog_text', 'blog_limit' ) ),
'contact' => array( '#contato', 'template-parts/front/contact', array( 'contact_eyebrow', 'contact_heading', 'contact_text', 'email', 'whatsapp', 'whatsapp_message', 'github_url', 'linkedin_url', 'instagram_url' ) ),
);
foreach ( $partials as $id => $partial ) {
$settings = array_map(
static function ( $key ) {
return 'gustavoo_portfolio_' . $key;
},
$partial[2]
);
/*
* A native edit shortcut is tied to the partial's primary setting.
* Using the first actual setting as the partial ID makes the pencil
* focus a real control instead of an unresolvable synthetic partial.
*/
$wp_customize->selective_refresh->add_partial(
$settings[0],
array(
'selector' => $partial[0],
'settings' => $settings,
'primary_setting' => $settings[0],
'container_inclusive' => true,
'render_callback' => static function () use ( $partial ) {
return gustavoo_portfolio_customize_render_part( $partial[1] );
},
)
);
}
$wp_customize->selective_refresh->add_partial(
'gustavoo_portfolio_whatsapp_shortcut',
array(
'selector' => '.whatsapp-float-wrap',
'settings' => array( 'gustavoo_portfolio_whatsapp', 'gustavoo_portfolio_whatsapp_message' ),
'primary_setting' => 'gustavoo_portfolio_whatsapp',
'container_inclusive' => true,
'render_callback' => static function () {
return gustavoo_portfolio_customize_render_part( 'template-parts/global/whatsapp-float' );
},
)
);
}
add_action( 'customize_register', 'gustavoo_portfolio_customize_register' );
/** Register native Customizer shortcuts for the theme's menu locations. */
function gustavoo_portfolio_customize_menu_shortcuts( $wp_customize ) {
if ( ! isset( $wp_customize->selective_refresh ) ) {
return;
}
$menus = array(
'primary' => '#site-navigation',
'news_categories' => '.news-category-nav',
);
foreach ( $menus as $location => $selector ) {
$setting = 'nav_menu_locations[' . $location . ']';
if ( ! $wp_customize->get_setting( $setting ) ) {
continue;
}
$wp_customize->selective_refresh->add_partial(
'gustavoo_portfolio_menu_shortcut_' . $location,
array(
'selector' => $selector,
'settings' => array( $setting ),
'primary_setting' => $setting,
)
);
}
}
add_action( 'customize_register', 'gustavoo_portfolio_customize_menu_shortcuts', 20 );