Automatic AI Posts, setup automatizado e seeder de permalinks/avatar
Plugin automatic-ai-posts (v2.0.0) - Pipeline completo: coleta de feeds RSS/Atom, filtro por IA, reescrita, categoria, imagem de capa e agendamento - Página de configuração com teste real do provedor de IA - Editor: botão para refazer imagem de capa e metadados, textos em PT-BR - Ajuda com botão Pix (copia-e-cola + QR) e sem nota de avaliação - Cache-busting por mtime nos assets do admin Tema gustavoo-portfolio - Marca do cabeçalho reduzida a "Gustavo" - Suporte a título próprio da marca Setup (docker/wp-init.sh, compose.yaml) - Plugins de terceiros (Post Views Counter, Rank Math, Site Kit) instalados do WordPress.org em vez de versionados - Falha explícita ao final se algum plugin obrigatório não instalar - WPCLI_UID/WPCLI_GID configuráveis Seeder do tema - Links permanentes "Dia e nome" e avatar "Iniciais" aplicados apenas em instalação nova, com regravação do .htaccess
This commit is contained in:
1 parent
5891467266
commit
0ea3651fb5
73 files changed
+8858
-39
No files matched your search
@@ -72,6 +72,7 @@ final class GSO_Seeder {
|
||||
* @return void
|
||||
*/
|
||||
public static function maybe_seed() {
|
||||
self::normalize_sidebar_widgets();
|
||||
self::seed_site_configuration();
|
||||
|
||||
$state = self::get_state();
|
||||
@@ -158,12 +159,103 @@ final class GSO_Seeder {
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $state['title'] ) ) {
|
||||
self::seed_site_title();
|
||||
$state = is_array( $state ) ? $state : array();
|
||||
$state['title'] = 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 );
|
||||
}
|
||||
|
||||
if ( empty( $state['permalinks'] ) ) {
|
||||
self::seed_permalinks();
|
||||
$state = is_array( $state ) ? $state : array();
|
||||
$state['permalinks'] = true;
|
||||
update_option( self::SITE_OPTION, $state, false );
|
||||
}
|
||||
|
||||
if ( empty( $state['avatars'] ) ) {
|
||||
self::seed_avatars();
|
||||
$state = is_array( $state ) ? $state : array();
|
||||
$state['avatars'] = true;
|
||||
update_option( self::SITE_OPTION, $state, false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the "Day and name" permalink structure.
|
||||
*
|
||||
* The post URL then reads /2026/11/02/post-slug/, which keeps dates
|
||||
* meaningful for a news-style blog. Only the stock "plain" structure is
|
||||
* replaced, so a structure chosen by the owner is respected.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function seed_permalinks() {
|
||||
if ( '' !== (string) get_option( 'permalink_structure' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_option( 'permalink_structure', '/%year%/%monthnum%/%day%/%postname%/' );
|
||||
|
||||
// Rebuild the rewrite rules and write the Apache block into .htaccess.
|
||||
// `hard = true` is required: without it the rules stay cached in the DB
|
||||
// and the web server never sees the new URLs (everything would 404).
|
||||
global $wp_rewrite;
|
||||
|
||||
if ( $wp_rewrite instanceof WP_Rewrite ) {
|
||||
$wp_rewrite->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' );
|
||||
$wp_rewrite->flush_rules( true );
|
||||
}
|
||||
|
||||
// flush_rules() only rewrites .htaccess when it can detect mod_rewrite,
|
||||
// which needs an HTTP request context. Force the block in otherwise.
|
||||
if ( function_exists( 'save_mod_rewrite_rules' ) ) {
|
||||
save_mod_rewrite_rules();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fall back to the "initials" avatar.
|
||||
*
|
||||
* Stand-in avatars avoid broken images and third-party requests on every
|
||||
* comment. Only the stock "mystery" default is replaced.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function seed_avatars() {
|
||||
if ( 'mystery' === (string) get_option( 'avatar_default' ) ) {
|
||||
update_option( 'avatar_default', 'initials' );
|
||||
}
|
||||
|
||||
// Gravatar images are remote; keep them enabled but never required.
|
||||
if ( '' === (string) get_option( 'show_avatars' ) ) {
|
||||
update_option( 'show_avatars', '1' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Name the site with the full professional title used on the home page.
|
||||
*
|
||||
* WordPress fills the browser title of the front page from `blogname`, so
|
||||
* this value is what search engines and tabs display. A name changed by the
|
||||
* site owner is respected: only the stock install value is replaced.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function seed_site_title() {
|
||||
$title = __( 'Gustavo Desenvolvedor Full Stack | Web, Mobile, Infraestrutura & Automação', 'gustavoo-portfolio-core' );
|
||||
$name = (string) get_option( 'blogname' );
|
||||
|
||||
if ( '' === $name || in_array( $name, array( 'Gustavo Portfolio', 'My Blog', 'Just another WordPress site', 'WordPress' ), true ) ) {
|
||||
update_option( 'blogname', $title );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,6 +312,15 @@ final class GSO_Seeder {
|
||||
* @return void
|
||||
*/
|
||||
private static function seed_theme_widgets() {
|
||||
/*
|
||||
* WordPress stores a snapshot of the widget layout in the `sidebars_widgets`
|
||||
* theme mod. Retrieve_widgets() reapplies that snapshot on every `init`
|
||||
* whenever it exists, which reverts this seeding and re-introduces blocks
|
||||
* that were moved to the inactive area. The option is the source of truth
|
||||
* here, so a stale snapshot is dropped before reading the layout.
|
||||
*/
|
||||
remove_theme_mod( 'sidebars_widgets' );
|
||||
|
||||
$sidebars = wp_get_sidebars_widgets();
|
||||
$sidebars = is_array( $sidebars ) ? $sidebars : array();
|
||||
|
||||
@@ -255,6 +356,55 @@ final class GSO_Seeder {
|
||||
}
|
||||
|
||||
update_option( 'sidebars_widgets', $sidebars, false );
|
||||
|
||||
// The option is authoritative from now on; discarding the stale theme
|
||||
// mod snapshot stops retrieve_widgets() from overriding it on `init`.
|
||||
remove_theme_mod( 'sidebars_widgets' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Repair widget areas that print the same widget more than once.
|
||||
*
|
||||
* Earlier versions persisted duplicate widget ids, so the same block was
|
||||
* rendered twice in the sidebar and footer. Runs on every boot and only
|
||||
* writes when a duplicate is actually found.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function normalize_sidebar_widgets() {
|
||||
/*
|
||||
* Read the raw option on purpose. wp_get_sidebars_widgets() merges the
|
||||
* layout through retrieve_widgets(), which already drops duplicate
|
||||
* ids from the array it returns. Relying on it would hide the
|
||||
* duplicated entries and the repair below would never run.
|
||||
*/
|
||||
$sidebars = get_option( 'sidebars_widgets' );
|
||||
|
||||
if ( ! is_array( $sidebars ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$changed = false;
|
||||
|
||||
foreach ( $sidebars as $sidebar_id => $widgets ) {
|
||||
if ( ! is_array( $widgets ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$unique = array_values( array_unique( $widgets ) );
|
||||
|
||||
if ( count( $unique ) !== count( $widgets ) ) {
|
||||
$sidebars[ $sidebar_id ] = $unique;
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $changed ) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_option( 'sidebars_widgets', $sidebars, false );
|
||||
remove_theme_mod( 'sidebars_widgets' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user