First Commit
This commit is contained in:
Executable
+794
@@ -0,0 +1,794 @@
|
||||
{% extends "layouts/dashboard.twig" %}
|
||||
|
||||
{% block title %}{{ page_title }} - {{ platformName }}{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<style>
|
||||
.serp-preview {
|
||||
max-width: 600px;
|
||||
padding: 15px;
|
||||
border: 1px solid #dfe1e5;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
font-family: arial, sans-serif;
|
||||
}
|
||||
.serp-url {
|
||||
color: #202124;
|
||||
font-size: 14px;
|
||||
margin-bottom: 4px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.serp-title {
|
||||
color: #1a0dab;
|
||||
font-size: 20px;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.serp-title:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.serp-description {
|
||||
color: #4d5156;
|
||||
font-size: 14px;
|
||||
line-height: 1.58;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.health-badge {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.3rem 0.6rem;
|
||||
}
|
||||
.btn-outline-purple {
|
||||
color: #6f42c1;
|
||||
border-color: #6f42c1;
|
||||
}
|
||||
.btn-outline-purple:hover {
|
||||
background-color: #6f42c1;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid px-4">
|
||||
<h1 class="mt-4">{{ page_title }}</h1>
|
||||
<ol class="breadcrumb mb-4">
|
||||
<li class="breadcrumb-item"><a href="{{ url('admin/dashboard') }}">{{ __('layout.dashboard') }}</a></li>
|
||||
<li class="breadcrumb-item active">{{ page_title }}</li>
|
||||
</ol>
|
||||
|
||||
{% include '@seo/admin/nav.twig' ignore missing %}
|
||||
|
||||
{% if flash_messages.success %}
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
{{ flash_messages.success }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-8">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<i class="bi bi-search me-1"></i>
|
||||
{{ __('seo.configuration') }}
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="button" id="btn-ai-generate" class="btn btn-outline-purple btn-sm">
|
||||
<i class="bi bi-cpu me-1"></i> {{ __('seo.ai_generate') }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" onclick="document.getElementById('seoSettingsForm').submit();">
|
||||
<i class="bi bi-save me-1"></i> {{ __('seo.save_settings') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="seoSettingsForm" action="{{ url('/admin/seo/save') }}" method="POST" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="{{ session('csrf_token') }}">
|
||||
<input type="hidden" name="_token" value="{{ session('_token') }}">
|
||||
|
||||
<ul class="nav nav-tabs mb-3" id="seoTabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="general-tab" data-bs-toggle="tab" data-bs-target="#general" type="button" role="tab">{{ __('seo.general') }}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="social-tab" data-bs-toggle="tab" data-bs-target="#social" type="button" role="tab">{{ __('seo.social_media') }}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="structured-tab" data-bs-toggle="tab" data-bs-target="#structured" type="button" role="tab">{{ __('seo.structured_data') }}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="google-tab" data-bs-toggle="tab" data-bs-target="#google" type="button" role="tab">{{ __('seo.google_tools') }}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="sitemap-tab" data-bs-toggle="tab" data-bs-target="#sitemap" type="button" role="tab">{{ __('seo.sitemap') }}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="redirects-tab" data-bs-toggle="tab" data-bs-target="#redirects" type="button" role="tab">{{ __('seo.redirects') }}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="robots-tab" data-bs-toggle="tab" data-bs-target="#robots" type="button" role="tab">{{ __('seo.robots_txt') }}</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="seoTabsContent">
|
||||
<!-- General Tab -->
|
||||
<div class="tab-pane fade show active" id="general" role="tabpanel">
|
||||
<div class="mb-3">
|
||||
<label for="meta_title" class="form-label fw-bold">{{ __('seo.meta_title') }}</label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="meta_title" name="meta_title" value="{{ settings.meta_title }}" onkeyup="updatePreview()">
|
||||
<span class="input-group-text" id="title-counter">0</span>
|
||||
</div>
|
||||
<div class="form-text">{{ __('seo.meta_title_help') }}</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="meta_description" class="form-label fw-bold">{{ __('seo.meta_description') }}</label>
|
||||
<div class="input-group">
|
||||
<textarea class="form-control" id="meta_description" name="meta_description" rows="3" onkeyup="updatePreview()">{{ settings.meta_description }}</textarea>
|
||||
<span class="input-group-text" id="desc-counter">0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="meta_keywords" class="form-label fw-bold">{{ __('seo.meta_keywords') }}</label>
|
||||
<input type="text" class="form-control" id="meta_keywords" name="meta_keywords" value="{{ settings.meta_keywords }}">
|
||||
<div class="form-text">{{ __('seo.meta_keywords_help') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<h6 class="fw-bold mb-3">{{ __('seo.serp_preview') }}</h6>
|
||||
<div class="serp-preview shadow-sm">
|
||||
<div class="serp-url">{{ url('/') }}</div>
|
||||
<div class="serp-title" id="preview-title">Título do Site</div>
|
||||
<div class="serp-description" id="preview-description">Descrição meta aparecerá aqui para visualização nos resultados de busca do Google.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Social Media Tab -->
|
||||
<div class="tab-pane fade" id="social" role="tabpanel">
|
||||
<h5 class="mt-3">{{ __('seo.og_section') }}</h5>
|
||||
<div class="mb-3">
|
||||
<label for="og_title" class="form-label">{{ __('seo.og_title') }}</label>
|
||||
<input type="text" class="form-control" id="og_title" name="og_title" value="{{ settings.og_title }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="og_description" class="form-label">{{ __('seo.og_description') }}</label>
|
||||
<textarea class="form-control" id="og_description" name="og_description" rows="2">{{ settings.og_description }}</textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label d-block">{{ __('seo.og_image') }}</label>
|
||||
{% if settings.og_image %}
|
||||
<div class="mb-2">
|
||||
<img src="/storage/uploads/seo/{{ settings.og_image }}" class="img-thumbnail" style="max-height: 150px;">
|
||||
<div class="small text-muted">{{ __('seo.og_image_current') }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<input type="file" class="form-control" name="og_image_file" accept="image/*">
|
||||
<div class="form-text">{{ __('seo.og_image_help') }}</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<h5 class="mt-3">{{ __('seo.twitter_section') }}</h5>
|
||||
<div class="mb-3">
|
||||
<label for="twitter_card" class="form-label">{{ __('seo.twitter_card_type') }}</label>
|
||||
<select class="form-select" id="twitter_card" name="twitter_card">
|
||||
<option value="summary" {{ settings.twitter_card == 'summary' ? 'selected' : '' }}>{{ __('seo.summary') }}</option>
|
||||
<option value="summary_large_image" {{ settings.twitter_card == 'summary_large_image' ? 'selected' : '' }}>{{ __('seo.summary_large_image') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Structured Data Tab -->
|
||||
<div class="tab-pane fade" id="structured" role="tabpanel">
|
||||
<h5 class="mt-3">{{ __('seo.structured_data') }} (JSON-LD)</h5>
|
||||
<div class="mb-3">
|
||||
<label for="json_ld_type" class="form-label">{{ __('seo.json_ld_type') }}</label>
|
||||
<select class="form-select" id="json_ld_type" name="json_ld_type" onchange="toggleJsonLdFields()">
|
||||
<option value="none" {{ settings.json_ld_type == 'none' ? 'selected' : '' }}>{{ __('seo.json_ld_none') }}</option>
|
||||
<option value="Organization" {{ settings.json_ld_type == 'Organization' ? 'selected' : '' }}>{{ __('seo.json_ld_organization') }}</option>
|
||||
<option value="LocalBusiness" {{ settings.json_ld_type == 'LocalBusiness' ? 'selected' : '' }}>{{ __('seo.json_ld_local_business') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="json-ld-fields" style="{{ settings.json_ld_type == 'none' or not settings.json_ld_type ? 'display: none;' : '' }}">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="json_ld_name" class="form-label">{{ __('seo.json_ld_name') }}</label>
|
||||
<input type="text" class="form-control" id="json_ld_name" name="json_ld_name" value="{{ settings.json_ld_name }}">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="json_ld_url" class="form-label">{{ __('seo.json_ld_url') }}</label>
|
||||
<input type="url" class="form-control" id="json_ld_url" name="json_ld_url" value="{{ settings.json_ld_url ?: url('/') }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="json_ld_description" class="form-label">{{ __('seo.json_ld_description') }}</label>
|
||||
<textarea class="form-control" id="json_ld_description" name="json_ld_description" rows="2">{{ settings.json_ld_description }}</textarea>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="json_ld_phone" class="form-label">{{ __('seo.json_ld_phone') }}</label>
|
||||
<input type="text" class="form-control" id="json_ld_phone" name="json_ld_phone" value="{{ settings.json_ld_phone }}">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="json_ld_email" class="form-label">{{ __('seo.json_ld_email') }}</label>
|
||||
<input type="email" class="form-control" id="json_ld_email" name="json_ld_email" value="{{ settings.json_ld_email }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="json_ld_address" class="form-label">{{ __('seo.json_ld_address') }}</label>
|
||||
<input type="text" class="form-control" id="json_ld_address" name="json_ld_address" value="{{ settings.json_ld_address }}">
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="json_ld_city" class="form-label">{{ __('seo.json_ld_city') }}</label>
|
||||
<input type="text" class="form-control" id="json_ld_city" name="json_ld_city" value="{{ settings.json_ld_city }}">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="json_ld_state" class="form-label">{{ __('seo.json_ld_state') }}</label>
|
||||
<input type="text" class="form-control" id="json_ld_state" name="json_ld_state" value="{{ settings.json_ld_state }}">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="json_ld_zip" class="form-label">{{ __('seo.json_ld_zip') }}</label>
|
||||
<input type="text" class="form-control" id="json_ld_zip" name="json_ld_zip" value="{{ settings.json_ld_zip }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="json_ld_social_links" class="form-label">{{ __('seo.json_ld_social_links') }}</label>
|
||||
<textarea class="form-control" id="json_ld_social_links" name="json_ld_social_links" rows="3" placeholder="https://facebook.com/yourpage https://twitter.com/yourprofile">{{ settings.json_ld_social_links }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Google Tools Tab -->
|
||||
<div class="tab-pane fade" id="google" role="tabpanel">
|
||||
<div class="mb-3 mt-3">
|
||||
<label for="google_analytics_id" class="form-label">{{ __('seo.google_analytics_id') }}</label>
|
||||
<input type="text" class="form-control" id="google_analytics_id" name="google_analytics_id" value="{{ settings.google_analytics_id }}" placeholder="G-XXXXXXXXXX">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="google_site_verification" class="form-label">{{ __('seo.google_site_verification') }}</label>
|
||||
<input type="text" class="form-control" id="google_site_verification" name="google_site_verification" value="{{ settings.google_site_verification }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sitemap Tab -->
|
||||
<div class="tab-pane fade" id="sitemap" role="tabpanel">
|
||||
<div class="alert alert-light border border-info mt-3">
|
||||
<i class="bi bi-info-circle text-info me-2"></i>
|
||||
Configure a visibilidade, frequência de atualização e prioridade para cada tipo de conteúdo do seu site.
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 40px;"></th>
|
||||
<th>Tipo de Conteúdo</th>
|
||||
<th style="width: 200px;">Frequência</th>
|
||||
<th style="width: 150px;">Prioridade (0.1 - 1.0)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{# Static Pages #}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="sitemap_include_static" value="1" {{ settings.sitemap_include_static|default('1') == '1' ? 'checked' : '' }}>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold">Páginas Estáticas</div>
|
||||
<div class="small text-muted">Home, Sobre, Contato, etc.</div>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm" name="sitemap_freq_static">
|
||||
{% set freqs = ['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never'] %}
|
||||
{% for freq in freqs %}
|
||||
<option value="{{ freq }}" {{ settings.sitemap_freq_static|default('weekly') == freq ? 'selected' : '' }}>{{ __('seo.' ~ freq) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm" name="sitemap_prio_static" value="{{ settings.sitemap_prio_static|default('1.0') }}" step="0.1" min="0.1" max="1.0">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{# Blog Posts #}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="sitemap_include_blog" value="1" {{ settings.sitemap_include_blog|default('1') == '1' ? 'checked' : '' }}>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold">Blog</div>
|
||||
<div class="small text-muted">Artigos e postagens individuais</div>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm" name="sitemap_freq_blog">
|
||||
{% for freq in freqs %}
|
||||
<option value="{{ freq }}" {{ settings.sitemap_freq_blog|default('daily') == freq ? 'selected' : '' }}>{{ __('seo.' ~ freq) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm" name="sitemap_prio_blog" value="{{ settings.sitemap_prio_blog|default('0.8') }}" step="0.1" min="0.1" max="1.0">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{# News #}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="sitemap_include_news" value="1" {{ settings.sitemap_include_news|default('1') == '1' ? 'checked' : '' }}>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold">Notícias</div>
|
||||
<div class="small text-muted">Últimas notícias e comunicados</div>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm" name="sitemap_freq_news">
|
||||
{% for freq in freqs %}
|
||||
<option value="{{ freq }}" {{ settings.sitemap_freq_news|default('daily') == freq ? 'selected' : '' }}>{{ __('seo.' ~ freq) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm" name="sitemap_prio_news" value="{{ settings.sitemap_prio_news|default('0.7') }}" step="0.1" min="0.1" max="1.0">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{# Commercial Guide #}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="sitemap_include_guide" value="1" {{ settings.sitemap_include_guide|default('1') == '1' ? 'checked' : '' }}>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold">Guia Comercial</div>
|
||||
<div class="small text-muted">Empresas e perfis comerciais</div>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm" name="sitemap_freq_guide">
|
||||
{% for freq in freqs %}
|
||||
<option value="{{ freq }}" {{ settings.sitemap_freq_guide|default('monthly') == freq ? 'selected' : '' }}>{{ __('seo.' ~ freq) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm" name="sitemap_prio_guide" value="{{ settings.sitemap_prio_guide|default('0.7') }}" step="0.1" min="0.1" max="1.0">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{# Events Guide #}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="sitemap_include_events" value="1" {{ settings.sitemap_include_events|default('1') == '1' ? 'checked' : '' }}>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold">Guia de Eventos</div>
|
||||
<div class="small text-muted">Eventos públicos e datas festivas</div>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm" name="sitemap_freq_events">
|
||||
{% for freq in freqs %}
|
||||
<option value="{{ freq }}" {{ settings.sitemap_freq_events|default('daily') == freq ? 'selected' : '' }}>{{ __('seo.' ~ freq) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm" name="sitemap_prio_events" value="{{ settings.sitemap_prio_events|default('0.7') }}" step="0.1" min="0.1" max="1.0">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{# FAQ #}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="sitemap_include_faq" value="1" {{ settings.sitemap_include_faq|default('1') == '1' ? 'checked' : '' }}>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold">FAQ</div>
|
||||
<div class="small text-muted">Perguntas frequentes</div>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm" name="sitemap_freq_faq">
|
||||
{% for freq in freqs %}
|
||||
<option value="{{ freq }}" {{ settings.sitemap_freq_faq|default('monthly') == freq ? 'selected' : '' }}>{{ __('seo.' ~ freq) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm" name="sitemap_prio_faq" value="{{ settings.sitemap_prio_faq|default('0.5') }}" step="0.1" min="0.1" max="1.0">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{# Expositor #}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="sitemap_include_expositor" value="1" {{ settings.sitemap_include_expositor|default('1') == '1' ? 'checked' : '' }}>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold">Expositor (Vitrine)</div>
|
||||
<div class="small text-muted">Produtos, serviços e categorias da vitrine</div>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm" name="sitemap_freq_expositor">
|
||||
{% for freq in freqs %}
|
||||
<option value="{{ freq }}" {{ settings.sitemap_freq_expositor|default('daily') == freq ? 'selected' : '' }}>{{ __('seo.' ~ freq) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm" name="sitemap_prio_expositor" value="{{ settings.sitemap_prio_expositor|default('0.8') }}" step="0.1" min="0.1" max="1.0">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{# Photo Albums #}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="sitemap_include_albums" value="1" {{ settings.sitemap_include_albums|default('1') == '1' ? 'checked' : '' }}>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold">Álbuns de Fotos</div>
|
||||
<div class="small text-muted">Galerias e álbuns de fotos públicos</div>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm" name="sitemap_freq_albums">
|
||||
{% for freq in freqs %}
|
||||
<option value="{{ freq }}" {{ settings.sitemap_freq_albums|default('monthly') == freq ? 'selected' : '' }}>{{ __('seo.' ~ freq) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm" name="sitemap_prio_albums" value="{{ settings.sitemap_prio_albums|default('0.6') }}" step="0.1" min="0.1" max="1.0">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{# Custom Pages #}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="sitemap_include_pages" value="1" {{ settings.sitemap_include_pages|default('1') == '1' ? 'checked' : '' }}>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold">Páginas Personalizadas</div>
|
||||
<div class="small text-muted">Páginas criadas via PageBuilder</div>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm" name="sitemap_freq_pages">
|
||||
{% for freq in freqs %}
|
||||
<option value="{{ freq }}" {{ settings.sitemap_freq_pages|default('monthly') == freq ? 'selected' : '' }}>{{ __('seo.' ~ freq) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm" name="sitemap_prio_pages" value="{{ settings.sitemap_prio_pages|default('0.7') }}" step="0.1" min="0.1" max="1.0">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{# Photo Essays #}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="sitemap_include_photoessays" value="1" {{ settings.sitemap_include_photoessays|default('1') == '1' ? 'checked' : '' }}>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold">Ensaios Fotográficos</div>
|
||||
<div class="small text-muted">Ensaios e galerias do PhotoEssay</div>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm" name="sitemap_freq_photoessays">
|
||||
{% for freq in freqs %}
|
||||
<option value="{{ freq }}" {{ settings.sitemap_freq_photoessays|default('monthly') == freq ? 'selected' : '' }}>{{ __('seo.' ~ freq) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm" name="sitemap_prio_photoessays" value="{{ settings.sitemap_prio_photoessays|default('0.6') }}" step="0.1" min="0.1" max="1.0">
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Redirects Tab (Handled separately) -->
|
||||
<div class="tab-pane fade" id="redirects" role="tabpanel">
|
||||
<div class="alert alert-warning mt-3">
|
||||
<i class="bi bi-exclamation-triangle"></i> Redirecionamentos são aplicados globalmente. Tenha cuidado ao configurar caminhos que já existem.
|
||||
</div>
|
||||
<div class="mb-3 d-flex justify-content-end">
|
||||
<button type="button" class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#addRedirectModal">
|
||||
<i class="bi bi-plus-lg"></i> {{ __('seo.add_redirect') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('seo.redirect_from') }}</th>
|
||||
<th>{{ __('seo.redirect_to') }}</th>
|
||||
<th>{{ __('seo.redirect_code') }}</th>
|
||||
<th>Ações</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for redirect in redirects %}
|
||||
<tr>
|
||||
<td><code>{{ redirect.redirects_from }}</code></td>
|
||||
<td><code>{{ redirect.redirects_to }}</code></td>
|
||||
<td><span class="badge bg-secondary">{{ redirect.redirects_code }}</span></td>
|
||||
<td>
|
||||
<a href="{{ url('admin/seo/redirect/delete/' ~ redirect.redirects_id) }}" class="text-danger" onclick="return confirm('Tem certeza?')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-center text-muted">{{ __('seo.no_redirects') }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Robots.txt Tab -->
|
||||
<div class="tab-pane fade" id="robots" role="tabpanel">
|
||||
<div class="alert alert-info mt-3">
|
||||
<i class="bi bi-info-circle"></i> {{ __('seo.robots_txt_help') }} <code>/robots.txt</code>.
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="robots_txt" class="form-label">{{ __('seo.robots_txt_content') }}</label>
|
||||
<textarea class="form-control font-monospace" id="robots_txt" name="robots_txt" rows="10">{{ settings.robots_txt }}</textarea>
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input" type="checkbox" value="1" id="update_robots_file" name="update_robots_file">
|
||||
<label class="form-check-label" for="update_robots_file">
|
||||
{{ __('seo.update_robots_file') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Botão removido daqui pois o superior no card-header é o que está funcionando #}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-4">
|
||||
<!-- SEO Health Card -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<i class="bi bi-heart-pulse me-1"></i>
|
||||
{{ __('seo.seo_health') }}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span>{{ __('seo.health_title_length') }}</span>
|
||||
<span id="health-title-badge" class="badge health-badge bg-secondary">...</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span>{{ __('seo.health_desc_length') }}</span>
|
||||
<span id="health-desc-badge" class="badge health-badge bg-secondary">...</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-0">
|
||||
<span>{{ __('seo.health_keywords_presence') }}</span>
|
||||
<span id="health-keywords-badge" class="badge health-badge bg-secondary">...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-light">
|
||||
<i class="bi bi-link-45deg me-1"></i>
|
||||
Links Gerados
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label class="small fw-bold text-muted d-block mb-1">Sitemap XML</label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control form-control-sm" value="{{ url('sitemap.xml') }}" readonly>
|
||||
<a href="{{ url('sitemap.xml') }}" target="_blank" class="btn btn-outline-secondary btn-sm"><i class="bi bi-box-arrow-up-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-0">
|
||||
<label class="small fw-bold text-muted d-block mb-1">Robots.txt</label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control form-control-sm" value="{{ url('robots.txt') }}" readonly>
|
||||
<a href="{{ url('robots.txt') }}" target="_blank" class="btn btn-outline-secondary btn-sm"><i class="bi bi-box-arrow-up-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-light">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
Dicas de SEO
|
||||
</div>
|
||||
<div class="card-body small">
|
||||
<ul class="ps-3 mb-0">
|
||||
<li class="mb-2"><strong>Título:</strong> Mantenha entre 50-60 caracteres.</li>
|
||||
<li class="mb-2"><strong>Descrição:</strong> Idealmente entre 150-160 caracteres.</li>
|
||||
<li class="mb-2"><strong>Schema.org:</strong> Ajuda o Google a entender quem você é.</li>
|
||||
<li><strong>Redirecionamentos:</strong> Evite erros 404 ao mudar URLs.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Redirect Modal -->
|
||||
<div class="modal fade" id="addRedirectModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form action="{{ url('admin/seo/redirect/add') }}" method="POST">
|
||||
{{ csrf_field()|raw }}
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ __('seo.add_redirect') }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label for="redirects_from" class="form-label">{{ __('seo.redirect_from') }}</label>
|
||||
<input type="text" class="form-control" id="redirects_from" name="redirects_from" placeholder="/pagina-antiga" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="redirects_to" class="form-label">{{ __('seo.redirect_to') }}</label>
|
||||
<input type="text" class="form-control" id="redirects_to" name="redirects_to" placeholder="/nova-pagina" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="redirects_code" class="form-label">{{ __('seo.redirect_code') }}</label>
|
||||
<select class="form-select" id="redirects_code" name="redirects_code">
|
||||
<option value="301">{{ __('seo.redirect_permanent') }}</option>
|
||||
<option value="302">{{ __('seo.redirect_temporary') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fechar</button>
|
||||
<button type="submit" class="btn btn-primary">Salvar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
function updatePreview() {
|
||||
const titleInput = document.getElementById('meta_title');
|
||||
const descInput = document.getElementById('meta_description');
|
||||
const keywordsInput = document.getElementById('meta_keywords');
|
||||
|
||||
const title = titleInput.value || 'Título do Site';
|
||||
const desc = descInput.value || 'Descrição meta aparecerá aqui para visualização nos resultados de busca do Google.';
|
||||
|
||||
document.getElementById('preview-title').innerText = title;
|
||||
document.getElementById('preview-description').innerText = desc;
|
||||
|
||||
// Counters
|
||||
const titleLen = titleInput.value.length;
|
||||
const descLen = descInput.value.length;
|
||||
|
||||
document.getElementById('title-counter').innerText = titleLen;
|
||||
document.getElementById('desc-counter').innerText = descLen;
|
||||
|
||||
// Health Check
|
||||
const titleBadge = document.getElementById('health-title-badge');
|
||||
if (titleLen === 0) {
|
||||
titleBadge.innerText = '{{ __('seo.health_error') }}';
|
||||
titleBadge.className = 'badge health-badge bg-danger';
|
||||
} else if (titleLen < 30 || titleLen > 65) {
|
||||
titleBadge.innerText = '{{ __('seo.health_warning') }}';
|
||||
titleBadge.className = 'badge health-badge bg-warning text-dark';
|
||||
} else {
|
||||
titleBadge.innerText = '{{ __('seo.health_good') }}';
|
||||
titleBadge.className = 'badge health-badge bg-success';
|
||||
}
|
||||
|
||||
const descBadge = document.getElementById('health-desc-badge');
|
||||
if (descLen === 0) {
|
||||
descBadge.innerText = '{{ __('seo.health_error') }}';
|
||||
descBadge.className = 'badge health-badge bg-danger';
|
||||
} else if (descLen < 120 || descLen > 165) {
|
||||
descBadge.innerText = '{{ __('seo.health_warning') }}';
|
||||
descBadge.className = 'badge health-badge bg-warning text-dark';
|
||||
} else {
|
||||
descBadge.innerText = '{{ __('seo.health_good') }}';
|
||||
descBadge.className = 'badge health-badge bg-success';
|
||||
}
|
||||
|
||||
const kwBadge = document.getElementById('health-keywords-badge');
|
||||
if (keywordsInput.value.trim() === '') {
|
||||
kwBadge.innerText = '{{ __('seo.health_warning') }}';
|
||||
kwBadge.className = 'badge health-badge bg-warning text-dark';
|
||||
} else {
|
||||
kwBadge.innerText = '{{ __('seo.health_good') }}';
|
||||
kwBadge.className = 'badge health-badge bg-success';
|
||||
}
|
||||
}
|
||||
|
||||
function toggleJsonLdFields() {
|
||||
const type = document.getElementById('json_ld_type').value;
|
||||
const fields = document.getElementById('json-ld-fields');
|
||||
fields.style.display = type === 'none' ? 'none' : 'block';
|
||||
}
|
||||
|
||||
// Check hash for active tab
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (window.location.hash) {
|
||||
const tabId = window.location.hash.substring(1) + '-tab';
|
||||
const tab = document.getElementById(tabId);
|
||||
if (tab) {
|
||||
const bsTab = new bootstrap.Tab(tab);
|
||||
bsTab.show();
|
||||
}
|
||||
}
|
||||
updatePreview();
|
||||
});
|
||||
|
||||
// AI Generate Logic
|
||||
document.getElementById('btn-ai-generate').addEventListener('click', function() {
|
||||
const btn = this;
|
||||
const originalHtml = btn.innerHTML;
|
||||
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span> {{ __('seo.ai_generating') }}';
|
||||
|
||||
fetch('{{ url('/admin/seo/ai-generate') }}')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
document.getElementById('meta_title').value = data.title;
|
||||
document.getElementById('meta_description').value = data.description;
|
||||
document.getElementById('meta_keywords').value = data.keywords;
|
||||
|
||||
// Robots.txt
|
||||
if (data.robots_txt) {
|
||||
document.getElementById('robots_txt').value = data.robots_txt;
|
||||
console.log('Robots.txt preenchido via IA');
|
||||
}
|
||||
|
||||
updatePreview();
|
||||
|
||||
// Alerta informativo
|
||||
const alertMsg = '{{ __('seo.ai_success') }}' + '\n\nAs tags Meta e o arquivo Robots.txt foram preenchidos com sugestões otimizadas.';
|
||||
alert(alertMsg);
|
||||
} else {
|
||||
alert('{{ __('seo.ai_error') }}');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('AI Error:', error);
|
||||
alert('{{ __('seo.ai_error') }}');
|
||||
})
|
||||
.finally(() => {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = originalHtml;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Executable
+82
@@ -0,0 +1,82 @@
|
||||
{% extends "layouts/dashboard.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid px-4">
|
||||
<h1 class="mt-4">{{ title }}</h1>
|
||||
<ol class="breadcrumb mb-4">
|
||||
<li class="breadcrumb-item"><a href="{{ url('admin/dashboard') }}">{{ __('dashboard.title') }}</a></li>
|
||||
<li class="breadcrumb-item active">SEO</li>
|
||||
</ol>
|
||||
|
||||
{% include '@seo/admin/nav.twig' ignore missing %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-3 d-none d-lg-block">
|
||||
<div class="list-group sticky-top" style="top: 100px; z-index: 1;">
|
||||
<a href="#visao-geral" class="list-group-item list-group-item-action">Visão Geral</a>
|
||||
<a href="#meta-tags" class="list-group-item list-group-item-action">Tags Meta</a>
|
||||
<a href="#redes-sociais" class="list-group-item list-group-item-action">Redes Sociais</a>
|
||||
<a href="#sitemap" class="list-group-item list-group-item-action">Sitemap XML</a>
|
||||
<a href="#redirecionamentos" class="list-group-item list-group-item-action">Redirecionamentos</a>
|
||||
<a href="#ia-seo" class="list-group-item list-group-item-action">IA de SEO</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-9">
|
||||
<!-- Visão Geral -->
|
||||
<div class="card shadow mb-4" id="visao-geral">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">1. Visão Geral</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>O módulo de <strong>SEO (Search Engine Optimization)</strong> centraliza as configurações que ajudam o seu site a ser encontrado e bem posicionado no Google e outros buscadores.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Meta Tags -->
|
||||
<div class="card shadow mb-4" id="meta-tags">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">2. Tags Meta (Geral)</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li><strong>Título Meta:</strong> O título que aparece no Google. Ideal entre 50-60 caracteres.</li>
|
||||
<li><strong>Descrição Meta:</strong> O resumo do site nos buscadores. Ideal até 160 caracteres.</li>
|
||||
<li><strong>Palavras-chave:</strong> Termos que descrevem seu negócio.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sitemap -->
|
||||
<div class="card shadow mb-4" id="sitemap">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">3. Sitemap XML</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>O Sitemap é o "mapa" do seu site para os buscadores. Aqui você define quais módulos (Blog, Notícias, Guia) devem ser indexados e qual a frequência de atualização de cada um.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Redirecionamentos -->
|
||||
<div class="card shadow mb-4" id="redirecionamentos">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">4. Redirecionamentos (301/302)</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Use esta ferramenta para redirecionar URLs antigas que não existem mais para novas páginas, evitando o erro 404 e mantendo a autoridade do link.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- IA de SEO -->
|
||||
<div class="card shadow mb-4" id="ia-seo">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">5. IA de SEO</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>O botão <strong>"Gerar com IA"</strong> analisa todo o conteúdo do seu site localmente e sugere automaticamente as melhores Tags Meta e a estrutura do arquivo Robots.txt.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
<div class="mb-4 d-print-none">
|
||||
<div class="btn-group" role="group" aria-label="Navegação SEO">
|
||||
<a href="/admin/seo" class="btn btn-outline-primary {% if request_path == '/admin/seo' %}active{% endif %}">
|
||||
<i class="bi bi-search"></i> {{ __('seo.menu_seo') }}
|
||||
</a>
|
||||
<a href="/admin/seo/manual" class="btn btn-outline-info {% if request_path == '/admin/seo/manual' %}active{% endif %}">
|
||||
<i class="bi bi-book"></i> Manual
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user