From f3eacd0d8de8d5760ccd697be7d620049b9be0d0 Mon Sep 17 00:00:00 2001 From: peptiderepo Date: Thu, 23 Apr 2026 02:42:48 +0000 Subject: [PATCH] style(phpcs): autofix WordPress-Core violations via phpcbf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run phpcbf --standard=WordPress-Core across includes/, prautoblogger.php, and uninstall.php. Fixed 1,362 formatting violations in 75 files: - Short array syntax: [] → array() - Line breaking for long function calls - Consistent indentation - Function call parameter alignment No logic changes; purely mechanical formatting. --- includes/admin/class-admin-notices.php | 10 +- includes/admin/class-admin-page.php | 142 +++++++++----- includes/admin/class-dashboard-widget.php | 8 +- includes/admin/class-ideas-browser.php | 108 +++++++---- includes/admin/class-image-model-registry.php | 46 ++--- includes/admin/class-log-viewer.php | 18 +- includes/admin/class-metrics-page.php | 2 +- includes/admin/class-post-list-columns.php | 16 +- includes/admin/class-post-metabox.php | 2 +- includes/admin/class-review-queue.php | 88 ++++++--- .../admin/class-settings-fields-extended.php | 114 +++++------ includes/admin/class-settings-fields.php | 144 +++++++------- includes/class-activator.php | 57 +++--- includes/class-ajax-handlers.php | 36 ++-- includes/class-autoloader.php | 6 +- includes/class-deactivator.php | 8 +- includes/class-executor.php | 107 ++++++---- includes/class-prautoblogger.php | 126 ++++++------ includes/core/class-analysis-prompts.php | 36 ++-- includes/core/class-article-worker.php | 19 +- includes/core/class-chief-editor.php | 58 +++--- includes/core/class-content-analyzer.php | 64 +++--- includes/core/class-content-generator.php | 110 ++++++++--- includes/core/class-content-prompts.php | 39 ++-- includes/core/class-cost-reporter.php | 16 +- includes/core/class-cost-tracker.php | 57 +++--- includes/core/class-ga4-client.php | 102 +++++----- includes/core/class-idea-scorer.php | 182 ++++++++++++++---- .../core/class-image-media-sideloader.php | 12 +- includes/core/class-image-nsfw-retry.php | 12 +- includes/core/class-image-pipeline.php | 41 ++-- includes/core/class-image-prompt-builder.php | 46 +++-- includes/core/class-logger.php | 42 ++-- includes/core/class-metrics-collector.php | 62 +++--- includes/core/class-peptide-linker.php | 42 ++-- includes/core/class-pipeline-runner.php | 58 ++++-- includes/core/class-post-assembler.php | 59 +++--- includes/core/class-publisher.php | 8 +- includes/core/class-research-reaper.php | 42 ++-- includes/core/class-semantic-dedup.php | 163 ++++++++++++---- includes/core/class-source-collector.php | 30 +-- .../frontend/class-article-typography.php | 132 +++++++------ includes/frontend/class-posts-widget.php | 50 ++--- includes/models/class-analysis-result.php | 6 +- includes/models/class-article-idea.php | 22 +-- includes/models/class-content-request.php | 2 +- includes/models/class-content-score.php | 31 +-- includes/models/class-editorial-review.php | 12 +- includes/models/class-generation-log.php | 43 +++-- includes/models/class-source-data.php | 4 +- .../providers/class-llm-research-provider.php | 76 ++++---- .../class-open-router-embedding-provider.php | 27 +-- .../class-open-router-image-batch.php | 92 ++++++--- .../class-open-router-image-pricing.php | 14 +- .../class-open-router-image-provider.php | 127 ++++++++---- .../class-open-router-image-support.php | 2 +- .../providers/class-open-router-pricing.php | 76 +++++--- .../providers/class-open-router-provider.php | 18 +- .../class-open-router-request-builder.php | 6 +- .../class-open-router-response-parser.php | 6 +- .../providers/class-open-router-validator.php | 26 +-- .../providers/class-reddit-availability.php | 32 +-- .../providers/class-reddit-json-client.php | 26 +-- includes/providers/class-reddit-provider.php | 86 +++++---- .../providers/class-reddit-rss-parser.php | 10 +- .../providers/class-runware-image-batch.php | 69 ++++--- .../providers/class-runware-image-pricing.php | 8 +- .../class-runware-image-provider.php | 86 +++++---- .../providers/class-runware-image-support.php | 13 +- .../providers/interface-image-provider.php | 4 +- includes/providers/interface-llm-provider.php | 2 +- .../class-open-router-model-normalizer.php | 62 ++++-- .../class-open-router-model-registry.php | 31 +-- prautoblogger.php | 13 +- uninstall.php | 8 +- 75 files changed, 2148 insertions(+), 1412 deletions(-) diff --git a/includes/admin/class-admin-notices.php b/includes/admin/class-admin-notices.php index 54cf98c..7c9c3cb 100755 --- a/includes/admin/class-admin-notices.php +++ b/includes/admin/class-admin-notices.php @@ -62,11 +62,13 @@ class PRAutoBlogger_Admin_Notices { } elseif ( $utilization >= 80.0 ) { printf( '

%s

', - esc_html( sprintf( + esc_html( + sprintf( /* translators: %s: budget utilization percentage */ - __( 'PRAutoBlogger: Monthly API budget is at %.0f%%. Consider increasing the budget or reducing daily article count.', 'prautoblogger' ), - $utilization - ) ) + __( 'PRAutoBlogger: Monthly API budget is at %.0f%%. Consider increasing the budget or reducing daily article count.', 'prautoblogger' ), + $utilization + ) + ) ); } } diff --git a/includes/admin/class-admin-page.php b/includes/admin/class-admin-page.php index e8cd9ac..33736c7 100755 --- a/includes/admin/class-admin-page.php +++ b/includes/admin/class-admin-page.php @@ -26,7 +26,7 @@ class PRAutoBlogger_Admin_Page { __( 'PRAutoBlogger', 'prautoblogger' ), 'manage_options', self::PAGE_SLUG, - [ $this, 'render_page' ], + array( $this, 'render_page' ), 'dashicons-edit-page', 30 ); @@ -43,54 +43,62 @@ class PRAutoBlogger_Admin_Page { foreach ( $fields as $field ) { $section = $field['section'] ?? 'prautoblogger_api'; - register_setting( self::OPTION_GROUP, $field['id'], [ - 'type' => $field['wp_type'] ?? 'string', - 'sanitize_callback' => [ $this, 'sanitize_field' ], - 'default' => $field['default'] ?? '', - ] ); - add_settings_field( $field['id'], $field['label'], [ $this, 'render_field' ], self::PAGE_SLUG, $section, $field ); + register_setting( + self::OPTION_GROUP, + $field['id'], + array( + 'type' => $field['wp_type'] ?? 'string', + 'sanitize_callback' => array( $this, 'sanitize_field' ), + 'default' => $field['default'] ?? '', + ) + ); + add_settings_field( $field['id'], $field['label'], array( $this, 'render_field' ), self::PAGE_SLUG, $section, $field ); } } /** Enqueue admin CSS and JS on all PRAutoBlogger admin pages. */ public function on_enqueue_assets( string $hook_suffix ): void { - $pages = [ + $pages = array( 'toplevel_page_' . self::PAGE_SLUG, 'prautoblogger_page_prautoblogger-metrics', 'prautoblogger_page_prautoblogger-review-queue', 'prautoblogger_page_prautoblogger-ideas', 'prautoblogger_page_prautoblogger-logs', - ]; + ); if ( ! in_array( $hook_suffix, $pages, true ) ) { return; } - wp_enqueue_style( 'prautoblogger-admin', PRAUTOBLOGGER_PLUGIN_URL . 'assets/css/admin.css', [], PRAUTOBLOGGER_VERSION ); - wp_enqueue_style( 'prautoblogger-model-picker', PRAUTOBLOGGER_PLUGIN_URL . 'assets/css/model-picker.css', [ 'prautoblogger-admin' ], PRAUTOBLOGGER_VERSION ); - wp_enqueue_script( 'prautoblogger-admin', PRAUTOBLOGGER_PLUGIN_URL . 'assets/js/admin.js', [ 'jquery' ], PRAUTOBLOGGER_VERSION, true ); - wp_enqueue_script( 'prautoblogger-model-picker', PRAUTOBLOGGER_PLUGIN_URL . 'assets/js/model-picker.js', [ 'jquery', 'prautoblogger-admin' ], PRAUTOBLOGGER_VERSION, true ); + wp_enqueue_style( 'prautoblogger-admin', PRAUTOBLOGGER_PLUGIN_URL . 'assets/css/admin.css', array(), PRAUTOBLOGGER_VERSION ); + wp_enqueue_style( 'prautoblogger-model-picker', PRAUTOBLOGGER_PLUGIN_URL . 'assets/css/model-picker.css', array( 'prautoblogger-admin' ), PRAUTOBLOGGER_VERSION ); + wp_enqueue_script( 'prautoblogger-admin', PRAUTOBLOGGER_PLUGIN_URL . 'assets/js/admin.js', array( 'jquery' ), PRAUTOBLOGGER_VERSION, true ); + wp_enqueue_script( 'prautoblogger-model-picker', PRAUTOBLOGGER_PLUGIN_URL . 'assets/js/model-picker.js', array( 'jquery', 'prautoblogger-admin' ), PRAUTOBLOGGER_VERSION, true ); - wp_localize_script( 'prautoblogger-admin', 'prautobloggerAdmin', [ - 'ajaxUrl' => admin_url( 'admin-ajax.php' ), - 'adminUrl' => admin_url(), - 'siteUrl' => home_url( '/' ), - 'generateNonce' => wp_create_nonce( 'prautoblogger_generate_now' ), - 'imageNonce' => wp_create_nonce( 'prautoblogger_generate_image' ), - 'testNonce' => wp_create_nonce( 'prautoblogger_test_connection' ), - 'modelsNonce' => wp_create_nonce( 'prautoblogger_get_models' ), - 'reviewNonce' => wp_create_nonce( 'prautoblogger_review_queue' ), - 'ideaGenNonce' => wp_create_nonce( 'prautoblogger_idea_gen' ), - 'generatingText' => __( 'Generating...', 'prautoblogger' ), - 'generateText' => __( 'Generate Now', 'prautoblogger' ), - 'testingText' => __( 'Testing...', 'prautoblogger' ), - 'testText' => __( 'Test Connections', 'prautoblogger' ), - // Image models for the picker — defined in the settings class to keep this file short. - 'imageModels' => PRAutoBlogger_Settings_Fields_Extended::get_image_models(), - ] ); + wp_localize_script( + 'prautoblogger-admin', + 'prautobloggerAdmin', + array( + 'ajaxUrl' => admin_url( 'admin-ajax.php' ), + 'adminUrl' => admin_url(), + 'siteUrl' => home_url( '/' ), + 'generateNonce' => wp_create_nonce( 'prautoblogger_generate_now' ), + 'imageNonce' => wp_create_nonce( 'prautoblogger_generate_image' ), + 'testNonce' => wp_create_nonce( 'prautoblogger_test_connection' ), + 'modelsNonce' => wp_create_nonce( 'prautoblogger_get_models' ), + 'reviewNonce' => wp_create_nonce( 'prautoblogger_review_queue' ), + 'ideaGenNonce' => wp_create_nonce( 'prautoblogger_idea_gen' ), + 'generatingText' => __( 'Generating...', 'prautoblogger' ), + 'generateText' => __( 'Generate Now', 'prautoblogger' ), + 'testingText' => __( 'Testing...', 'prautoblogger' ), + 'testText' => __( 'Test Connections', 'prautoblogger' ), + // Image models for the picker — defined in the settings class to keep this file short. + 'imageModels' => PRAutoBlogger_Settings_Fields_Extended::get_image_models(), + ) + ); // Ideas browser: generate-from-idea JS (only on the Ideas page). if ( 'prautoblogger_page_prautoblogger-ideas' === $hook_suffix ) { - wp_enqueue_script( 'prautoblogger-ideas-browser', PRAUTOBLOGGER_PLUGIN_URL . 'assets/js/ideas-browser.js', [ 'jquery', 'prautoblogger-admin' ], PRAUTOBLOGGER_VERSION, true ); + wp_enqueue_script( 'prautoblogger-ideas-browser', PRAUTOBLOGGER_PLUGIN_URL . 'assets/js/ideas-browser.js', array( 'jquery', 'prautoblogger-admin' ), PRAUTOBLOGGER_VERSION, true ); } } @@ -127,15 +135,22 @@ class PRAutoBlogger_Admin_Page { case 'url': case 'time': $attrs = ''; - if ( isset( $args['min'] ) ) { $attrs .= ' min="' . esc_attr( (string) $args['min'] ) . '"'; } - if ( isset( $args['max'] ) ) { $attrs .= ' max="' . esc_attr( (string) $args['max'] ) . '"'; } - if ( isset( $args['step'] ) ) { $attrs .= ' step="' . esc_attr( (string) $args['step'] ) . '"'; } + if ( isset( $args['min'] ) ) { + $attrs .= ' min="' . esc_attr( (string) $args['min'] ) . '"'; } + if ( isset( $args['max'] ) ) { + $attrs .= ' max="' . esc_attr( (string) $args['max'] ) . '"'; } + if ( isset( $args['step'] ) ) { + $attrs .= ' step="' . esc_attr( (string) $args['step'] ) . '"'; } printf( '', esc_attr( $type ), $id, $id, esc_attr( (string) $value ), $attrs ); break; case 'password': - printf( '', - $id, $id, '' !== $value ? esc_attr__( 'Saved (enter new value to change)', 'prautoblogger' ) : '' ); + printf( + '', + $id, + $id, + '' !== $value ? esc_attr__( 'Saved (enter new value to change)', 'prautoblogger' ) : '' + ); break; case 'textarea': @@ -144,30 +159,40 @@ class PRAutoBlogger_Admin_Page { case 'select': printf( ''; break; case 'toggle': - $checked = in_array( $value, [ '1', 'yes', true ], true ); - printf( '', - $id, $id, checked( $checked, true, false ) ); + $checked = in_array( $value, array( '1', 'yes', true ), true ); + printf( + '', + $id, + $id, + checked( $checked, true, false ) + ); break; case 'checkboxes': - $current = json_decode( (string) $value, true ) ?: []; + $current = json_decode( (string) $value, true ) ?: array(); // Hidden input ensures an empty value is POSTed when all boxes // are unchecked — without this, the browser omits the field // entirely, so WordPress never fires the sanitize callback and // the old value persists in wp_options. printf( '', $id ); - foreach ( ( $args['options'] ?? [] ) as $v => $label ) { + foreach ( ( $args['options'] ?? array() ) as $v => $label ) { $is_checked = in_array( $v, $current, true ); $disabled = strpos( $label, 'coming soon' ) !== false ? ' disabled' : ''; - printf( '', - $id, esc_attr( $v ), checked( $is_checked, true, false ), $disabled, esc_html( $label ) ); + printf( + '', + $id, + esc_attr( $v ), + checked( $is_checked, true, false ), + $disabled, + esc_html( $label ) + ); } break; @@ -180,11 +205,30 @@ class PRAutoBlogger_Admin_Page { break; case 'author_select': - wp_dropdown_users( [ 'name' => $id, 'id' => $id, 'selected' => absint( $value ), 'show_option_none' => __( '— Auto (first admin) —', 'prautoblogger' ), 'option_none_value' => '0', 'class' => 'ab-select' ] ); + wp_dropdown_users( + array( + 'name' => $id, + 'id' => $id, + 'selected' => absint( $value ), + 'show_option_none' => __( '— Auto (first admin) —', 'prautoblogger' ), + 'option_none_value' => '0', + 'class' => 'ab-select', + ) + ); break; case 'category_select': - wp_dropdown_categories( [ 'name' => $id, 'id' => $id, 'selected' => absint( $value ), 'show_option_none' => __( '— Auto-assign by type —', 'prautoblogger' ), 'option_none_value' => '0', 'class' => 'ab-select', 'hide_empty' => false ] ); + wp_dropdown_categories( + array( + 'name' => $id, + 'id' => $id, + 'selected' => absint( $value ), + 'show_option_none' => __( '— Auto-assign by type —', 'prautoblogger' ), + 'option_none_value' => '0', + 'class' => 'ab-select', + 'hide_empty' => false, + ) + ); break; } @@ -231,7 +275,7 @@ class PRAutoBlogger_Admin_Page { $option_name = substr( $filter, strlen( 'sanitize_option_' ) ); } - $encrypted = [ 'prautoblogger_openrouter_api_key', 'prautoblogger_ga4_credentials_json', 'prautoblogger_runware_api_key' ]; + $encrypted = array( 'prautoblogger_openrouter_api_key', 'prautoblogger_ga4_credentials_json', 'prautoblogger_runware_api_key' ); if ( in_array( $option_name, $encrypted, true ) ) { // Empty value means password field wasn't touched — keep existing. if ( '' === $value ) { @@ -251,7 +295,7 @@ class PRAutoBlogger_Admin_Page { return PRAutoBlogger_Encryption::encrypt( sanitize_text_field( $value ) ); } - $json_fields = [ 'prautoblogger_target_subreddits', 'prautoblogger_topic_exclusions', 'prautoblogger_enabled_sources' ]; + $json_fields = array( 'prautoblogger_target_subreddits', 'prautoblogger_topic_exclusions', 'prautoblogger_enabled_sources' ); if ( in_array( $option_name, $json_fields, true ) ) { // PHP array from checkboxes — sanitize each item and re-encode. if ( is_array( $value ) ) { @@ -275,7 +319,7 @@ class PRAutoBlogger_Admin_Page { return wp_json_encode( array_values( array_map( 'sanitize_text_field', $items ) ) ); } - $numeric = [ 'prautoblogger_daily_article_target', 'prautoblogger_monthly_budget_usd', 'prautoblogger_min_word_count', 'prautoblogger_max_word_count', 'prautoblogger_default_author', 'prautoblogger_default_category', 'prautoblogger_pullpush_cache_ttl', 'prautoblogger_reddit_posts_per_subreddit' ]; + $numeric = array( 'prautoblogger_daily_article_target', 'prautoblogger_monthly_budget_usd', 'prautoblogger_min_word_count', 'prautoblogger_max_word_count', 'prautoblogger_default_author', 'prautoblogger_default_category', 'prautoblogger_pullpush_cache_ttl', 'prautoblogger_reddit_posts_per_subreddit' ); if ( in_array( $option_name, $numeric, true ) ) { return is_numeric( $value ) ? $value : 0; } diff --git a/includes/admin/class-dashboard-widget.php b/includes/admin/class-dashboard-widget.php index 65346b2..2fb6de8 100755 --- a/includes/admin/class-dashboard-widget.php +++ b/includes/admin/class-dashboard-widget.php @@ -27,7 +27,7 @@ class PRAutoBlogger_Dashboard_Widget { wp_add_dashboard_widget( 'prautoblogger_status', __( 'PRAutoBlogger Status', 'prautoblogger' ), - [ $this, 'render_widget' ] + array( $this, 'render_widget' ) ); } @@ -44,7 +44,8 @@ class PRAutoBlogger_Dashboard_Widget { $next_run = wp_next_scheduled( 'prautoblogger_daily_generation' ); - printf( '

%s $%.2f / $%.2f (%.0f%%)

', + printf( + '

%s $%.2f / $%.2f (%.0f%%)

', esc_html__( 'Monthly Spend:', 'prautoblogger' ), $monthly_spend, $budget, @@ -52,7 +53,8 @@ class PRAutoBlogger_Dashboard_Widget { ); if ( false !== $next_run ) { - printf( '

%s %s

', + printf( + '

%s %s

', esc_html__( 'Next Generation:', 'prautoblogger' ), esc_html( wp_date( 'M j, Y g:i A', $next_run ) ) ); diff --git a/includes/admin/class-ideas-browser.php b/includes/admin/class-ideas-browser.php index 7f64510..385502c 100644 --- a/includes/admin/class-ideas-browser.php +++ b/includes/admin/class-ideas-browser.php @@ -28,7 +28,7 @@ class PRAutoBlogger_Ideas_Browser { __( 'Ideas', 'prautoblogger' ), 'manage_options', 'prautoblogger-ideas', - [ $this, 'render_page' ] + array( $this, 'render_page' ) ); } @@ -62,43 +62,51 @@ class PRAutoBlogger_Ideas_Browser { public function on_ajax_generate_from_idea(): void { check_ajax_referer( 'prautoblogger_idea_gen', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( [ 'message' => 'Insufficient permissions.' ], 403 ); + wp_send_json_error( array( 'message' => 'Insufficient permissions.' ), 403 ); return; } $idea_id = absint( $_POST['idea_id'] ?? 0 ); if ( $idea_id < 1 ) { - wp_send_json_error( [ 'message' => 'Invalid idea ID.' ] ); + wp_send_json_error( array( 'message' => 'Invalid idea ID.' ) ); return; } // Build Article_Idea from the analysis row. $idea_data = self::load_idea_data( $idea_id ); if ( null === $idea_data ) { - wp_send_json_error( [ 'message' => 'Idea not found.' ] ); + wp_send_json_error( array( 'message' => 'Idea not found.' ) ); return; } // Store idea for the cron handler and set initial "running" status. set_transient( self::STATUS_PREFIX . 'data_' . $idea_id, $idea_data, self::STATUS_TTL ); - set_transient( self::STATUS_PREFIX . $idea_id, [ - 'status' => 'running', - 'stage' => __( 'Starting generation…', 'prautoblogger' ), - 'started' => time(), - ], self::STATUS_TTL ); + set_transient( + self::STATUS_PREFIX . $idea_id, + array( + 'status' => 'running', + 'stage' => __( 'Starting generation…', 'prautoblogger' ), + 'started' => time(), + ), + self::STATUS_TTL + ); // Schedule background cron — passes idea_id as argument. $hook = 'prautoblogger_generate_from_idea'; - if ( ! wp_next_scheduled( $hook, [ $idea_id ] ) ) { - wp_schedule_single_event( time(), $hook, [ $idea_id ] ); + if ( ! wp_next_scheduled( $hook, array( $idea_id ) ) ) { + wp_schedule_single_event( time(), $hook, array( $idea_id ) ); } spawn_cron(); wp_remote_post( site_url( 'wp-cron.php?doing_wp_cron=' . sprintf( '%.22F', microtime( true ) ) ), - [ 'timeout' => 0.01, 'blocking' => false, 'sslverify' => false ] + array( + 'timeout' => 0.01, + 'blocking' => false, + 'sslverify' => false, + ) ); - wp_send_json_success( [ 'message' => 'Generation started.' ] ); + wp_send_json_success( array( 'message' => 'Generation started.' ) ); } /** @@ -109,14 +117,14 @@ class PRAutoBlogger_Ideas_Browser { public function on_ajax_idea_gen_status(): void { check_ajax_referer( 'prautoblogger_idea_gen', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( [ 'message' => 'Insufficient permissions.' ], 403 ); + wp_send_json_error( array( 'message' => 'Insufficient permissions.' ), 403 ); return; } $idea_id = absint( $_POST['idea_id'] ?? 0 ); $status = get_transient( self::STATUS_PREFIX . $idea_id ); if ( ! is_array( $status ) ) { - wp_send_json_success( [ 'status' => 'idle' ] ); + wp_send_json_success( array( 'status' => 'idle' ) ); return; } @@ -142,12 +150,26 @@ class PRAutoBlogger_Ideas_Browser { $key = self::STATUS_PREFIX . $idea_id; $idea_data = get_transient( self::STATUS_PREFIX . 'data_' . $idea_id ); if ( ! is_array( $idea_data ) ) { - set_transient( $key, [ 'status' => 'error', 'message' => 'Idea data expired.' ], self::STATUS_TTL ); + set_transient( + $key, + array( + 'status' => 'error', + 'message' => 'Idea data expired.', + ), + self::STATUS_TTL + ); return; } if ( ! PRAutoBlogger_Generation_Lock::acquire() ) { - set_transient( $key, [ 'status' => 'error', 'message' => 'Another generation is running.' ], self::STATUS_TTL ); + set_transient( + $key, + array( + 'status' => 'error', + 'message' => 'Another generation is running.', + ), + self::STATUS_TTL + ); return; } @@ -166,19 +188,30 @@ class PRAutoBlogger_Ideas_Browser { // Find the generated post ID for the "View" link. $post_id = self::find_post_by_run_id( $cost_tracker->get_run_id() ); - set_transient( $key, [ - 'status' => 'complete', - 'generated' => $result['generated'], - 'published' => $result['published'], - 'cost' => $result['cost'], - 'post_id' => $post_id, - ], self::STATUS_TTL ); + set_transient( + $key, + array( + 'status' => 'complete', + 'generated' => $result['generated'], + 'published' => $result['published'], + 'cost' => $result['cost'], + 'post_id' => $post_id, + ), + self::STATUS_TTL + ); } catch ( \Throwable $e ) { PRAutoBlogger_Logger::instance()->error( sprintf( 'Idea generation %s for #%d: %s', get_class( $e ), $idea_id, $e->getMessage() ), 'pipeline' ); - set_transient( $key, [ 'status' => 'error', 'message' => $e->getMessage() ], self::STATUS_TTL ); + set_transient( + $key, + array( + 'status' => 'error', + 'message' => $e->getMessage(), + ), + self::STATUS_TTL + ); } PRAutoBlogger_Generation_Lock::release(); @@ -231,26 +264,26 @@ class PRAutoBlogger_Ideas_Browser { return null; } - $meta = json_decode( $row['metadata_json'] ?? '{}', true ) ?: []; - return [ + $meta = json_decode( $row['metadata_json'] ?? '{}', true ) ?: array(); + return array( 'topic' => $row['topic'], 'article_type' => $row['analysis_type'], 'suggested_title' => $meta['suggested_title'] ?? $row['topic'], 'summary' => $row['summary'] ?? '', 'score' => (float) $row['relevance_score'], 'analysis_id' => (int) $row['id'], - 'source_ids' => json_decode( $row['source_ids_json'] ?? '[]', true ) ?: [], - 'key_points' => $meta['key_points'] ?? [], - 'target_keywords' => $meta['target_keywords'] ?? [], - ]; + 'source_ids' => json_decode( $row['source_ids_json'] ?? '[]', true ) ?: array(), + 'key_points' => $meta['key_points'] ?? array(), + 'target_keywords' => $meta['target_keywords'] ?? array(), + ); } /** Query analysis results with optional filtering and pagination. */ private function query_ideas( int $paged, string $type ): array { global $wpdb; $table = $wpdb->prefix . 'prautoblogger_analysis_results'; - $where = []; - $params = []; + $where = array(); + $params = array(); if ( '' !== $type ) { $where[] = 'analysis_type = %s'; @@ -276,7 +309,10 @@ class PRAutoBlogger_Ideas_Browser { ? $wpdb->get_results( $full_sql, ARRAY_A ) : $wpdb->get_results( $wpdb->prepare( $full_sql, ...$params ), ARRAY_A ); - return [ 'rows' => $rows ?: [], 'total' => $total ]; + return array( + 'rows' => $rows ?: array(), + 'total' => $total, + ); } /** Get counts per analysis_type for the filter badges. */ @@ -290,8 +326,8 @@ class PRAutoBlogger_Ideas_Browser { ARRAY_A ); - $counts = []; - foreach ( $rows ?: [] as $row ) { + $counts = array(); + foreach ( $rows ?: array() as $row ) { $counts[ $row['analysis_type'] ] = (int) $row['cnt']; } return $counts; diff --git a/includes/admin/class-image-model-registry.php b/includes/admin/class-image-model-registry.php index 1a38601..65959b3 100644 --- a/includes/admin/class-image-model-registry.php +++ b/includes/admin/class-image-model-registry.php @@ -33,64 +33,64 @@ class PRAutoBlogger_Image_Model_Registry { * @return array> */ public static function get_models(): array { - return [ - [ + return array( + array( 'id' => 'runware:100@1', 'name' => 'FLUX.1 schnell (Runware)', 'provider' => 'runware', 'cost_per_image' => 0.0006, - 'capabilities' => [ 'image_generation' ], + 'capabilities' => array( 'image_generation' ), 'description' => __( 'Default. Fast, very cheap, comic-friendly fidelity.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'runware:101@1', 'name' => 'FLUX.1 dev (Runware)', 'provider' => 'runware', 'cost_per_image' => 0.02, - 'capabilities' => [ 'image_generation' ], + 'capabilities' => array( 'image_generation' ), 'description' => __( 'Higher fidelity FLUX. ~30x schnell cost.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'google/gemini-2.5-flash-image', 'name' => 'Gemini 2.5 Flash Image (Nano Banana)', 'provider' => 'openrouter', 'cost_per_image' => 0.005, - 'capabilities' => [ 'image_generation' ], + 'capabilities' => array( 'image_generation' ), 'description' => __( 'Mid-tier quality, proven.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'google/gemini-3.1-flash-image-preview', 'name' => 'Gemini 3.1 Flash Image (Nano Banana 2)', 'provider' => 'openrouter', 'cost_per_image' => 0.008, - 'capabilities' => [ 'image_generation' ], + 'capabilities' => array( 'image_generation' ), 'description' => __( 'Latest Google. Better quality.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'google/gemini-3-pro-image-preview', 'name' => 'Gemini 3 Pro Image (Nano Banana Pro)', 'provider' => 'openrouter', 'cost_per_image' => 0.03, - 'capabilities' => [ 'image_generation' ], + 'capabilities' => array( 'image_generation' ), 'description' => __( 'Highest quality Google. Premium.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'openai/gpt-5-image-mini', 'name' => 'GPT-5 Image Mini', 'provider' => 'openrouter', 'cost_per_image' => 0.02, - 'capabilities' => [ 'image_generation' ], + 'capabilities' => array( 'image_generation' ), 'description' => __( 'OpenAI budget image model.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'openai/gpt-5-image', 'name' => 'GPT-5 Image', 'provider' => 'openrouter', 'cost_per_image' => 0.08, - 'capabilities' => [ 'image_generation' ], + 'capabilities' => array( 'image_generation' ), 'description' => __( 'OpenAI premium. Photorealistic.', 'prautoblogger' ), - ], - ]; + ), + ); } /** diff --git a/includes/admin/class-log-viewer.php b/includes/admin/class-log-viewer.php index ebf72f0..c654713 100755 --- a/includes/admin/class-log-viewer.php +++ b/includes/admin/class-log-viewer.php @@ -29,7 +29,7 @@ class PRAutoBlogger_Log_Viewer { __( 'Activity Log', 'prautoblogger' ), 'manage_options', 'prautoblogger-logs', - [ $this, 'render_page' ] + array( $this, 'render_page' ) ); } @@ -66,19 +66,21 @@ class PRAutoBlogger_Log_Viewer { check_ajax_referer( 'prautoblogger_clear_logs', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ], 403 ); + wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ), 403 ); return; } $days = isset( $_POST['days'] ) ? absint( $_POST['days'] ) : 30; $deleted = PRAutoBlogger_Logger::prune( $days ); - wp_send_json_success( [ - 'message' => sprintf( + wp_send_json_success( + array( + 'message' => sprintf( /* translators: %d: number of entries deleted */ - __( '%d log entries cleared.', 'prautoblogger' ), - $deleted - ), - ] ); + __( '%d log entries cleared.', 'prautoblogger' ), + $deleted + ), + ) + ); } } diff --git a/includes/admin/class-metrics-page.php b/includes/admin/class-metrics-page.php index 7e4b167..737cdcb 100755 --- a/includes/admin/class-metrics-page.php +++ b/includes/admin/class-metrics-page.php @@ -27,7 +27,7 @@ class PRAutoBlogger_Metrics_Page { __( 'Metrics & Costs', 'prautoblogger' ), 'manage_options', 'prautoblogger-metrics', - [ $this, 'render_page' ] + array( $this, 'render_page' ) ); } diff --git a/includes/admin/class-post-list-columns.php b/includes/admin/class-post-list-columns.php index d7fea31..9a3e731 100644 --- a/includes/admin/class-post-list-columns.php +++ b/includes/admin/class-post-list-columns.php @@ -23,11 +23,11 @@ class PRAutoBlogger_Post_List_Columns { * Side effects: adds WordPress filters/actions for post list customization. */ public function register(): void { - add_filter( 'manage_posts_columns', [ $this, 'filter_add_columns' ] ); - add_action( 'manage_posts_custom_column', [ $this, 'on_render_column' ], 10, 2 ); - add_filter( 'manage_edit-post_sortable_columns', [ $this, 'filter_sortable_columns' ] ); - add_action( 'pre_get_posts', [ $this, 'on_sort_by_model' ] ); - add_action( 'admin_head', [ $this, 'on_column_styles' ] ); + add_filter( 'manage_posts_columns', array( $this, 'filter_add_columns' ) ); + add_action( 'manage_posts_custom_column', array( $this, 'on_render_column' ), 10, 2 ); + add_filter( 'manage_edit-post_sortable_columns', array( $this, 'filter_sortable_columns' ) ); + add_action( 'pre_get_posts', array( $this, 'on_sort_by_model' ) ); + add_action( 'admin_head', array( $this, 'on_column_styles' ) ); } /** @@ -37,7 +37,7 @@ class PRAutoBlogger_Post_List_Columns { * @return array Modified columns. */ public function filter_add_columns( array $columns ): array { - $new = []; + $new = array(); foreach ( $columns as $key => $label ) { $new[ $key ] = $label; if ( 'title' === $key ) { @@ -192,7 +192,7 @@ class PRAutoBlogger_Post_List_Columns { return; } - $total = array_sum( array_column( $rows, 'estimated_cost' ) ); + $total = array_sum( array_column( $rows, 'estimated_cost' ) ); $formatted = $total < 0.01 ? sprintf( '$%.4f', $total ) : sprintf( '$%.2f', $total ); @@ -243,7 +243,7 @@ class PRAutoBlogger_Post_List_Columns { . '%s', esc_html( $total_f ) ); - $html .= ''; + $html .= ''; return $html; } diff --git a/includes/admin/class-post-metabox.php b/includes/admin/class-post-metabox.php index 80921fb..39ec893 100755 --- a/includes/admin/class-post-metabox.php +++ b/includes/admin/class-post-metabox.php @@ -34,7 +34,7 @@ class PRAutoBlogger_Post_Metabox { add_meta_box( 'prautoblogger_generation_info', __( 'PRAutoBlogger Generation Info', 'prautoblogger' ), - [ $this, 'render_metabox' ], + array( $this, 'render_metabox' ), 'post', 'side', 'default' diff --git a/includes/admin/class-review-queue.php b/includes/admin/class-review-queue.php index 0ccd144..833fce6 100755 --- a/includes/admin/class-review-queue.php +++ b/includes/admin/class-review-queue.php @@ -28,11 +28,11 @@ class PRAutoBlogger_Review_Queue { __( 'Review Queue', 'prautoblogger' ), 'manage_options', 'prautoblogger-review-queue', - [ $this, 'render_page' ] + array( $this, 'render_page' ) ); if ( false !== $hook ) { - add_action( "load-{$hook}", [ $this, 'on_handle_bulk_actions' ] ); + add_action( "load-{$hook}", array( $this, 'on_handle_bulk_actions' ) ); } } @@ -60,20 +60,22 @@ class PRAutoBlogger_Review_Queue { * @return \WP_Query */ public function get_pending_posts( int $paged = 1 ): \WP_Query { - return new \WP_Query( [ - 'post_type' => 'post', - 'post_status' => 'draft', - 'posts_per_page' => 20, - 'paged' => $paged, - 'meta_query' => [ - [ - 'key' => '_prautoblogger_generated', - 'value' => '1', - ], - ], - 'orderby' => 'date', - 'order' => 'DESC', - ] ); + return new \WP_Query( + array( + 'post_type' => 'post', + 'post_status' => 'draft', + 'posts_per_page' => 20, + 'paged' => $paged, + 'meta_query' => array( + array( + 'key' => '_prautoblogger_generated', + 'value' => '1', + ), + ), + 'orderby' => 'date', + 'order' => 'DESC', + ) + ); } /** @@ -100,7 +102,7 @@ class PRAutoBlogger_Review_Queue { $action = sanitize_text_field( wp_unslash( $_POST['prautoblogger_bulk_action'] ) ); $post_ids = isset( $_POST['prautoblogger_post_ids'] ) && is_array( $_POST['prautoblogger_post_ids'] ) ? array_map( 'absint', $_POST['prautoblogger_post_ids'] ) - : []; + : array(); if ( empty( $post_ids ) ) { return; @@ -113,25 +115,31 @@ class PRAutoBlogger_Review_Queue { } if ( 'approve' === $action ) { - $result = wp_update_post( [ 'ID' => $post_id, 'post_status' => 'publish' ], true ); + $result = wp_update_post( + array( + 'ID' => $post_id, + 'post_status' => 'publish', + ), + true + ); if ( ! is_wp_error( $result ) ) { update_post_meta( $post_id, '_prautoblogger_approved_at', gmdate( 'c' ) ); - $count++; + ++$count; } } elseif ( 'reject' === $action ) { $result = wp_trash_post( $post_id ); if ( false !== $result ) { - $count++; + ++$count; } } } $redirect = add_query_arg( - [ - 'page' => 'prautoblogger-review-queue', + array( + 'page' => 'prautoblogger-review-queue', 'prautoblogger_bulk_done' => $count, 'prautoblogger_bulk_type' => $action, - ], + ), admin_url( 'admin.php' ) ); @@ -150,25 +158,36 @@ class PRAutoBlogger_Review_Queue { check_ajax_referer( 'prautoblogger_review_queue', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ], 403 ); + wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ), 403 ); return; } $post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0; if ( $post_id <= 0 ) { - wp_send_json_error( [ 'message' => __( 'Invalid post ID.', 'prautoblogger' ) ] ); + wp_send_json_error( array( 'message' => __( 'Invalid post ID.', 'prautoblogger' ) ) ); return; } - $result = wp_update_post( [ 'ID' => $post_id, 'post_status' => 'publish' ], true ); + $result = wp_update_post( + array( + 'ID' => $post_id, + 'post_status' => 'publish', + ), + true + ); if ( is_wp_error( $result ) ) { - wp_send_json_error( [ 'message' => $result->get_error_message() ] ); + wp_send_json_error( array( 'message' => $result->get_error_message() ) ); return; } update_post_meta( $post_id, '_prautoblogger_approved_at', gmdate( 'c' ) ); - wp_send_json_success( [ 'message' => __( 'Post published.', 'prautoblogger' ), 'post_id' => $post_id ] ); + wp_send_json_success( + array( + 'message' => __( 'Post published.', 'prautoblogger' ), + 'post_id' => $post_id, + ) + ); } /** @@ -182,22 +201,27 @@ class PRAutoBlogger_Review_Queue { check_ajax_referer( 'prautoblogger_review_queue', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ], 403 ); + wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ), 403 ); return; } $post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0; if ( $post_id <= 0 ) { - wp_send_json_error( [ 'message' => __( 'Invalid post ID.', 'prautoblogger' ) ] ); + wp_send_json_error( array( 'message' => __( 'Invalid post ID.', 'prautoblogger' ) ) ); return; } $result = wp_trash_post( $post_id ); if ( false === $result || null === $result ) { - wp_send_json_error( [ 'message' => __( 'Failed to reject post.', 'prautoblogger' ) ] ); + wp_send_json_error( array( 'message' => __( 'Failed to reject post.', 'prautoblogger' ) ) ); return; } - wp_send_json_success( [ 'message' => __( 'Post rejected.', 'prautoblogger' ), 'post_id' => $post_id ] ); + wp_send_json_success( + array( + 'message' => __( 'Post rejected.', 'prautoblogger' ), + 'post_id' => $post_id, + ) + ); } } diff --git a/includes/admin/class-settings-fields-extended.php b/includes/admin/class-settings-fields-extended.php index 7093a2d..0e68051 100644 --- a/includes/admin/class-settings-fields-extended.php +++ b/includes/admin/class-settings-fields-extended.php @@ -33,9 +33,9 @@ class PRAutoBlogger_Settings_Fields_Extended { * @return array> */ public static function get_fields(): array { - return [ + return array( // ── Sources (extended) ────────────────────────────────────── - [ + array( 'id' => 'prautoblogger_research_model', 'label' => __( 'Research Model', 'prautoblogger' ), 'type' => 'model_select', @@ -44,43 +44,43 @@ class PRAutoBlogger_Settings_Fields_Extended { 'capability' => 'text→text', 'description' => __( 'Model for LLM Deep Research. Pick a reasoning-capable model (e.g. Grok 4.1 Fast, DeepSeek-R1) for best results. Only used when LLM Deep Research is enabled above.', 'prautoblogger' ), 'badge' => __( 'Reasoning', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_research_prompt', 'label' => __( 'Research Prompt', 'prautoblogger' ), 'type' => 'textarea', 'section' => 'prautoblogger_sources', 'default' => 'Conduct a deep research sweep of the {niche} space and identify the most substantive, actionable topics that practitioners and curious newcomers are searching for or actively discussing.' . "\n\n" . 'Focus on:' . "\n" . '- Practical questions real readers would search for (not theoretical debates)' . "\n" . '- Emerging trends gaining momentum in the community' . "\n" . '- Common misconceptions that deserve clarification' . "\n" . '- Comparative analysis (product vs. product, protocol vs. protocol)' . "\n" . '- Safety and efficacy topics that drive concern or curiosity' . "\n" . '- Beginner-to-advanced mix — cover entry-level and depth-focused topics' . "\n\n" . 'Aim for topics that feel timely, underserved by existing content, and likely to drive reader engagement. Return 8-12 findings with detailed analysis in each.', 'description' => __( 'The research brief sent to the LLM. Use {niche} as a placeholder for your niche description. The system prompt handles output format — this controls WHAT to research.', 'prautoblogger' ), - ], + ), // ── AI Models (extended) ──────────────────────────────────── - [ + array( 'id' => 'prautoblogger_reasoning_enabled', 'label' => __( 'Enable Reasoning', 'prautoblogger' ), 'type' => 'toggle', 'section' => 'prautoblogger_models', 'default' => '0', 'description' => __( 'Send reasoning instructions to models that support it (e.g. Grok, DeepSeek-R1). Reasoning tokens are billed as output tokens — expect higher costs per call. Models that don\'t support reasoning will ignore this.', 'prautoblogger' ), - ], - [ - 'id' => 'prautoblogger_reasoning_effort', - 'label' => __( 'Reasoning Effort', 'prautoblogger' ), - 'type' => 'select', - 'section' => 'prautoblogger_models', - 'default' => 'medium', - 'options' => [ + ), + array( + 'id' => 'prautoblogger_reasoning_effort', + 'label' => __( 'Reasoning Effort', 'prautoblogger' ), + 'type' => 'select', + 'section' => 'prautoblogger_models', + 'default' => 'medium', + 'options' => array( 'xhigh' => __( 'Extra High — maximum depth, highest cost', 'prautoblogger' ), 'high' => __( 'High — thorough reasoning', 'prautoblogger' ), 'medium' => __( 'Medium — balanced (recommended)', 'prautoblogger' ), 'low' => __( 'Low — light reasoning, lower cost', 'prautoblogger' ), 'minimal' => __( 'Minimal — barely any reasoning', 'prautoblogger' ), - ], + ), 'description' => __( 'How much effort the model spends reasoning before answering. Higher effort = more reasoning tokens = higher cost. Only applies when reasoning is enabled above.', 'prautoblogger' ), - ], + ), // ── Schedule & Budget ─────────────────────────────────────── - [ + array( 'id' => 'prautoblogger_daily_article_target', 'label' => __( 'Articles per Day', 'prautoblogger' ), 'type' => 'number', @@ -88,8 +88,8 @@ class PRAutoBlogger_Settings_Fields_Extended { 'default' => 1, 'min' => 1, 'max' => 10, - ], - [ + ), + array( 'id' => 'prautoblogger_schedule_time', 'label' => __( 'Generation Time', 'prautoblogger' ), 'type' => 'time', @@ -100,8 +100,8 @@ class PRAutoBlogger_Settings_Fields_Extended { esc_html__( "Daily generation runs at this time in your site's configured timezone (Settings → General → Timezone). Current site timezone: %s.", 'prautoblogger' ), esc_html( function_exists( 'wp_timezone_string' ) ? wp_timezone_string() : 'UTC' ) ), - ], - [ + ), + array( 'id' => 'prautoblogger_monthly_budget_usd', 'label' => __( 'Monthly Budget (USD)', 'prautoblogger' ), 'type' => 'number', @@ -110,66 +110,66 @@ class PRAutoBlogger_Settings_Fields_Extended { 'min' => 0, 'step' => '0.01', 'description' => __( 'Hard stop when reached. 0 = unlimited.', 'prautoblogger' ), - ], + ), // ── Publishing ────────────────────────────────────────────── - [ + array( 'id' => 'prautoblogger_auto_publish', 'label' => __( 'Auto-Publish', 'prautoblogger' ), 'type' => 'toggle', 'section' => 'prautoblogger_publishing', 'default' => '0', 'description' => __( 'Automatically publish editor-approved posts. When off, all posts go to the Review Queue as drafts.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_default_author', 'label' => __( 'Default Author', 'prautoblogger' ), 'type' => 'author_select', 'section' => 'prautoblogger_publishing', 'default' => 0, 'description' => __( 'WordPress user assigned as author of generated posts.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_default_category', 'label' => __( 'Default Category', 'prautoblogger' ), 'type' => 'category_select', 'section' => 'prautoblogger_publishing', 'default' => 0, 'description' => __( 'Fallback category for generated posts.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_log_level', 'label' => __( 'Log Level', 'prautoblogger' ), 'type' => 'select', 'section' => 'prautoblogger_publishing', 'default' => 'info', - 'options' => [ + 'options' => array( 'error' => __( 'Error — only failures', 'prautoblogger' ), 'warning' => __( 'Warning — errors + warnings', 'prautoblogger' ), 'info' => __( 'Info — key events (recommended)', 'prautoblogger' ), 'debug' => __( 'Debug — everything (verbose)', 'prautoblogger' ), - ], + ), 'description' => __( 'Controls detail level in the Activity Log.', 'prautoblogger' ), - ], + ), // ── Analytics ─────────────────────────────────────────────── - [ + array( 'id' => 'prautoblogger_ga4_property_id', 'label' => __( 'GA4 Property ID', 'prautoblogger' ), 'type' => 'text', 'section' => 'prautoblogger_analytics', 'description' => __( 'Your GA4 Property ID — digits only, e.g. 123456789 (the code adds the "properties/" prefix internally). Find it in GA4 → Admin → Property details. Leave blank to skip GA4.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_ga4_credentials_json', 'label' => __( 'Service Account JSON', 'prautoblogger' ), 'type' => 'password', 'section' => 'prautoblogger_analytics', 'description' => __( 'Paste the full JSON key file for a service account with Analytics read access.', 'prautoblogger' ), - ], + ), // ── Display ──────────────────────────────────────────────── - [ + array( 'id' => 'prautoblogger_article_font_family', 'label' => __( 'Article Font', 'prautoblogger' ), 'type' => 'select', @@ -177,8 +177,8 @@ class PRAutoBlogger_Settings_Fields_Extended { 'default' => 'default', 'options' => PRAutoBlogger_Article_Typography::get_font_choices(), 'description' => __( 'Font family used for generated article body text. Serif fonts improve long-form readability.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_article_font_size', 'label' => __( 'Article Font Size (px)', 'prautoblogger' ), 'type' => 'number', @@ -187,34 +187,34 @@ class PRAutoBlogger_Settings_Fields_Extended { 'min' => 0, 'max' => 32, 'description' => __( 'Base font size for article body text. 0 uses the theme default (13px). Recommended: 16–18px for comfortable reading.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_table_borders', 'label' => __( 'Table Borders', 'prautoblogger' ), 'type' => 'toggle', 'section' => 'prautoblogger_display', 'default' => '1', 'description' => __( 'Add visible borders, padding, and alternating row colors to tables in generated articles.', 'prautoblogger' ), - ], + ), // ── Images ───────────────────────────────────────────────── - [ + array( 'id' => 'prautoblogger_image_enabled', 'label' => __( 'Enable Image Generation', 'prautoblogger' ), 'type' => 'toggle', 'section' => 'prautoblogger_images', 'default' => '0', 'description' => __( 'Generate images for each published article.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_image_b_enabled', 'label' => __( 'Generate Second Image (B)', 'prautoblogger' ), 'type' => 'toggle', 'section' => 'prautoblogger_images', 'default' => '1', 'description' => __( 'Generate a second image from source data for A/B testing. Disabling saves one image generation + one LLM prompt rewrite per article.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_image_model', 'label' => __( 'Image Model', 'prautoblogger' ), 'type' => 'model_select', @@ -223,39 +223,39 @@ class PRAutoBlogger_Settings_Fields_Extended { 'capability' => 'image_generation', 'description' => __( 'Pick an image model. The provider (Runware or OpenRouter) is derived from the model registry on save, so mismatched pairs are no longer possible.', 'prautoblogger' ), 'badge' => __( 'Quality', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_runware_api_key', 'label' => __( 'Runware API Key', 'prautoblogger' ), 'type' => 'password', 'section' => 'prautoblogger_images', 'description' => __( 'Required when using a Runware FLUX model. Get your key at runware.ai/signup.', 'prautoblogger' ), 'icon' => '🔑', - ], - [ + ), + array( 'id' => 'prautoblogger_image_style_suffix', 'label' => __( 'Style Suffix', 'prautoblogger' ), 'type' => 'textarea', 'section' => 'prautoblogger_images', 'default' => PRAUTOBLOGGER_DEFAULT_IMAGE_STYLE_SUFFIX, 'description' => __( 'Appended to every image prompt. Controls visual look. Changing mid-run causes visible style drift.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_image_prompt_instructions', 'label' => __( 'Image Prompt Instructions', 'prautoblogger' ), 'type' => 'textarea', 'section' => 'prautoblogger_images', 'default' => PRAutoBlogger_Image_Prompt_Builder::REWRITER_SYSTEM_PROMPT, 'description' => __( 'System prompt given to the rewriter LLM that turns each article into a SCENE + CAPTION for the image generator. Changing this reshapes the look of all future images. Leave blank to use the default.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_image_nsfw_retry', 'label' => __( 'Retry NSFW-Blocked Images', 'prautoblogger' ), 'type' => 'toggle', 'section' => 'prautoblogger_images', 'default' => '1', 'description' => __( 'When the provider rejects an image prompt as NSFW, retry once with a generic fallback scene built from the article title. Disable to fail fast if the filter gets trigger-happy.', 'prautoblogger' ), - ], - ]; + ), + ); } } diff --git a/includes/admin/class-settings-fields.php b/includes/admin/class-settings-fields.php index 9f6ff3b..c1695c9 100755 --- a/includes/admin/class-settings-fields.php +++ b/includes/admin/class-settings-fields.php @@ -24,53 +24,53 @@ class PRAutoBlogger_Settings_Fields { * @return array */ public static function get_sections(): array { - return [ - 'prautoblogger_api' => [ + return array( + 'prautoblogger_api' => array( 'title' => __( 'API Keys', 'prautoblogger' ), 'icon' => 'dashicons-admin-network', 'description' => __( 'Connect your external services. Keys are encrypted at rest.', 'prautoblogger' ), - ], - 'prautoblogger_models' => [ + ), + 'prautoblogger_models' => array( 'title' => __( 'AI Models', 'prautoblogger' ), 'icon' => 'dashicons-superhero-alt', 'description' => __( 'Choose which models power each stage of the pipeline.', 'prautoblogger' ), - ], - 'prautoblogger_content' => [ + ), + 'prautoblogger_content' => array( 'title' => __( 'Content', 'prautoblogger' ), 'icon' => 'dashicons-edit-large', 'description' => __( 'Control tone, length, pipeline mode, and topic guardrails.', 'prautoblogger' ), - ], - 'prautoblogger_sources' => [ + ), + 'prautoblogger_sources' => array( 'title' => __( 'Sources', 'prautoblogger' ), 'icon' => 'dashicons-rss', 'description' => __( 'Configure where PRAutoBlogger finds trending topics.', 'prautoblogger' ), - ], - 'prautoblogger_schedule' => [ + ), + 'prautoblogger_schedule' => array( 'title' => __( 'Schedule & Budget', 'prautoblogger' ), 'icon' => 'dashicons-calendar-alt', 'description' => __( 'Set daily generation schedule, volume, and spending limits.', 'prautoblogger' ), - ], - 'prautoblogger_publishing' => [ + ), + 'prautoblogger_publishing' => array( 'title' => __( 'Publishing', 'prautoblogger' ), 'icon' => 'dashicons-megaphone', 'description' => __( 'Control how generated content is published.', 'prautoblogger' ), - ], - 'prautoblogger_analytics' => [ + ), + 'prautoblogger_analytics' => array( 'title' => __( 'Analytics', 'prautoblogger' ), 'icon' => 'dashicons-chart-area', 'description' => __( 'Connect Google Analytics 4 for post performance scoring.', 'prautoblogger' ), - ], - 'prautoblogger_display' => [ + ), + 'prautoblogger_display' => array( 'title' => __( 'Display', 'prautoblogger' ), 'icon' => 'dashicons-editor-textcolor', 'description' => __( 'Control how generated articles look on the frontend — fonts, sizes, and table styling.', 'prautoblogger' ), - ], - 'prautoblogger_images' => [ + ), + 'prautoblogger_images' => array( 'title' => __( 'Images', 'prautoblogger' ), 'icon' => 'dashicons-format-image', 'description' => __( 'Image provider, model, and style controls. OpenRouter reuses your existing API key.', 'prautoblogger' ), - ], - ]; + ), + ); } /** @@ -88,25 +88,25 @@ class PRAutoBlogger_Settings_Fields { * @return array> */ private static function get_core_fields(): array { - return [ + return array( // ── API Keys ──────────────────────────────────────────────── - [ + array( 'id' => 'prautoblogger_openrouter_api_key', 'label' => __( 'OpenRouter API Key', 'prautoblogger' ), 'type' => 'password', 'section' => 'prautoblogger_api', 'description' => __( 'Get your key at openrouter.ai/keys', 'prautoblogger' ), 'icon' => '🔑', - ], - [ + ), + array( 'id' => 'prautoblogger_reddit_source_status', 'label' => __( 'Reddit Data Source', 'prautoblogger' ), 'type' => 'source_status', 'section' => 'prautoblogger_api', 'description' => __( 'Uses Reddit RSS (primary) and .json (fallback). No API key required.', 'prautoblogger' ), 'icon' => '📡', - ], - [ + ), + array( 'id' => 'prautoblogger_ai_gateway_base_url', 'label' => __( 'Cloudflare AI Gateway URL', 'prautoblogger' ), 'type' => 'text', @@ -114,8 +114,8 @@ class PRAutoBlogger_Settings_Fields { 'default' => '', 'description' => __( 'Optional. Route OpenRouter calls through a Cloudflare AI Gateway for caching, cost logging, and rate limiting. Format: https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/openrouter — leave blank to call OpenRouter directly.', 'prautoblogger' ), 'icon' => '☁️', - ], - [ + ), + array( 'id' => 'prautoblogger_ai_gateway_cache_ttl', 'label' => __( 'AI Gateway Cache TTL (seconds)', 'prautoblogger' ), 'type' => 'number', @@ -124,10 +124,10 @@ class PRAutoBlogger_Settings_Fields { 'min' => 0, 'max' => 2592000, 'description' => __( 'How long Cloudflare may serve cached responses for identical LLM calls. 0 disables caching. Only used when a gateway URL is set above. Safe values: 0 for article generation (always fresh), 3600+ for repeated classification/scoring calls.', 'prautoblogger' ), - ], + ), // ── AI Models ─────────────────────────────────────────────── - [ + array( 'id' => 'prautoblogger_analysis_model', 'label' => __( 'Analysis Model', 'prautoblogger' ), 'type' => 'model_select', @@ -136,8 +136,8 @@ class PRAutoBlogger_Settings_Fields { 'capability' => 'text→text', 'description' => __( 'Used for source analysis. Pick a cheap, fast model.', 'prautoblogger' ), 'badge' => __( 'Low cost', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_writing_model', 'label' => __( 'Writing Model', 'prautoblogger' ), 'type' => 'model_select', @@ -146,8 +146,8 @@ class PRAutoBlogger_Settings_Fields { 'capability' => 'text→text', 'description' => __( 'Used for article generation. Quality matters here.', 'prautoblogger' ), 'badge' => __( 'Quality', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_editor_model', 'label' => __( 'Editor Model', 'prautoblogger' ), 'type' => 'model_select', @@ -156,110 +156,110 @@ class PRAutoBlogger_Settings_Fields { 'capability' => 'text→text', 'description' => __( 'Used for the chief editor review pass.', 'prautoblogger' ), 'badge' => __( 'Quality', 'prautoblogger' ), - ], + ), // ── Content ───────────────────────────────────────────────── - [ + array( 'id' => 'prautoblogger_niche_description', 'label' => __( 'Niche Description', 'prautoblogger' ), 'type' => 'textarea', 'section' => 'prautoblogger_content', 'description' => __( 'Describe your site\'s niche. Guides content analysis and generation.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_analysis_instructions', 'label' => __( 'Analysis Instructions', 'prautoblogger' ), 'type' => 'textarea', 'section' => 'prautoblogger_content', 'default' => '', 'description' => __( 'Custom instructions for the topic analysis LLM. Steers how source data is evaluated and which ideas get surfaced — e.g. "Prioritize questions over news. Ignore price-related discussions."', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_tone', 'label' => __( 'Content Tone', 'prautoblogger' ), 'type' => 'select', 'section' => 'prautoblogger_content', 'default' => 'informational', - 'options' => [ + 'options' => array( 'informational' => __( 'Informational', 'prautoblogger' ), 'conversational' => __( 'Conversational', 'prautoblogger' ), 'professional' => __( 'Professional', 'prautoblogger' ), 'casual' => __( 'Casual', 'prautoblogger' ), 'authoritative' => __( 'Authoritative', 'prautoblogger' ), - ], - ], - [ + ), + ), + array( 'id' => 'prautoblogger_writing_pipeline', 'label' => __( 'Writing Pipeline', 'prautoblogger' ), 'type' => 'select', 'section' => 'prautoblogger_content', 'default' => 'multi_step', - 'options' => [ + 'options' => array( 'multi_step' => __( 'Multi-step (outline → draft → polish)', 'prautoblogger' ), 'single_pass' => __( 'Single-pass (one LLM call)', 'prautoblogger' ), - ], - ], - [ + ), + ), + array( 'id' => 'prautoblogger_min_word_count', 'label' => __( 'Min Word Count', 'prautoblogger' ), 'type' => 'number', 'section' => 'prautoblogger_content', 'default' => 800, 'min' => 200, - ], - [ + ), + array( 'id' => 'prautoblogger_max_word_count', 'label' => __( 'Max Word Count', 'prautoblogger' ), 'type' => 'number', 'section' => 'prautoblogger_content', 'default' => 2000, 'min' => 500, - ], - [ + ), + array( 'id' => 'prautoblogger_writing_instructions', 'label' => __( 'Writing Instructions', 'prautoblogger' ), 'type' => 'textarea', 'section' => 'prautoblogger_content', 'default' => '', 'description' => __( 'Custom instructions appended to the LLM\'s system prompt when writing articles. Use this to steer style, structure, voice, and formatting — e.g. "Always open with a hook question. Use short paragraphs. Cite at least two studies."', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_editor_instructions', 'label' => __( 'Editor Instructions', 'prautoblogger' ), 'type' => 'textarea', 'section' => 'prautoblogger_content', 'default' => '', 'description' => __( 'Custom instructions for the chief editor LLM review pass. Steers what the editor looks for and how it revises — e.g. "Be strict about medical disclaimers. Reject any article under 800 words."', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_topic_exclusions', 'label' => __( 'Topic Exclusions', 'prautoblogger' ), 'type' => 'textarea', 'section' => 'prautoblogger_content', 'description' => __( 'Comma-separated topics to never write about.', 'prautoblogger' ), - ], + ), // ── Sources ───────────────────────────────────────────────── - [ + array( 'id' => 'prautoblogger_target_subreddits', 'label' => __( 'Target Subreddits', 'prautoblogger' ), 'type' => 'textarea', 'section' => 'prautoblogger_sources', 'description' => __( 'Comma-separated, without r/. E.g.: peptides, Nootropics, biohackers', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_enabled_sources', 'label' => __( 'Enabled Sources', 'prautoblogger' ), 'type' => 'checkboxes', 'section' => 'prautoblogger_sources', - 'options' => [ + 'options' => array( 'reddit' => __( 'Reddit (RSS + .json)', 'prautoblogger' ), 'llm_research' => __( 'LLM Deep Research (reasoning model)', 'prautoblogger' ), - ], + ), 'default' => '["reddit"]', 'description' => __( 'Select which platforms to monitor for topics.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_pullpush_cache_ttl', 'label' => __( 'Research Cache (hours)', 'prautoblogger' ), 'type' => 'number', @@ -268,21 +268,21 @@ class PRAutoBlogger_Settings_Fields { 'min' => 1, 'max' => 72, 'description' => __( 'How long to cache Reddit research results before re-fetching. Saves bandwidth on low-traffic sites.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_reddit_time_filter', 'label' => __( 'Reddit Time Window', 'prautoblogger' ), 'type' => 'select', 'section' => 'prautoblogger_sources', 'default' => 'day', - 'options' => [ + 'options' => array( 'day' => __( 'Past 24 hours', 'prautoblogger' ), 'week' => __( 'Past week', 'prautoblogger' ), 'month' => __( 'Past month', 'prautoblogger' ), - ], + ), 'description' => __( 'How far back to search for trending posts and comments.', 'prautoblogger' ), - ], - [ + ), + array( 'id' => 'prautoblogger_reddit_posts_per_subreddit', 'label' => __( 'Posts per Subreddit', 'prautoblogger' ), 'type' => 'number', @@ -291,7 +291,7 @@ class PRAutoBlogger_Settings_Fields { 'min' => 5, 'max' => 100, 'description' => __( 'Maximum posts to fetch per subreddit per collection run.', 'prautoblogger' ), - ], - ]; + ), + ); } } diff --git a/includes/class-activator.php b/includes/class-activator.php index 9594f82..2e06312 100755 --- a/includes/class-activator.php +++ b/includes/class-activator.php @@ -49,27 +49,27 @@ class PRAutoBlogger_Activator { * @return void */ private static function set_default_options(): void { - $defaults = [ + $defaults = array( 'prautoblogger_analysis_model' => PRAUTOBLOGGER_DEFAULT_ANALYSIS_MODEL, 'prautoblogger_writing_model' => PRAUTOBLOGGER_DEFAULT_WRITING_MODEL, 'prautoblogger_editor_model' => PRAUTOBLOGGER_DEFAULT_EDITOR_MODEL, - 'prautoblogger_daily_article_target' => 1, - 'prautoblogger_writing_pipeline' => 'multi_step', - 'prautoblogger_niche_description' => '', - 'prautoblogger_target_subreddits' => '[]', - 'prautoblogger_monthly_budget_usd' => 50.00, - 'prautoblogger_tone' => 'informational', - 'prautoblogger_min_word_count' => 800, - 'prautoblogger_max_word_count' => 2000, - 'prautoblogger_topic_exclusions' => '[]', - 'prautoblogger_enabled_sources' => '["reddit"]', - 'prautoblogger_article_font_family' => 'default', - 'prautoblogger_article_font_size' => 0, - 'prautoblogger_table_borders' => '1', - 'prautoblogger_schedule_time' => '03:00', - 'prautoblogger_log_level' => 'info', - 'prautoblogger_image_nsfw_retry' => '1', - ]; + 'prautoblogger_daily_article_target' => 1, + 'prautoblogger_writing_pipeline' => 'multi_step', + 'prautoblogger_niche_description' => '', + 'prautoblogger_target_subreddits' => '[]', + 'prautoblogger_monthly_budget_usd' => 50.00, + 'prautoblogger_tone' => 'informational', + 'prautoblogger_min_word_count' => 800, + 'prautoblogger_max_word_count' => 2000, + 'prautoblogger_topic_exclusions' => '[]', + 'prautoblogger_enabled_sources' => '["reddit"]', + 'prautoblogger_article_font_family' => 'default', + 'prautoblogger_article_font_size' => 0, + 'prautoblogger_table_borders' => '1', + 'prautoblogger_schedule_time' => '03:00', + 'prautoblogger_log_level' => 'info', + 'prautoblogger_image_nsfw_retry' => '1', + ); foreach ( $defaults as $key => $value ) { add_option( $key, $value ); @@ -101,13 +101,16 @@ class PRAutoBlogger_Activator { // in class-prautoblogger.php may not be hooked yet. $schedules = wp_get_schedules(); if ( ! isset( $schedules['prautoblogger_six_hours'] ) ) { - add_filter( 'cron_schedules', static function ( array $scheds ): array { - $scheds['prautoblogger_six_hours'] = [ - 'interval' => 6 * HOUR_IN_SECONDS, - 'display' => __( 'Every Six Hours', 'prautoblogger' ), - ]; - return $scheds; - } ); + add_filter( + 'cron_schedules', + static function ( array $scheds ): array { + $scheds['prautoblogger_six_hours'] = array( + 'interval' => 6 * HOUR_IN_SECONDS, + 'display' => __( 'Every Six Hours', 'prautoblogger' ), + ); + return $scheds; + } + ); } // Schedule a separate metrics collection job (runs every 6 hours). @@ -146,7 +149,7 @@ class PRAutoBlogger_Activator { $site_tz = function_exists( 'wp_timezone' ) ? wp_timezone() : new \DateTimeZone( 'UTC' ); - $local = ( new \DateTimeImmutable( 'tomorrow', $site_tz ) ) + $local = ( new \DateTimeImmutable( 'tomorrow', $site_tz ) ) ->setTime( $hour, $minute, 0 ); return (int) $local->getTimestamp(); } catch ( \Exception $e ) { @@ -256,7 +259,7 @@ class PRAutoBlogger_Activator { return; } $curr = (string) get_option( 'prautoblogger_image_model', '' ); - if ( in_array( $curr, [ '', 'google/gemini-2.5-flash-image' ], true ) ) { + if ( in_array( $curr, array( '', 'google/gemini-2.5-flash-image' ), true ) ) { update_option( 'prautoblogger_image_model', 'runware:100@1' ); } $final = (string) get_option( 'prautoblogger_image_model', 'runware:100@1' ); diff --git a/includes/class-ajax-handlers.php b/includes/class-ajax-handlers.php index c8e48a2..393466d 100644 --- a/includes/class-ajax-handlers.php +++ b/includes/class-ajax-handlers.php @@ -38,7 +38,7 @@ class PRAutoBlogger_Ajax_Handlers { check_ajax_referer( 'prautoblogger_generate_image', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ], 403 ); + wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ), 403 ); return; } @@ -48,29 +48,29 @@ class PRAutoBlogger_Ajax_Handlers { $post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0; if ( 0 === $post_id ) { - wp_send_json_error( [ 'message' => __( 'Missing post_id parameter.', 'prautoblogger' ) ] ); + wp_send_json_error( array( 'message' => __( 'Missing post_id parameter.', 'prautoblogger' ) ) ); return; } $post = get_post( $post_id ); if ( ! $post ) { - wp_send_json_error( [ 'message' => sprintf( __( 'Post %d not found.', 'prautoblogger' ), $post_id ) ] ); + wp_send_json_error( array( 'message' => sprintf( __( 'Post %d not found.', 'prautoblogger' ), $post_id ) ) ); return; } try { $pipeline = new PRAutoBlogger_Image_Pipeline(); - $article_data = [ + $article_data = array( 'post_title' => $post->post_title, 'post_content' => $post->post_content, - ]; + ); // Retrieve original source IDs from post meta so Image B can generate // a source-driven prompt even on retroactive regeneration. $source_ids_json = get_post_meta( $post_id, '_prautoblogger_source_ids', true ); - $source_ids = is_string( $source_ids_json ) ? json_decode( $source_ids_json, true ) : []; + $source_ids = is_string( $source_ids_json ) ? json_decode( $source_ids_json, true ) : array(); $source_data = ( new PRAutoBlogger_Source_Collector() )->get_source_data_for_image( - is_array( $source_ids ) ? array_map( 'absint', $source_ids ) : [] + is_array( $source_ids ) ? array_map( 'absint', $source_ids ) : array() ); // The pipeline sets featured image and Image B meta internally. @@ -82,7 +82,7 @@ class PRAutoBlogger_Ajax_Handlers { sprintf( 'Retroactive image gen %s for post %d: %s', get_class( $e ), $post_id, $e->getMessage() ), 'image_pipeline' ); - wp_send_json_error( [ 'message' => $e->getMessage() ] ); + wp_send_json_error( array( 'message' => $e->getMessage() ) ); } } @@ -98,7 +98,7 @@ class PRAutoBlogger_Ajax_Handlers { check_ajax_referer( 'prautoblogger_get_models', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ], 403 ); + wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ), 403 ); return; } @@ -123,22 +123,28 @@ class PRAutoBlogger_Ajax_Handlers { public function on_ajax_test_connection(): void { check_ajax_referer( 'prautoblogger_test_connection', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ], 403 ); + wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ), 403 ); return; } $service = isset( $_POST['service'] ) ? sanitize_text_field( wp_unslash( $_POST['service'] ) ) : ''; - $results = []; + $results = array(); if ( 'openrouter' === $service || 'all' === $service ) { $results['openrouter'] = ( new PRAutoBlogger_OpenRouter_Provider() )->validate_credentials_detailed(); } if ( 'reddit' === $service || 'all' === $service ) { - $reddit = new PRAutoBlogger_Reddit_Provider(); - $is_ok = $reddit->validate_credentials(); + $reddit = new PRAutoBlogger_Reddit_Provider(); + $is_ok = $reddit->validate_credentials(); $results['reddit'] = $is_ok - ? [ 'status' => 'ok', 'message' => __( 'Reddit source available (RSS primary, .json fallback).', 'prautoblogger' ) ] - : [ 'status' => 'error', 'message' => __( 'Reddit sources unreachable (both RSS and .json failed).', 'prautoblogger' ) ]; + ? array( + 'status' => 'ok', + 'message' => __( 'Reddit source available (RSS primary, .json fallback).', 'prautoblogger' ), + ) + : array( + 'status' => 'error', + 'message' => __( 'Reddit sources unreachable (both RSS and .json failed).', 'prautoblogger' ), + ); } wp_send_json_success( $results ); } diff --git a/includes/class-autoloader.php b/includes/class-autoloader.php index 471d363..4bca9f5 100755 --- a/includes/class-autoloader.php +++ b/includes/class-autoloader.php @@ -19,7 +19,7 @@ class PRAutoBlogger_Autoloader { * * @var string[] */ - private static array $directories = [ + private static array $directories = array( '', // includes/ root 'admin/', 'admin/fields/', @@ -28,7 +28,7 @@ class PRAutoBlogger_Autoloader { 'models/', 'frontend/', 'services/', - ]; + ); /** * Register the autoloader with SPL. @@ -36,7 +36,7 @@ class PRAutoBlogger_Autoloader { * @return void */ public static function register(): void { - spl_autoload_register( [ __CLASS__, 'autoload' ] ); + spl_autoload_register( array( __CLASS__, 'autoload' ) ); } /** diff --git a/includes/class-deactivator.php b/includes/class-deactivator.php index a1d9405..3ab8566 100755 --- a/includes/class-deactivator.php +++ b/includes/class-deactivator.php @@ -33,11 +33,11 @@ class PRAutoBlogger_Deactivator { * @return void */ private static function clear_cron(): void { - $hooks = [ + $hooks = array( 'prautoblogger_daily_generation', 'prautoblogger_collect_metrics', 'prautoblogger_reap_orphan_research_rows', - ]; + ); foreach ( $hooks as $hook ) { $timestamp = wp_next_scheduled( $hook ); @@ -55,11 +55,11 @@ class PRAutoBlogger_Deactivator { * @return void */ private static function clear_transients(): void { - $transients = [ + $transients = array( 'prautoblogger_reddit_token', 'prautoblogger_generation_lock', 'prautoblogger_openrouter_models', - ]; + ); foreach ( $transients as $transient ) { delete_transient( $transient ); diff --git a/includes/class-executor.php b/includes/class-executor.php index 01bfc16..7db7b29 100644 --- a/includes/class-executor.php +++ b/includes/class-executor.php @@ -83,7 +83,7 @@ class PRAutoBlogger_Executor { check_ajax_referer( 'prautoblogger_generate_now', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ], 403 ); + wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ), 403 ); return; } @@ -96,20 +96,26 @@ class PRAutoBlogger_Executor { // Check if a run is already in progress. $current = get_transient( self::STATUS_TRANSIENT ); if ( is_array( $current ) && 'running' === ( $current['status'] ?? '' ) ) { - wp_send_json_success( [ - 'background' => true, - 'message' => __( 'Generation already in progress.', 'prautoblogger' ), - ] ); + wp_send_json_success( + array( + 'background' => true, + 'message' => __( 'Generation already in progress.', 'prautoblogger' ), + ) + ); return; } // Write initial "running" status for the frontend to poll. - set_transient( self::STATUS_TRANSIENT, [ - 'status' => 'running', - 'stage' => __( 'Starting generation...', 'prautoblogger' ), - 'started' => time(), - 'last_updated' => time(), - ], self::STATUS_TTL ); + set_transient( + self::STATUS_TRANSIENT, + array( + 'status' => 'running', + 'stage' => __( 'Starting generation...', 'prautoblogger' ), + 'started' => time(), + 'last_updated' => time(), + ), + self::STATUS_TTL + ); // Schedule immediate one-shot cron event. WordPress will fire this // on the next page load (or via wp-cron.php) in a separate PHP process @@ -126,17 +132,19 @@ class PRAutoBlogger_Executor { // fires even if DISABLE_WP_CRON is true or spawn_cron() no-ops. wp_remote_post( site_url( 'wp-cron.php?doing_wp_cron=' . sprintf( '%.22F', microtime( true ) ) ), - [ + array( 'timeout' => 0.01, 'blocking' => false, 'sslverify' => false, - ] + ) ); - wp_send_json_success( [ - 'background' => true, - 'message' => __( 'Generation started in background. Polling for status...', 'prautoblogger' ), - ] ); + wp_send_json_success( + array( + 'background' => true, + 'message' => __( 'Generation started in background. Polling for status...', 'prautoblogger' ), + ) + ); } /** @@ -153,10 +161,14 @@ class PRAutoBlogger_Executor { @set_time_limit( 300 ); if ( ! PRAutoBlogger_Generation_Lock::acquire() ) { - set_transient( self::STATUS_TRANSIENT, [ - 'status' => 'error', - 'message' => __( 'Could not acquire generation lock. Another run may be in progress.', 'prautoblogger' ), - ], self::STATUS_TTL ); + set_transient( + self::STATUS_TRANSIENT, + array( + 'status' => 'error', + 'message' => __( 'Could not acquire generation lock. Another run may be in progress.', 'prautoblogger' ), + ), + self::STATUS_TTL + ); return; } @@ -169,13 +181,17 @@ class PRAutoBlogger_Executor { // If no articles were queued (target=1 or 0 ideas), finalize here. // When articles ARE queued, the pipeline handles status + lock release. if ( ! get_option( 'prautoblogger_article_queue' ) ) { - set_transient( self::STATUS_TRANSIENT, [ - 'status' => 'complete', - 'generated' => $results['generated'], - 'published' => $results['published'], - 'rejected' => $results['rejected'], - 'cost' => $results['cost'], - ], self::STATUS_TTL ); + set_transient( + self::STATUS_TRANSIENT, + array( + 'status' => 'complete', + 'generated' => $results['generated'], + 'published' => $results['published'], + 'rejected' => $results['rejected'], + 'cost' => $results['cost'], + ), + self::STATUS_TTL + ); PRAutoBlogger_Generation_Lock::release(); } } catch ( \Throwable $e ) { @@ -183,10 +199,14 @@ class PRAutoBlogger_Executor { sprintf( 'Manual generation %s: %s', get_class( $e ), $e->getMessage() ), 'pipeline' ); - set_transient( self::STATUS_TRANSIENT, [ - 'status' => 'error', - 'message' => $e->getMessage(), - ], self::STATUS_TTL ); + set_transient( + self::STATUS_TRANSIENT, + array( + 'status' => 'error', + 'message' => $e->getMessage(), + ), + self::STATUS_TTL + ); PRAutoBlogger_Generation_Lock::release(); } } @@ -208,10 +228,14 @@ class PRAutoBlogger_Executor { // Clean up on catastrophic failure. delete_option( 'prautoblogger_article_queue' ); PRAutoBlogger_Generation_Lock::release(); - set_transient( self::STATUS_TRANSIENT, [ - 'status' => 'error', - 'message' => $e->getMessage(), - ], self::STATUS_TTL ); + set_transient( + self::STATUS_TRANSIENT, + array( + 'status' => 'error', + 'message' => $e->getMessage(), + ), + self::STATUS_TTL + ); } } @@ -219,13 +243,13 @@ class PRAutoBlogger_Executor { public function on_ajax_generation_status(): void { check_ajax_referer( 'prautoblogger_generate_now', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ], 403 ); + wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ), 403 ); return; } $status = get_transient( self::STATUS_TRANSIENT ); if ( ! is_array( $status ) ) { - wp_send_json_success( [ 'status' => 'idle' ] ); + wp_send_json_success( array( 'status' => 'idle' ) ); return; } @@ -263,7 +287,12 @@ class PRAutoBlogger_Executor { delete_transient( self::STATUS_TRANSIENT ); delete_option( 'prautoblogger_article_queue' ); PRAutoBlogger_Generation_Lock::release(); - wp_send_json_success( [ 'status' => 'error', 'message' => $message ] ); + wp_send_json_success( + array( + 'status' => 'error', + 'message' => $message, + ) + ); } /** diff --git a/includes/class-prautoblogger.php b/includes/class-prautoblogger.php index db4289d..4edfc43 100644 --- a/includes/class-prautoblogger.php +++ b/includes/class-prautoblogger.php @@ -39,12 +39,12 @@ class PRAutoBlogger { if ( $this->initialized ) { return; } - $this->initialized = true; - $this->executor = new PRAutoBlogger_Executor(); + $this->initialized = true; + $this->executor = new PRAutoBlogger_Executor(); $this->ajax_handlers = new PRAutoBlogger_Ajax_Handlers( $this->executor->get_model_registry() ); - add_action( 'admin_init', [ $this, 'on_check_db_version' ] ); - add_filter( 'cron_schedules', [ $this, 'filter_add_cron_schedules' ] ); + add_action( 'admin_init', array( $this, 'on_check_db_version' ) ); + add_filter( 'cron_schedules', array( $this, 'filter_add_cron_schedules' ) ); if ( is_admin() ) { $this->register_admin_hooks(); @@ -61,101 +61,106 @@ class PRAutoBlogger { /** Register admin-only hooks (settings, notices, metabox, dashboard widget). */ private function register_admin_hooks(): void { $admin_page = new PRAutoBlogger_Admin_Page(); - add_action( 'admin_menu', [ $admin_page, 'on_register_menu' ] ); - add_action( 'admin_init', [ $admin_page, 'on_register_settings' ] ); - add_action( 'admin_enqueue_scripts', [ $admin_page, 'on_enqueue_assets' ] ); + add_action( 'admin_menu', array( $admin_page, 'on_register_menu' ) ); + add_action( 'admin_init', array( $admin_page, 'on_register_settings' ) ); + add_action( 'admin_enqueue_scripts', array( $admin_page, 'on_enqueue_assets' ) ); - add_action( 'admin_notices', [ new PRAutoBlogger_Admin_Notices(), 'on_display_notices' ] ); - add_action( 'add_meta_boxes', [ new PRAutoBlogger_Post_Metabox(), 'on_register_metabox' ] ); - add_action( 'admin_menu', [ new PRAutoBlogger_Metrics_Page(), 'on_register_menu' ] ); - add_action( 'wp_dashboard_setup', [ new PRAutoBlogger_Dashboard_Widget(), 'on_register_widget' ] ); + add_action( 'admin_notices', array( new PRAutoBlogger_Admin_Notices(), 'on_display_notices' ) ); + add_action( 'add_meta_boxes', array( new PRAutoBlogger_Post_Metabox(), 'on_register_metabox' ) ); + add_action( 'admin_menu', array( new PRAutoBlogger_Metrics_Page(), 'on_register_menu' ) ); + add_action( 'wp_dashboard_setup', array( new PRAutoBlogger_Dashboard_Widget(), 'on_register_widget' ) ); $review_queue = new PRAutoBlogger_Review_Queue(); - add_action( 'admin_menu', [ $review_queue, 'on_register_menu' ] ); + add_action( 'admin_menu', array( $review_queue, 'on_register_menu' ) ); $ideas_browser = new PRAutoBlogger_Ideas_Browser(); - add_action( 'admin_menu', [ $ideas_browser, 'on_register_menu' ] ); - add_action( 'admin_menu', [ new PRAutoBlogger_Log_Viewer(), 'on_register_menu' ] ); + add_action( 'admin_menu', array( $ideas_browser, 'on_register_menu' ) ); + add_action( 'admin_menu', array( new PRAutoBlogger_Log_Viewer(), 'on_register_menu' ) ); ( new PRAutoBlogger_Post_List_Columns() )->register(); // Block false update notifications — our slug collides with another plugin. - add_filter( 'site_transient_update_plugins', [ $this, 'filter_block_false_updates' ] ); + add_filter( 'site_transient_update_plugins', array( $this, 'filter_block_false_updates' ) ); } /** Register frontend hooks (shortcode, REST, typography). */ private function register_frontend_hooks(): void { $posts_widget = new PRAutoBlogger_Posts_Widget(); - add_action( 'init', [ $posts_widget, 'on_register_shortcode' ] ); - add_action( 'rest_api_init', [ $posts_widget, 'on_register_rest_route' ] ); + add_action( 'init', array( $posts_widget, 'on_register_shortcode' ) ); + add_action( 'rest_api_init', array( $posts_widget, 'on_register_rest_route' ) ); $typography = new PRAutoBlogger_Article_Typography(); - add_action( 'wp_head', [ $typography, 'on_wp_head' ] ); - add_action( 'wp_enqueue_scripts', [ $typography, 'on_enqueue_fonts' ] ); - add_filter( 'the_content', [ $typography, 'on_wrap_tables' ], 99 ); + add_action( 'wp_head', array( $typography, 'on_wp_head' ) ); + add_action( 'wp_enqueue_scripts', array( $typography, 'on_enqueue_fonts' ) ); + add_filter( 'the_content', array( $typography, 'on_wrap_tables' ), 99 ); } /** Register cron-triggered hooks for scheduled generation and metrics. */ private function register_cron_hooks(): void { - add_action( 'prautoblogger_daily_generation', [ $this->executor, 'on_daily_generation' ] ); - add_action( 'prautoblogger_collect_metrics', [ $this->executor, 'on_collect_metrics' ] ); + add_action( 'prautoblogger_daily_generation', array( $this->executor, 'on_daily_generation' ) ); + add_action( 'prautoblogger_collect_metrics', array( $this->executor, 'on_collect_metrics' ) ); // Manual "Generate Now" runs as a one-shot cron event to avoid // Hostinger's 120-second web-server connection timeout. - add_action( 'prautoblogger_manual_generation', [ $this->executor, 'on_manual_generation' ] ); + add_action( 'prautoblogger_manual_generation', array( $this->executor, 'on_manual_generation' ) ); // Chained article generation — each queued article fires as its own // cron event so it gets a fresh PHP process and execution time budget. add_action( PRAutoBlogger_Pipeline_Runner::CRON_ACTION, - [ $this->executor, 'on_process_article_queue' ] + array( $this->executor, 'on_process_article_queue' ) ); $registry = $this->executor->get_model_registry(); - add_action( 'prautoblogger_refresh_model_registry', [ $registry, 'refresh' ] ); + add_action( 'prautoblogger_refresh_model_registry', array( $registry, 'refresh' ) ); // Single-idea generation from the Ideas browser page. - add_action( 'prautoblogger_generate_from_idea', [ 'PRAutoBlogger_Ideas_Browser', 'on_cron_generate_from_idea' ] ); + add_action( 'prautoblogger_generate_from_idea', array( 'PRAutoBlogger_Ideas_Browser', 'on_cron_generate_from_idea' ) ); // v0.8.1: daily reaper for orphan `llm_research` rows (when a // pipeline dies before amortize_research_costs runs). - add_action( 'prautoblogger_reap_orphan_research_rows', [ 'PRAutoBlogger_Research_Reaper', 'on_cron' ] ); + add_action( 'prautoblogger_reap_orphan_research_rows', array( 'PRAutoBlogger_Research_Reaper', 'on_cron' ) ); // v0.8.1: WP-CLI manual trigger for the reaper. Only registers when // WP-CLI is present; no-op in normal HTTP requests. if ( defined( 'WP_CLI' ) && WP_CLI ) { - \WP_CLI::add_command( 'prautoblogger reap-research', static function (): void { - $stats = PRAutoBlogger_Research_Reaper::reap(); - \WP_CLI::success( sprintf( - 'Reaped %d, deleted %d (stale), skipped %d.', - (int) $stats['reaped'], - (int) $stats['deleted'], - (int) $stats['skipped'] - ) ); - } ); + \WP_CLI::add_command( + 'prautoblogger reap-research', + static function (): void { + $stats = PRAutoBlogger_Research_Reaper::reap(); + \WP_CLI::success( + sprintf( + 'Reaped %d, deleted %d (stale), skipped %d.', + (int) $stats['reaped'], + (int) $stats['deleted'], + (int) $stats['skipped'] + ) + ); + } + ); } } /** Register AJAX handlers for admin actions. */ private function register_ajax_hooks(): void { // Generation AJAX (start + status polling) stays on executor. - add_action( 'wp_ajax_prautoblogger_generate_now', [ $this->executor, 'on_ajax_generate_now' ] ); - add_action( 'wp_ajax_prautoblogger_generation_status', [ $this->executor, 'on_ajax_generation_status' ] ); + add_action( 'wp_ajax_prautoblogger_generate_now', array( $this->executor, 'on_ajax_generate_now' ) ); + add_action( 'wp_ajax_prautoblogger_generation_status', array( $this->executor, 'on_ajax_generation_status' ) ); // Non-generation AJAX (images, models, test) on dedicated handler. - add_action( 'wp_ajax_prautoblogger_generate_image', [ $this->ajax_handlers, 'on_ajax_generate_image' ] ); - add_action( 'wp_ajax_prautoblogger_test_connection', [ $this->ajax_handlers, 'on_ajax_test_connection' ] ); - add_action( 'wp_ajax_prautoblogger_get_models', [ $this->ajax_handlers, 'on_ajax_get_models' ] ); + add_action( 'wp_ajax_prautoblogger_generate_image', array( $this->ajax_handlers, 'on_ajax_generate_image' ) ); + add_action( 'wp_ajax_prautoblogger_test_connection', array( $this->ajax_handlers, 'on_ajax_test_connection' ) ); + add_action( 'wp_ajax_prautoblogger_get_models', array( $this->ajax_handlers, 'on_ajax_get_models' ) ); $review_queue = new PRAutoBlogger_Review_Queue(); - add_action( 'wp_ajax_prautoblogger_approve_post', [ $review_queue, 'on_ajax_approve_post' ] ); - add_action( 'wp_ajax_prautoblogger_reject_post', [ $review_queue, 'on_ajax_reject_post' ] ); + add_action( 'wp_ajax_prautoblogger_approve_post', array( $review_queue, 'on_ajax_approve_post' ) ); + add_action( 'wp_ajax_prautoblogger_reject_post', array( $review_queue, 'on_ajax_reject_post' ) ); - add_action( 'wp_ajax_prautoblogger_clear_logs', [ new PRAutoBlogger_Log_Viewer(), 'on_ajax_clear_logs' ] ); + add_action( 'wp_ajax_prautoblogger_clear_logs', array( new PRAutoBlogger_Log_Viewer(), 'on_ajax_clear_logs' ) ); $ideas = new PRAutoBlogger_Ideas_Browser(); - add_action( 'wp_ajax_prautoblogger_generate_from_idea', [ $ideas, 'on_ajax_generate_from_idea' ] ); - add_action( 'wp_ajax_prautoblogger_idea_gen_status', [ $ideas, 'on_ajax_idea_gen_status' ] ); + add_action( 'wp_ajax_prautoblogger_generate_from_idea', array( $ideas, 'on_ajax_generate_from_idea' ) ); + add_action( 'wp_ajax_prautoblogger_idea_gen_status', array( $ideas, 'on_ajax_idea_gen_status' ) ); } /** @@ -203,12 +208,12 @@ class PRAutoBlogger { // Replaces both the old infomercial pastiche and the short-lived premium // photography style. Force-update unless the user has a truly custom value. if ( ! get_option( 'prautoblogger_migrated_style_suffix_v3' ) ) { - $known_old_prefixes = [ + $known_old_prefixes = array( 'Style: a screengrab from a 1995', // v1: infomercial. 'Style: premium scientific lifestyle', // v2: photography. - ]; - $current = get_option( 'prautoblogger_image_style_suffix', '' ); - $is_old = ( '' === $current ); + ); + $current = get_option( 'prautoblogger_image_style_suffix', '' ); + $is_old = ( '' === $current ); foreach ( $known_old_prefixes as $prefix ) { if ( false !== strpos( $current, $prefix ) ) { $is_old = true; @@ -237,7 +242,7 @@ class PRAutoBlogger { // One-time migration: re-wrap existing encrypted values with "enc:" prefix. if ( ! get_option( 'prautoblogger_migrated_enc_prefix' ) ) { - $enc_options = [ 'prautoblogger_openrouter_api_key', 'prautoblogger_ga4_credentials_json', 'prautoblogger_runware_api_key' ]; + $enc_options = array( 'prautoblogger_openrouter_api_key', 'prautoblogger_ga4_credentials_json', 'prautoblogger_runware_api_key' ); foreach ( $enc_options as $opt ) { $val = get_option( $opt, '' ); if ( '' !== $val && ! PRAutoBlogger_Encryption::is_encrypted( $val ) ) { @@ -255,10 +260,10 @@ class PRAutoBlogger { * @return array */ public function filter_add_cron_schedules( array $schedules ): array { - $schedules['prautoblogger_six_hours'] = [ + $schedules['prautoblogger_six_hours'] = array( 'interval' => 6 * HOUR_IN_SECONDS, 'display' => __( 'Every Six Hours', 'prautoblogger' ), - ]; + ); return $schedules; } @@ -284,17 +289,22 @@ class PRAutoBlogger { // ── Backward-compatible proxies ── /** @see PRAutoBlogger_Executor::on_daily_generation() */ - public function on_daily_generation(): void { $this->executor->on_daily_generation(); } + public function on_daily_generation(): void { + $this->executor->on_daily_generation(); } /** @see PRAutoBlogger_Executor::on_collect_metrics() */ - public function on_collect_metrics(): void { $this->executor->on_collect_metrics(); } + public function on_collect_metrics(): void { + $this->executor->on_collect_metrics(); } /** @see PRAutoBlogger_Executor::on_ajax_generate_now() */ - public function on_ajax_generate_now(): void { $this->executor->on_ajax_generate_now(); } + public function on_ajax_generate_now(): void { + $this->executor->on_ajax_generate_now(); } /** @see PRAutoBlogger_Ajax_Handlers::on_ajax_test_connection() */ - public function on_ajax_test_connection(): void { $this->ajax_handlers->on_ajax_test_connection(); } + public function on_ajax_test_connection(): void { + $this->ajax_handlers->on_ajax_test_connection(); } /** @see PRAutoBlogger_Executor::get_model_registry() */ - public function get_model_registry(): PRAutoBlogger_OpenRouter_Model_Registry { return $this->executor->get_model_registry(); } + public function get_model_registry(): PRAutoBlogger_OpenRouter_Model_Registry { + return $this->executor->get_model_registry(); } } diff --git a/includes/core/class-analysis-prompts.php b/includes/core/class-analysis-prompts.php index 09a4613..b0cbda9 100644 --- a/includes/core/class-analysis-prompts.php +++ b/includes/core/class-analysis-prompts.php @@ -23,14 +23,14 @@ class PRAutoBlogger_Analysis_Prompts { * @return string System prompt text. */ public static function build_system_prompt( string $niche, string $performance_context, int $target_count = 6 ): string { - $prompt = "You are a content strategist analyzing social media discussions to find article ideas for a blog"; + $prompt = 'You are a content strategist analyzing social media discussions to find article ideas for a blog'; if ( '' !== $niche ) { $prompt .= " in the {$niche} niche"; } $prompt .= ".\n\n"; $prompt .= "IMPORTANT: You must identify exactly {$target_count} DISTINCT article ideas. "; - $prompt .= "Each idea must cover a substantially different topic — no two ideas should overlap "; + $prompt .= 'Each idea must cover a substantially different topic — no two ideas should overlap '; $prompt .= "in their main subject. Aim for diversity across these categories:\n"; $prompt .= "1. QUESTIONS: Recurring questions people ask (\"How do I...\", \"What is...\", \"Is it safe to...\")\n"; $prompt .= "2. COMPLAINTS: Pain points, frustrations, or problems people report\n"; @@ -39,7 +39,7 @@ class PRAutoBlogger_Analysis_Prompts { $prompt .= "5. GUIDES: How-to topics, best practices, or educational content people need\n\n"; $prompt .= "Spread your {$target_count} ideas across multiple categories. "; - $prompt .= "Be specific — \"peptide dosing for BPC-157\" is better than \"peptide information\". "; + $prompt .= 'Be specific — "peptide dosing for BPC-157" is better than "peptide information". '; $prompt .= "Each idea should be narrow enough to be a single focused blog post.\n\n"; $prompt .= "For each idea, provide:\n"; @@ -81,7 +81,7 @@ class PRAutoBlogger_Analysis_Prompts { * @return string User prompt text. */ public static function build_user_prompt( string $summary, int $target_count = 6 ): string { - return "Here are the recent social media posts and comments to analyze. " + return 'Here are the recent social media posts and comments to analyze. ' . "Find {$target_count} distinct, diverse article ideas from this data:\n\n" . $summary; } @@ -112,7 +112,7 @@ class PRAutoBlogger_Analysis_Prompts { return ''; } - $lines = [ 'Top performing past articles (learn from these):' ]; + $lines = array( 'Top performing past articles (learn from these):' ); foreach ( $top_posts as $post ) { $lines[] = sprintf( '- "%s" (score: %.1f)', @@ -136,27 +136,29 @@ class PRAutoBlogger_Analysis_Prompts { * @return string Formatted context block, or empty string if no recent articles. */ public static function get_recent_articles_context(): string { - $query = new \WP_Query( [ - 'post_type' => 'post', - 'post_status' => [ 'publish', 'draft', 'pending' ], - 'meta_key' => '_prautoblogger_generated', - 'meta_value' => '1', - 'date_query' => [ [ 'after' => '30 days ago' ] ], - 'posts_per_page' => 100, - 'fields' => 'ids', - 'no_found_rows' => true, - ] ); + $query = new \WP_Query( + array( + 'post_type' => 'post', + 'post_status' => array( 'publish', 'draft', 'pending' ), + 'meta_key' => '_prautoblogger_generated', + 'meta_value' => '1', + 'date_query' => array( array( 'after' => '30 days ago' ) ), + 'posts_per_page' => 100, + 'fields' => 'ids', + 'no_found_rows' => true, + ) + ); if ( empty( $query->posts ) ) { return ''; } - $titles = []; + $titles = array(); foreach ( $query->posts as $post_id ) { $titles[] = '- "' . get_the_title( $post_id ) . '"'; } - $block = "IMPORTANT — Topics already covered (last 30 days). Do NOT suggest topics that overlap with these. "; + $block = 'IMPORTANT — Topics already covered (last 30 days). Do NOT suggest topics that overlap with these. '; $block .= "Find genuinely NEW angles, questions, or subjects that are NOT already covered:\n"; $block .= implode( "\n", $titles ); diff --git a/includes/core/class-article-worker.php b/includes/core/class-article-worker.php index 40d6ca2..38ede9e 100644 --- a/includes/core/class-article-worker.php +++ b/includes/core/class-article-worker.php @@ -47,20 +47,20 @@ class PRAutoBlogger_Article_Worker { $auto_publish = in_array( get_option( 'prautoblogger_auto_publish', '0' ), - [ '1', 'yes' ], + array( '1', 'yes' ), true ); - $result = [ + $result = array( 'generated' => 0, 'published' => 0, 'rejected' => 0, 'cost' => 0.0, - ]; + ); try { $this->broadcast_stage( __( 'Generating article draft via AI…', 'prautoblogger' ) ); - $content = $generator->generate( $idea ); + $content = $generator->generate( $idea ); $result['generated'] = 1; $this->broadcast_stage( __( 'Running editorial pass…', 'prautoblogger' ) ); @@ -68,7 +68,12 @@ class PRAutoBlogger_Article_Worker { $this->broadcast_stage( __( 'Saving and publishing…', 'prautoblogger' ) ); $this->publish_or_draft( - $content, $idea, $review, $publisher, $auto_publish, $result + $content, + $idea, + $review, + $publisher, + $auto_publish, + $result ); } catch ( \Throwable $e ) { PRAutoBlogger_Logger::instance()->error( @@ -114,13 +119,13 @@ class PRAutoBlogger_Article_Worker { if ( $auto_publish ) { $publisher->publish( $final, $idea, $review, $run_id ); - $result['published']++; + ++$result['published']; } else { $publisher->save_as_draft( $final, $idea, $review, $run_id ); } } else { $publisher->save_as_draft( $content, $idea, $review, $run_id ); - $result['rejected']++; + ++$result['rejected']; PRAutoBlogger_Logger::instance()->info( 'Article rejected by editor: ' . $idea->get_topic(), 'pipeline' diff --git a/includes/core/class-chief-editor.php b/includes/core/class-chief-editor.php index 6c562a8..d647d66 100755 --- a/includes/core/class-chief-editor.php +++ b/includes/core/class-chief-editor.php @@ -51,16 +51,22 @@ class PRAutoBlogger_Chief_Editor { $user_prompt = $this->build_review_prompt( $content, $idea ); $response = $this->llm->send_chat_completion( - [ - [ 'role' => 'system', 'content' => $system_prompt ], - [ 'role' => 'user', 'content' => $user_prompt ], - ], + array( + array( + 'role' => 'system', + 'content' => $system_prompt, + ), + array( + 'role' => 'user', + 'content' => $user_prompt, + ), + ), $model, - [ + array( 'temperature' => 0.3, 'max_tokens' => 5000, - 'response_format' => [ 'type' => 'json_object' ], - ] + 'response_format' => array( 'type' => 'json_object' ), + ) ); $this->cost_tracker->log_api_call( @@ -81,7 +87,7 @@ class PRAutoBlogger_Chief_Editor { * @return string */ private function build_system_prompt( string $niche ): string { - $prompt = "You are a senior blog editor"; + $prompt = 'You are a senior blog editor'; if ( '' !== $niche ) { $prompt .= " specializing in {$niche} content"; } @@ -161,27 +167,31 @@ class PRAutoBlogger_Chief_Editor { . mb_substr( $content, 0, 500 ), 'editor' ); - return new PRAutoBlogger_Editorial_Review( [ - 'verdict' => 'rejected', - 'notes' => 'Editor response could not be parsed.', - 'quality_score' => 0.0, - 'seo_score' => 0.0, - 'issues' => [ 'Unparseable editor response' ], - ] ); + return new PRAutoBlogger_Editorial_Review( + array( + 'verdict' => 'rejected', + 'notes' => 'Editor response could not be parsed.', + 'quality_score' => 0.0, + 'seo_score' => 0.0, + 'issues' => array( 'Unparseable editor response' ), + ) + ); } $verdict = sanitize_text_field( $data['verdict'] ?? 'rejected' ); - if ( ! in_array( $verdict, [ 'approved', 'revised', 'rejected' ], true ) ) { + if ( ! in_array( $verdict, array( 'approved', 'revised', 'rejected' ), true ) ) { $verdict = 'rejected'; } - return new PRAutoBlogger_Editorial_Review( [ - 'verdict' => $verdict, - 'notes' => sanitize_textarea_field( $data['notes'] ?? '' ), - 'revised_content' => isset( $data['revised_content'] ) ? wp_kses_post( $data['revised_content'] ) : null, - 'quality_score' => (float) ( $data['quality_score'] ?? 0.0 ), - 'seo_score' => (float) ( $data['seo_score'] ?? 0.0 ), - 'issues' => array_map( 'sanitize_text_field', $data['issues'] ?? [] ), - ] ); + return new PRAutoBlogger_Editorial_Review( + array( + 'verdict' => $verdict, + 'notes' => sanitize_textarea_field( $data['notes'] ?? '' ), + 'revised_content' => isset( $data['revised_content'] ) ? wp_kses_post( $data['revised_content'] ) : null, + 'quality_score' => (float) ( $data['quality_score'] ?? 0.0 ), + 'seo_score' => (float) ( $data['seo_score'] ?? 0.0 ), + 'issues' => array_map( 'sanitize_text_field', $data['issues'] ?? array() ), + ) + ); } } diff --git a/includes/core/class-content-analyzer.php b/includes/core/class-content-analyzer.php index 877a48f..c8e8fc8 100755 --- a/includes/core/class-content-analyzer.php +++ b/includes/core/class-content-analyzer.php @@ -49,7 +49,7 @@ class PRAutoBlogger_Content_Analyzer { if ( empty( $source_items ) ) { PRAutoBlogger_Logger::instance()->info( 'No new source data to analyze.', 'analyzer' ); - return []; + return array(); } $niche = get_option( 'prautoblogger_niche_description', '' ); @@ -61,16 +61,22 @@ class PRAutoBlogger_Content_Analyzer { $user_prompt = PRAutoBlogger_Analysis_Prompts::build_user_prompt( $summary, $target_idea_count ); $response = $this->llm->send_chat_completion( - [ - [ 'role' => 'system', 'content' => $system_prompt ], - [ 'role' => 'user', 'content' => $user_prompt ], - ], + array( + array( + 'role' => 'system', + 'content' => $system_prompt, + ), + array( + 'role' => 'user', + 'content' => $user_prompt, + ), + ), $model, - [ + array( 'temperature' => 0.5, 'max_tokens' => 8000, - 'response_format' => [ 'type' => 'json_object' ], - ] + 'response_format' => array( 'type' => 'json_object' ), + ) ); $this->cost_tracker->log_api_call( @@ -130,7 +136,7 @@ class PRAutoBlogger_Content_Analyzer { gmdate( 'Y-m-d H:i:s', time() - DAY_IN_SECONDS ) ), ARRAY_A - ) ?: []; + ) ?: array(); } /** @@ -142,8 +148,8 @@ class PRAutoBlogger_Content_Analyzer { * @return string Formatted text summary. */ private function build_source_summary( array $items ): string { - $parts = []; - $char_limit = 30000; // Roughly ~7500 tokens. + $parts = array(); + $char_limit = 30000; // Roughly ~7500 tokens. $current_chars = 0; foreach ( $items as $item ) { @@ -163,7 +169,7 @@ class PRAutoBlogger_Content_Analyzer { break; } - $parts[] = $entry; + $parts[] = $entry; $current_chars += strlen( $entry ); } @@ -185,27 +191,29 @@ class PRAutoBlogger_Content_Analyzer { . mb_substr( $content, 0, 500 ), 'analyzer' ); - return []; + return array(); } $source_ids = array_column( $source_items, 'id' ); - $results = []; + $results = array(); foreach ( $data['patterns'] as $pattern ) { - $results[] = new PRAutoBlogger_Analysis_Result( [ - 'analysis_type' => sanitize_text_field( $pattern['type'] ?? 'question' ), - 'topic' => sanitize_text_field( $pattern['topic'] ?? '' ), - 'summary' => sanitize_textarea_field( $pattern['summary'] ?? '' ), - 'frequency' => absint( $pattern['frequency'] ?? 1 ), - 'relevance_score' => (float) ( $pattern['relevance_score'] ?? 0.0 ), - 'source_ids' => $source_ids, - 'analyzed_at' => current_time( 'mysql' ), - 'metadata' => [ - 'suggested_title' => $pattern['suggested_title'] ?? '', - 'key_points' => $pattern['key_points'] ?? [], - 'target_keywords' => $pattern['target_keywords'] ?? [], - ], - ] ); + $results[] = new PRAutoBlogger_Analysis_Result( + array( + 'analysis_type' => sanitize_text_field( $pattern['type'] ?? 'question' ), + 'topic' => sanitize_text_field( $pattern['topic'] ?? '' ), + 'summary' => sanitize_textarea_field( $pattern['summary'] ?? '' ), + 'frequency' => absint( $pattern['frequency'] ?? 1 ), + 'relevance_score' => (float) ( $pattern['relevance_score'] ?? 0.0 ), + 'source_ids' => $source_ids, + 'analyzed_at' => current_time( 'mysql' ), + 'metadata' => array( + 'suggested_title' => $pattern['suggested_title'] ?? '', + 'key_points' => $pattern['key_points'] ?? array(), + 'target_keywords' => $pattern['target_keywords'] ?? array(), + ), + ) + ); } return $results; diff --git a/includes/core/class-content-generator.php b/includes/core/class-content-generator.php index b2b4164..cbb04c5 100755 --- a/includes/core/class-content-generator.php +++ b/includes/core/class-content-generator.php @@ -49,7 +49,7 @@ class PRAutoBlogger_Content_Generator { absint( get_option( 'prautoblogger_min_word_count', 800 ) ), absint( get_option( 'prautoblogger_max_word_count', 2000 ) ), get_option( 'prautoblogger_niche_description', '' ), - json_decode( get_option( 'prautoblogger_topic_exclusions', '[]' ), true ) ?: [], + json_decode( get_option( 'prautoblogger_topic_exclusions', '[]' ), true ) ?: array(), get_option( 'prautoblogger_writing_instructions', '' ) ); @@ -70,17 +70,30 @@ class PRAutoBlogger_Content_Generator { $model = get_option( 'prautoblogger_writing_model', PRAUTOBLOGGER_DEFAULT_WRITING_MODEL ); $response = $this->llm->send_chat_completion( - [ - [ 'role' => 'system', 'content' => PRAutoBlogger_Content_Prompts::build_system( $request ) ], - [ 'role' => 'user', 'content' => PRAutoBlogger_Content_Prompts::build_single_pass( $request ) ], - ], + array( + array( + 'role' => 'system', + 'content' => PRAutoBlogger_Content_Prompts::build_system( $request ), + ), + array( + 'role' => 'user', + 'content' => PRAutoBlogger_Content_Prompts::build_single_pass( $request ), + ), + ), $model, - [ 'temperature' => 0.7, 'max_tokens' => 4000 ] + array( + 'temperature' => 0.7, + 'max_tokens' => 4000, + ) ); $this->cost_tracker->log_api_call( - null, 'draft', $this->llm->get_provider_name(), - $response['model'], $response['prompt_tokens'], $response['completion_tokens'] + null, + 'draft', + $this->llm->get_provider_name(), + $response['model'], + $response['prompt_tokens'], + $response['completion_tokens'] ); return $response['content']; @@ -102,17 +115,30 @@ class PRAutoBlogger_Content_Generator { $system = PRAutoBlogger_Content_Prompts::build_system( $request ); $response = $this->llm->send_chat_completion( - [ - [ 'role' => 'system', 'content' => $system ], - [ 'role' => 'user', 'content' => PRAutoBlogger_Content_Prompts::build_outline( $request ) ], - ], + array( + array( + 'role' => 'system', + 'content' => $system, + ), + array( + 'role' => 'user', + 'content' => PRAutoBlogger_Content_Prompts::build_outline( $request ), + ), + ), $model, - [ 'temperature' => 0.5, 'max_tokens' => 1500 ] + array( + 'temperature' => 0.5, + 'max_tokens' => 1500, + ) ); $this->cost_tracker->log_api_call( - null, 'outline', $this->llm->get_provider_name(), - $response['model'], $response['prompt_tokens'], $response['completion_tokens'] + null, + 'outline', + $this->llm->get_provider_name(), + $response['model'], + $response['prompt_tokens'], + $response['completion_tokens'] ); return $response['content']; @@ -123,17 +149,30 @@ class PRAutoBlogger_Content_Generator { $system = PRAutoBlogger_Content_Prompts::build_system( $request ); $response = $this->llm->send_chat_completion( - [ - [ 'role' => 'system', 'content' => $system ], - [ 'role' => 'user', 'content' => PRAutoBlogger_Content_Prompts::build_draft( $request, $outline ) ], - ], + array( + array( + 'role' => 'system', + 'content' => $system, + ), + array( + 'role' => 'user', + 'content' => PRAutoBlogger_Content_Prompts::build_draft( $request, $outline ), + ), + ), $model, - [ 'temperature' => 0.7, 'max_tokens' => 4000 ] + array( + 'temperature' => 0.7, + 'max_tokens' => 4000, + ) ); $this->cost_tracker->log_api_call( - null, 'draft', $this->llm->get_provider_name(), - $response['model'], $response['prompt_tokens'], $response['completion_tokens'] + null, + 'draft', + $this->llm->get_provider_name(), + $response['model'], + $response['prompt_tokens'], + $response['completion_tokens'] ); return $response['content']; @@ -144,17 +183,30 @@ class PRAutoBlogger_Content_Generator { $system = PRAutoBlogger_Content_Prompts::build_system( $request ); $response = $this->llm->send_chat_completion( - [ - [ 'role' => 'system', 'content' => $system ], - [ 'role' => 'user', 'content' => PRAutoBlogger_Content_Prompts::build_polish( $draft ) ], - ], + array( + array( + 'role' => 'system', + 'content' => $system, + ), + array( + 'role' => 'user', + 'content' => PRAutoBlogger_Content_Prompts::build_polish( $draft ), + ), + ), $model, - [ 'temperature' => 0.4, 'max_tokens' => 4000 ] + array( + 'temperature' => 0.4, + 'max_tokens' => 4000, + ) ); $this->cost_tracker->log_api_call( - null, 'polish', $this->llm->get_provider_name(), - $response['model'], $response['prompt_tokens'], $response['completion_tokens'] + null, + 'polish', + $this->llm->get_provider_name(), + $response['model'], + $response['prompt_tokens'], + $response['completion_tokens'] ); return $response['content']; diff --git a/includes/core/class-content-prompts.php b/includes/core/class-content-prompts.php index ba7a04a..d5bed5d 100644 --- a/includes/core/class-content-prompts.php +++ b/includes/core/class-content-prompts.php @@ -68,7 +68,7 @@ class PRAutoBlogger_Content_Prompts { "- Engaging intro, strong conclusion with CTA\n" . "- Do NOT include the title or / tags\n" . "- Output HTML only, no markdown or commentary\n" . - "- Follow EVERY formatting and structural requirement from your system prompt style guide", + '- Follow EVERY formatting and structural requirement from your system prompt style guide', $idea->get_suggested_title(), $idea->get_topic(), $idea->get_article_type(), @@ -92,10 +92,10 @@ class PRAutoBlogger_Content_Prompts { "Create a detailed outline for a blog post titled: \"%s\"\n\n" . "Topic: %s\nArticle type: %s\n\nKey points to cover:\n%s\n\n" . "Target keywords: %s\n\n" . - "The outline should have 4-6 main sections with bullet points under each. " . - "Include an introduction hook and a conclusion with a call to action. " . + 'The outline should have 4-6 main sections with bullet points under each. ' . + 'Include an introduction hook and a conclusion with a call to action. ' . "Word count target: %d-%d words.\n\n" . - "Plan the structure to satisfy EVERY requirement in your system prompt style guide.", + 'Plan the structure to satisfy EVERY requirement in your system prompt style guide.', $idea->get_suggested_title(), $idea->get_topic(), $idea->get_article_type(), @@ -125,7 +125,7 @@ class PRAutoBlogger_Content_Prompts { "- Naturally incorporate these keywords: %s\n" . "- Do NOT include the title in the HTML (it will be set separately)\n" . "- Do NOT wrap in , , or tags — just the article content\n" . - "- Follow EVERY formatting and structural requirement from your system prompt style guide", + '- Follow EVERY formatting and structural requirement from your system prompt style guide', $outline, $request->get_tone(), $request->get_min_word_count(), @@ -147,9 +147,9 @@ class PRAutoBlogger_Content_Prompts { "3. Engagement (hooks, transitions, call-to-action)\n" . "4. Accuracy and clarity\n" . "5. Remove any filler or redundant sentences\n\n" . - "IMPORTANT: Preserve all bullet points, numbered lists, hyperlinks, and " . - "structural elements from the draft. Do NOT flatten lists into prose or " . - "remove links. Ensure every requirement from your system prompt style " . + 'IMPORTANT: Preserve all bullet points, numbered lists, hyperlinks, and ' . + 'structural elements from the draft. Do NOT flatten lists into prose or ' . + 'remove links. Ensure every requirement from your system prompt style ' . "guide is satisfied in the final output.\n\n" . "Return the polished HTML content only. Do not add commentary.\n\n" . "DRAFT:\n" . $draft; @@ -172,7 +172,7 @@ class PRAutoBlogger_Content_Prompts { $rules .= self::build_article_links(); - $rules .= "--- END LINKING RULES ---"; + $rules .= '--- END LINKING RULES ---'; return $rules; } @@ -183,20 +183,22 @@ class PRAutoBlogger_Content_Prompts { * @return string Formatted list, or a fallback note. */ private static function build_article_links(): string { - $posts = get_posts( [ - 'post_type' => 'post', - 'post_status' => 'publish', - 'posts_per_page' => 30, - 'orderby' => 'date', - 'order' => 'DESC', - 'fields' => 'ids', - ] ); + $posts = get_posts( + array( + 'post_type' => 'post', + 'post_status' => 'publish', + 'posts_per_page' => 30, + 'orderby' => 'date', + 'order' => 'DESC', + 'fields' => 'ids', + ) + ); if ( empty( $posts ) ) { return "No published articles available for internal linking yet.\n"; } - $lines = [ "Available article links (use where topically relevant):\n" ]; + $lines = array( "Available article links (use where topically relevant):\n" ); foreach ( $posts as $post_id ) { $title = get_the_title( $post_id ); $url = get_permalink( $post_id ); @@ -207,5 +209,4 @@ class PRAutoBlogger_Content_Prompts { return implode( "\n", $lines ) . "\n"; } - } diff --git a/includes/core/class-cost-reporter.php b/includes/core/class-cost-reporter.php index fb5a13f..9f97c50 100644 --- a/includes/core/class-cost-reporter.php +++ b/includes/core/class-cost-reporter.php @@ -54,7 +54,7 @@ class PRAutoBlogger_Cost_Reporter { public function get_daily_spend( int $days = 30 ): array { global $wpdb; if ( null === $wpdb ) { - return []; + return array(); } $table = $wpdb->prefix . 'prautoblogger_generation_log'; @@ -74,8 +74,8 @@ class PRAutoBlogger_Cost_Reporter { ARRAY_A ); - $daily = []; - foreach ( ( $results ?: [] ) as $row ) { + $daily = array(); + foreach ( ( $results ?: array() ) as $row ) { $daily[ $row['day'] ] = (float) $row['total_cost']; } @@ -93,7 +93,7 @@ class PRAutoBlogger_Cost_Reporter { public function get_spend_by_stage( string $start_date, string $end_date ): array { global $wpdb; if ( null === $wpdb ) { - return []; + return array(); } $table = $wpdb->prefix . 'prautoblogger_generation_log'; @@ -114,13 +114,13 @@ class PRAutoBlogger_Cost_Reporter { ARRAY_A ); - $breakdown = []; - foreach ( ( $results ?: [] ) as $row ) { - $breakdown[ $row['stage'] ] = [ + $breakdown = array(); + foreach ( ( $results ?: array() ) as $row ) { + $breakdown[ $row['stage'] ] = array( 'cost' => (float) $row['total_cost'], 'tokens' => (int) $row['total_tokens'], 'calls' => (int) $row['call_count'], - ]; + ); } return $breakdown; diff --git a/includes/core/class-cost-tracker.php b/includes/core/class-cost-tracker.php index fca9ae5..5f1d88d 100755 --- a/includes/core/class-cost-tracker.php +++ b/includes/core/class-cost-tracker.php @@ -87,19 +87,21 @@ class PRAutoBlogger_Cost_Tracker { $this->current_run_cost += $cost; - $log_entry = new PRAutoBlogger_Generation_Log( [ - 'post_id' => $post_id, - 'run_id' => $this->run_id, - 'stage' => $stage, - 'provider' => $provider, - 'model' => $model, - 'prompt_tokens' => $prompt_tokens, - 'completion_tokens' => $completion_tokens, - 'estimated_cost' => $cost, - 'response_status' => $response_status, - 'error_message' => $error_message, - 'created_at' => current_time( 'mysql' ), - ] ); + $log_entry = new PRAutoBlogger_Generation_Log( + array( + 'post_id' => $post_id, + 'run_id' => $this->run_id, + 'stage' => $stage, + 'provider' => $provider, + 'model' => $model, + 'prompt_tokens' => $prompt_tokens, + 'completion_tokens' => $completion_tokens, + 'estimated_cost' => $cost, + 'response_status' => $response_status, + 'error_message' => $error_message, + 'created_at' => current_time( 'mysql' ), + ) + ); global $wpdb; $table = $wpdb->prefix . 'prautoblogger_generation_log'; @@ -158,19 +160,22 @@ class PRAutoBlogger_Cost_Tracker { $table = $wpdb->prefix . 'prautoblogger_generation_log'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery - $wpdb->insert( $table, [ - 'post_id' => $post_id, - 'run_id' => $this->run_id, - 'stage' => $stage, - 'provider' => 'cloudflare-workers-ai', - 'model' => $model, - 'prompt_tokens' => 0, - 'completion_tokens' => 0, - 'estimated_cost' => $cost_usd, - 'response_status' => 'success', - 'error_message' => '', - 'created_at' => current_time( 'mysql' ), - ] ); + $wpdb->insert( + $table, + array( + 'post_id' => $post_id, + 'run_id' => $this->run_id, + 'stage' => $stage, + 'provider' => 'cloudflare-workers-ai', + 'model' => $model, + 'prompt_tokens' => 0, + 'completion_tokens' => 0, + 'estimated_cost' => $cost_usd, + 'response_status' => 'success', + 'error_message' => '', + 'created_at' => current_time( 'mysql' ), + ) + ); } /** diff --git a/includes/core/class-ga4-client.php b/includes/core/class-ga4-client.php index 3952b3d..11ffc5d 100755 --- a/includes/core/class-ga4-client.php +++ b/includes/core/class-ga4-client.php @@ -29,32 +29,32 @@ class PRAutoBlogger_GA4_Client { public function fetch_data( array $posts ): array { $property_id = get_option( 'prautoblogger_ga4_property_id', '' ); if ( '' === $property_id ) { - return []; + return array(); } $credentials_encrypted = get_option( 'prautoblogger_ga4_credentials_json', '' ); if ( '' === $credentials_encrypted ) { - return []; + return array(); } $credentials = PRAutoBlogger_Encryption::decrypt( $credentials_encrypted ); if ( '' === $credentials ) { - return []; + return array(); } // Build page paths for the GA4 query. - $page_paths = []; - $path_to_id = []; + $page_paths = array(); + $path_to_id = array(); foreach ( $posts as $post ) { $path = wp_parse_url( get_permalink( $post->ID ), PHP_URL_PATH ); if ( $path ) { - $page_paths[] = $path; + $page_paths[] = $path; $path_to_id[ $path ] = (int) $post->ID; } } if ( empty( $page_paths ) ) { - return []; + return array(); } // GA4 Data API request. @@ -62,40 +62,45 @@ class PRAutoBlogger_GA4_Client { $access_token = $this->get_access_token( $credentials ); if ( '' === $access_token ) { PRAutoBlogger_Logger::instance()->error( 'GA4: Failed to get access token. Possible causes: invalid service account JSON, expired or revoked private key, or network error reaching oauth2.googleapis.com. Verify credentials in PRAutoBlogger → Settings.', 'ga4' ); - return []; + return array(); } - $request_body = [ - 'dateRanges' => [ [ 'startDate' => '30daysAgo', 'endDate' => 'today' ] ], - 'dimensions' => [ [ 'name' => 'pagePath' ] ], - 'metrics' => [ - [ 'name' => 'screenPageViews' ], - [ 'name' => 'averageSessionDuration' ], - [ 'name' => 'bounceRate' ], - ], - 'dimensionFilter' => [ - 'filter' => [ + $request_body = array( + 'dateRanges' => array( + array( + 'startDate' => '30daysAgo', + 'endDate' => 'today', + ), + ), + 'dimensions' => array( array( 'name' => 'pagePath' ) ), + 'metrics' => array( + array( 'name' => 'screenPageViews' ), + array( 'name' => 'averageSessionDuration' ), + array( 'name' => 'bounceRate' ), + ), + 'dimensionFilter' => array( + 'filter' => array( 'fieldName' => 'pagePath', - 'inListFilter' => [ 'values' => $page_paths ], - ], - ], - ]; + 'inListFilter' => array( 'values' => $page_paths ), + ), + ), + ); $response = wp_remote_post( "https://analyticsdata.googleapis.com/v1beta/properties/{$property_id}:runReport", - [ + array( 'timeout' => 30, - 'headers' => [ + 'headers' => array( 'Authorization' => 'Bearer ' . $access_token, 'Content-Type' => 'application/json', - ], + ), 'body' => wp_json_encode( $request_body ), - ] + ) ); if ( is_wp_error( $response ) ) { PRAutoBlogger_Logger::instance()->error( 'GA4 API request failed (WP HTTP error): ' . $response->get_error_message(), 'ga4' ); - return []; + return array(); } $ga4_status = wp_remote_retrieve_response_code( $response ); @@ -105,20 +110,20 @@ class PRAutoBlogger_GA4_Client { sprintf( 'GA4 API request failed (HTTP %d): %s', $ga4_status, substr( $ga4_body, 0, 500 ) ), 'ga4' ); - return []; + return array(); } $data = json_decode( wp_remote_retrieve_body( $response ), true ); - $results = []; + $results = array(); - foreach ( ( $data['rows'] ?? [] ) as $row ) { + foreach ( ( $data['rows'] ?? array() ) as $row ) { $path = $row['dimensionValues'][0]['value'] ?? ''; if ( isset( $path_to_id[ $path ] ) ) { - $results[ $path_to_id[ $path ] ] = [ + $results[ $path_to_id[ $path ] ] = array( 'pageviews' => (int) ( $row['metricValues'][0]['value'] ?? 0 ), 'avg_time_on_page' => (float) ( $row['metricValues'][1]['value'] ?? 0 ), 'bounce_rate' => (float) ( $row['metricValues'][2]['value'] ?? 0 ), - ]; + ); } } @@ -140,19 +145,26 @@ class PRAutoBlogger_GA4_Client { // Build JWT for service account auth. $now = time(); - $header = wp_json_encode( [ 'alg' => 'RS256', 'typ' => 'JWT' ] ); - $claim = wp_json_encode( [ - 'iss' => $creds['client_email'], - 'scope' => 'https://www.googleapis.com/auth/analytics.readonly', - 'aud' => 'https://oauth2.googleapis.com/token', - 'exp' => $now + 3600, - 'iat' => $now, - ] ); + $header = wp_json_encode( + array( + 'alg' => 'RS256', + 'typ' => 'JWT', + ) + ); + $claim = wp_json_encode( + array( + 'iss' => $creds['client_email'], + 'scope' => 'https://www.googleapis.com/auth/analytics.readonly', + 'aud' => 'https://oauth2.googleapis.com/token', + 'exp' => $now + 3600, + 'iat' => $now, + ) + ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode $base64_header = rtrim( strtr( base64_encode( $header ), '+/', '-_' ), '=' ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode - $base64_claim = rtrim( strtr( base64_encode( $claim ), '+/', '-_' ), '=' ); + $base64_claim = rtrim( strtr( base64_encode( $claim ), '+/', '-_' ), '=' ); $signing_input = $base64_header . '.' . $base64_claim; $signature = ''; @@ -171,13 +183,13 @@ class PRAutoBlogger_GA4_Client { $response = wp_remote_post( 'https://oauth2.googleapis.com/token', - [ + array( 'timeout' => 15, - 'body' => [ + 'body' => array( 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $jwt, - ], - ] + ), + ) ); if ( is_wp_error( $response ) ) { diff --git a/includes/core/class-idea-scorer.php b/includes/core/class-idea-scorer.php index 62dd62e..4f4abec 100755 --- a/includes/core/class-idea-scorer.php +++ b/includes/core/class-idea-scorer.php @@ -44,8 +44,8 @@ class PRAutoBlogger_Idea_Scorer { * @return PRAutoBlogger_Article_Idea[] Top-ranked ideas, sorted by score desc. */ public function score_and_rank( array $analysis_results, int $target_count ): array { - $exclusions = json_decode( get_option( 'prautoblogger_topic_exclusions', '[]' ), true ) ?: []; - $ideas = []; + $exclusions = json_decode( get_option( 'prautoblogger_topic_exclusions', '[]' ), true ) ?: array(); + $ideas = array(); $excluded_count = 0; $deduped_count = 0; @@ -55,11 +55,11 @@ class PRAutoBlogger_Idea_Scorer { } // Keyword sets kept for fallback (passed through to Semantic_Dedup). - $accepted_keyword_sets = []; + $accepted_keyword_sets = array(); foreach ( $analysis_results as $result ) { if ( $this->is_excluded( $result->get_topic(), $exclusions ) ) { - $excluded_count++; + ++$excluded_count; continue; } @@ -68,7 +68,7 @@ class PRAutoBlogger_Idea_Scorer { $topic_keywords = $this->extract_meaningful_keywords( $topic ); if ( $dedup->is_batch_duplicate( $topic, $topic_keywords, $accepted_keyword_sets ) ) { - $deduped_count++; + ++$deduped_count; PRAutoBlogger_Logger::instance()->info( sprintf( 'Dedup(batch): skipping "%s"', substr( $topic, 0, 80 ) ), 'scorer' @@ -77,7 +77,7 @@ class PRAutoBlogger_Idea_Scorer { } if ( $dedup->is_recent_duplicate( $topic, $topic_keywords ) ) { - $deduped_count++; + ++$deduped_count; PRAutoBlogger_Logger::instance()->info( sprintf( 'Dedup(recent): skipping "%s"', substr( $topic, 0, 80 ) ), 'scorer' @@ -89,19 +89,21 @@ class PRAutoBlogger_Idea_Scorer { $dedup->record_accepted( $topic ); } - $metadata = $result->get_metadata() ?? []; + $metadata = $result->get_metadata() ?? array(); - $ideas[] = new PRAutoBlogger_Article_Idea( [ - 'topic' => $result->get_topic(), - 'article_type' => $this->map_type( $result->get_analysis_type() ), - 'suggested_title' => $metadata['suggested_title'] ?? $result->get_topic(), - 'summary' => $result->get_summary() ?? '', - 'score' => $this->compute_score( $result ), - 'analysis_id' => $result->get_id(), - 'source_ids' => $result->get_source_ids(), - 'key_points' => $metadata['key_points'] ?? [], - 'target_keywords' => $metadata['target_keywords'] ?? [], - ] ); + $ideas[] = new PRAutoBlogger_Article_Idea( + array( + 'topic' => $result->get_topic(), + 'article_type' => $this->map_type( $result->get_analysis_type() ), + 'suggested_title' => $metadata['suggested_title'] ?? $result->get_topic(), + 'summary' => $result->get_summary() ?? '', + 'score' => $this->compute_score( $result ), + 'analysis_id' => $result->get_id(), + 'source_ids' => $result->get_source_ids(), + 'key_points' => $metadata['key_points'] ?? array(), + 'target_keywords' => $metadata['target_keywords'] ?? array(), + ) + ); } PRAutoBlogger_Logger::instance()->info( @@ -116,9 +118,12 @@ class PRAutoBlogger_Idea_Scorer { 'scorer' ); - usort( $ideas, static function ( PRAutoBlogger_Article_Idea $a, PRAutoBlogger_Article_Idea $b ): int { - return $b->get_score() <=> $a->get_score(); - } ); + usort( + $ideas, + static function ( PRAutoBlogger_Article_Idea $a, PRAutoBlogger_Article_Idea $b ): int { + return $b->get_score() <=> $a->get_score(); + } + ); return array_slice( $ideas, 0, $target_count ); } @@ -165,27 +170,122 @@ class PRAutoBlogger_Idea_Scorer { * @return string[] Unique lowercase keywords. */ private function extract_meaningful_keywords( string $text ): array { - static $stopwords = [ - 'a', 'an', 'the', 'and', 'or', 'but', 'is', 'are', 'was', 'were', - 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'from', 'as', - 'it', 'its', 'this', 'that', 'your', 'you', 'how', 'what', 'when', - 'why', 'where', 'which', 'who', 'do', 'does', 'did', 'not', 'no', - 'can', 'will', 'should', 'could', 'would', 'may', 'might', 'have', - 'has', 'had', 'be', 'been', 'being', 'about', 'into', 'through', - 'during', 'before', 'after', 'above', 'below', 'between', 'same', - 'up', 'down', 'out', 'off', 'over', 'under', 'again', 'then', - 'here', 'there', 'all', 'each', 'every', 'both', 'few', 'more', - 'most', 'other', 'some', 'such', 'than', 'too', 'very', 'just', - 'also', 'only', 'own', 'so', 'if', 'while', 'because', 'until', - 'vs', 'versus', 'guide', 'complete', 'ultimate', 'best', 'top', - 'new', 'first', 'need', 'know', 'everything', - ]; + static $stopwords = array( + 'a', + 'an', + 'the', + 'and', + 'or', + 'but', + 'is', + 'are', + 'was', + 'were', + 'in', + 'on', + 'at', + 'to', + 'for', + 'of', + 'with', + 'by', + 'from', + 'as', + 'it', + 'its', + 'this', + 'that', + 'your', + 'you', + 'how', + 'what', + 'when', + 'why', + 'where', + 'which', + 'who', + 'do', + 'does', + 'did', + 'not', + 'no', + 'can', + 'will', + 'should', + 'could', + 'would', + 'may', + 'might', + 'have', + 'has', + 'had', + 'be', + 'been', + 'being', + 'about', + 'into', + 'through', + 'during', + 'before', + 'after', + 'above', + 'below', + 'between', + 'same', + 'up', + 'down', + 'out', + 'off', + 'over', + 'under', + 'again', + 'then', + 'here', + 'there', + 'all', + 'each', + 'every', + 'both', + 'few', + 'more', + 'most', + 'other', + 'some', + 'such', + 'than', + 'too', + 'very', + 'just', + 'also', + 'only', + 'own', + 'so', + 'if', + 'while', + 'because', + 'until', + 'vs', + 'versus', + 'guide', + 'complete', + 'ultimate', + 'best', + 'top', + 'new', + 'first', + 'need', + 'know', + 'everything', + ); $text = strtolower( $text ); $words = preg_split( '/[^a-z0-9-]+/', $text, -1, PREG_SPLIT_NO_EMPTY ); - $words = array_filter( $words, static function ( string $w ) use ( $stopwords ): bool { - return strlen( $w ) >= 2 && ! in_array( $w, $stopwords, true ); - } ); + $words = array_filter( + $words, + static function ( string $w ) use ( $stopwords ): bool { + return strlen( $w ) >= 2 && ! in_array( $w, $stopwords, true ); + } + ); return array_values( array_unique( $words ) ); } @@ -197,13 +297,13 @@ class PRAutoBlogger_Idea_Scorer { * @return string Article type label. */ private function map_type( string $analysis_type ): string { - $map = [ + $map = array( 'question' => 'guide', 'complaint' => 'solution', 'comparison' => 'comparison', 'news' => 'news', 'guide' => 'guide', - ]; + ); return $map[ $analysis_type ] ?? 'article'; } } diff --git a/includes/core/class-image-media-sideloader.php b/includes/core/class-image-media-sideloader.php index b0feb03..badcf56 100644 --- a/includes/core/class-image-media-sideloader.php +++ b/includes/core/class-image-media-sideloader.php @@ -61,10 +61,10 @@ class PRAutoBlogger_Image_Media_Sideloader { } // Prepare file array for media_handle_sideload(). - $file_array = [ + $file_array = array( 'name' => $this->generate_filename( $image_data['model'], $image_data['width'], $image_data['height'] ), 'tmp_name' => $temp_file, - ]; + ); // Import the file into media library. $attachment_id = media_handle_sideload( $file_array, $post_id ); @@ -108,8 +108,8 @@ class PRAutoBlogger_Image_Media_Sideloader { * @return string|\WP_Error Path to temporary file on success, WP_Error on failure. */ private function create_temp_file( string $bytes, string $mime_type ) { - $temp_dir = get_temp_dir(); - $filename = 'prautoblogger_img_' . wp_generate_uuid4() . $this->get_extension_for_mime( $mime_type ); + $temp_dir = get_temp_dir(); + $filename = 'prautoblogger_img_' . wp_generate_uuid4() . $this->get_extension_for_mime( $mime_type ); $temp_path = $temp_dir . $filename; $written = file_put_contents( $temp_path, $bytes ); @@ -156,11 +156,11 @@ class PRAutoBlogger_Image_Media_Sideloader { * @return string File extension with leading dot (e.g., '.png'). */ private function get_extension_for_mime( string $mime_type ): string { - $map = [ + $map = array( 'image/png' => '.png', 'image/jpeg' => '.jpg', 'image/jpg' => '.jpg', - ]; + ); return $map[ strtolower( $mime_type ) ] ?? '.png'; } diff --git a/includes/core/class-image-nsfw-retry.php b/includes/core/class-image-nsfw-retry.php index 8b0ed71..f646629 100644 --- a/includes/core/class-image-nsfw-retry.php +++ b/includes/core/class-image-nsfw-retry.php @@ -106,15 +106,15 @@ class PRAutoBlogger_Image_NSFW_Retry { 'image_pipeline' ); - $retry_request = [ + $retry_request = array( 'prompt' => $fallback['prompt'], - 'width' => (int) ( $batch_requests[ $key ]['width'] ?? 0 ), + 'width' => (int) ( $batch_requests[ $key ]['width'] ?? 0 ), 'height' => (int) ( $batch_requests[ $key ]['height'] ?? 0 ), - 'options' => $batch_requests[ $key ]['options'] ?? [], - ]; + 'options' => $batch_requests[ $key ]['options'] ?? array(), + ); - $retry_results = $this->provider->generate_image_batch( [ $key => $retry_request ] ); - $retry_entry = $retry_results[ $key ] ?? [ 'error' => 'Retry provider returned no result.' ]; + $retry_results = $this->provider->generate_image_batch( array( $key => $retry_request ) ); + $retry_entry = $retry_results[ $key ] ?? array( 'error' => 'Retry provider returned no result.' ); if ( isset( $retry_entry['error'] ) ) { PRAutoBlogger_Logger::instance()->warning( diff --git a/includes/core/class-image-pipeline.php b/includes/core/class-image-pipeline.php index 41f31da..545787b 100644 --- a/includes/core/class-image-pipeline.php +++ b/includes/core/class-image-pipeline.php @@ -47,10 +47,10 @@ class PRAutoBlogger_Image_Pipeline { ?PRAutoBlogger_Image_Provider_Interface $provider = null, ?PRAutoBlogger_Cost_Tracker $cost_tracker = null ) { - $this->provider = $provider ?? self::create_default_provider(); - $this->prompt_builder = new PRAutoBlogger_Image_Prompt_Builder(); - $this->sideloader = new PRAutoBlogger_Image_Media_Sideloader(); - $this->cost_tracker = $cost_tracker ?? new PRAutoBlogger_Cost_Tracker(); + $this->provider = $provider ?? self::create_default_provider(); + $this->prompt_builder = new PRAutoBlogger_Image_Prompt_Builder(); + $this->sideloader = new PRAutoBlogger_Image_Media_Sideloader(); + $this->cost_tracker = $cost_tracker ?? new PRAutoBlogger_Cost_Tracker(); } /** @@ -85,7 +85,10 @@ class PRAutoBlogger_Image_Pipeline { array $article_data, ?array $source_data = null ): array { - $result = [ 'cost_usd' => 0.0, 'errors' => [] ]; + $result = array( + 'cost_usd' => 0.0, + 'errors' => array(), + ); if ( ! get_option( 'prautoblogger_image_enabled' ) ) { PRAutoBlogger_Logger::instance()->info( 'Image generation disabled in settings.', 'image_pipeline' ); @@ -107,24 +110,24 @@ class PRAutoBlogger_Image_Pipeline { // Build all prompts upfront (LLM calls happen here, sequentially). $article_prompt = $this->prompt_builder->build_article_prompt( $article_data ); - $batch_requests = [ - 'image_a' => [ + $batch_requests = array( + 'image_a' => array( 'prompt' => $article_prompt['prompt'], 'width' => self::DEFAULT_WIDTH, 'height' => self::DEFAULT_HEIGHT, - ], - ]; - $captions = [ 'image_a' => $article_prompt['caption'] ]; + ), + ); + $captions = array( 'image_a' => $article_prompt['caption'] ); $source_prompt = null; if ( $generate_b ) { - $source_prompt = $this->prompt_builder->build_source_prompt( $source_data ); - $batch_requests['image_b'] = [ + $source_prompt = $this->prompt_builder->build_source_prompt( $source_data ); + $batch_requests['image_b'] = array( 'prompt' => $source_prompt['prompt'], 'width' => self::DEFAULT_WIDTH, 'height' => self::DEFAULT_HEIGHT, - ]; - $captions['image_b'] = $source_prompt['caption']; + ); + $captions['image_b'] = $source_prompt['caption']; } // Fire all image generation requests in parallel. @@ -290,9 +293,11 @@ class PRAutoBlogger_Image_Pipeline { esc_html( $caption ) ); - wp_update_post( [ - 'ID' => $post_id, - 'post_content' => $caption_html . "\n\n" . $post->post_content, - ] ); + wp_update_post( + array( + 'ID' => $post_id, + 'post_content' => $caption_html . "\n\n" . $post->post_content, + ) + ); } } diff --git a/includes/core/class-image-prompt-builder.php b/includes/core/class-image-prompt-builder.php index 6ab2389..47c7735 100644 --- a/includes/core/class-image-prompt-builder.php +++ b/includes/core/class-image-prompt-builder.php @@ -82,10 +82,10 @@ PROMPT; $style_suffix = get_option( 'prautoblogger_image_style_suffix', PRAUTOBLOGGER_DEFAULT_IMAGE_STYLE_SUFFIX ); - return [ + return array( 'prompt' => trim( $parsed['scene'] . ' ' . $style_suffix ), 'caption' => $parsed['caption'], - ]; + ); } /** @@ -97,17 +97,17 @@ PROMPT; */ public function build_source_prompt( array $source_data ): array { $title = $source_data['title'] ?? 'Reddit Discussion'; - $comments = $source_data['comments'] ?? []; + $comments = $source_data['comments'] ?? array(); $context = is_array( $comments ) && ! empty( $comments ) ? $comments[0] : ''; $parsed = $this->rewrite_via_llm( $title, $context ); $style_suffix = get_option( 'prautoblogger_image_style_suffix', PRAUTOBLOGGER_DEFAULT_IMAGE_STYLE_SUFFIX ); - return [ + return array( 'prompt' => trim( $parsed['scene'] . ' ' . $style_suffix ), 'caption' => $parsed['caption'], - ]; + ); } /** @@ -146,15 +146,21 @@ PROMPT; $system = $this->resolve_system_prompt(); $result = $llm->send_chat_completion( - [ - [ 'role' => 'system', 'content' => $system ], - [ 'role' => 'user', 'content' => $user_message ], - ], + array( + array( + 'role' => 'system', + 'content' => $system, + ), + array( + 'role' => 'user', + 'content' => $user_message, + ), + ), $model, - [ + array( 'temperature' => 0.7, 'max_tokens' => self::REWRITER_MAX_TOKENS, - ] + ) ); $raw = trim( $result['content'] ?? '' ); @@ -217,11 +223,17 @@ PROMPT; $caption = trim( $parts[1] ); // Strip surrounding quotes from caption — the LLM wraps it in quotes. $caption = trim( $caption, '"\'' ); - return [ 'scene' => $scene, 'caption' => $caption ]; + return array( + 'scene' => $scene, + 'caption' => $caption, + ); } // No blank-line separator found — treat entire response as scene. - return [ 'scene' => trim( $raw ), 'caption' => '' ]; + return array( + 'scene' => trim( $raw ), + 'caption' => '', + ); } /** @@ -256,10 +268,10 @@ PROMPT; public function build_fallback_prompt( string $title ): array { $parsed = $this->synthesize_visual_concepts_fallback( $title, '' ); $style_suffix = get_option( 'prautoblogger_image_style_suffix', PRAUTOBLOGGER_DEFAULT_IMAGE_STYLE_SUFFIX ); - return [ + return array( 'prompt' => trim( $parsed['scene'] . ' ' . $style_suffix ), 'caption' => $parsed['caption'], - ]; + ); } /** @@ -278,10 +290,10 @@ PROMPT; $title ); - return [ + return array( 'scene' => trim( $scene ), 'caption' => 'Science is full of surprises.', - ]; + ); } /** Lazy-load the OpenRouter provider. */ diff --git a/includes/core/class-logger.php b/includes/core/class-logger.php index b9d3282..1a04017 100755 --- a/includes/core/class-logger.php +++ b/includes/core/class-logger.php @@ -26,19 +26,19 @@ class PRAutoBlogger_Logger { public const LEVEL_INFO = 2; public const LEVEL_DEBUG = 3; - private const LEVEL_MAP = [ + private const LEVEL_MAP = array( 'error' => self::LEVEL_ERROR, 'warning' => self::LEVEL_WARNING, 'info' => self::LEVEL_INFO, 'debug' => self::LEVEL_DEBUG, - ]; + ); - private const LEVEL_LABELS = [ + private const LEVEL_LABELS = array( self::LEVEL_ERROR => 'error', self::LEVEL_WARNING => 'warning', self::LEVEL_INFO => 'info', self::LEVEL_DEBUG => 'debug', - ]; + ); /** Singleton instance. */ private static ?self $instance = null; @@ -66,7 +66,7 @@ class PRAutoBlogger_Logger { * @param string $context Origin class or pipeline stage. * @param array $meta Optional structured data. */ - public function error( string $message, string $context = '', array $meta = [] ): void { + public function error( string $message, string $context = '', array $meta = array() ): void { $this->log( self::LEVEL_ERROR, $message, $context, $meta ); } @@ -77,7 +77,7 @@ class PRAutoBlogger_Logger { * @param string $context * @param array $meta */ - public function warning( string $message, string $context = '', array $meta = [] ): void { + public function warning( string $message, string $context = '', array $meta = array() ): void { $this->log( self::LEVEL_WARNING, $message, $context, $meta ); } @@ -88,7 +88,7 @@ class PRAutoBlogger_Logger { * @param string $context * @param array $meta */ - public function info( string $message, string $context = '', array $meta = [] ): void { + public function info( string $message, string $context = '', array $meta = array() ): void { $this->log( self::LEVEL_INFO, $message, $context, $meta ); } @@ -99,7 +99,7 @@ class PRAutoBlogger_Logger { * @param string $context * @param array $meta */ - public function debug( string $message, string $context = '', array $meta = [] ): void { + public function debug( string $message, string $context = '', array $meta = array() ): void { $this->log( self::LEVEL_DEBUG, $message, $context, $meta ); } @@ -134,13 +134,16 @@ class PRAutoBlogger_Logger { $table = $wpdb->prefix . 'prautoblogger_event_log'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery - $wpdb->insert( $table, [ - 'level' => $label, - 'context' => substr( $context, 0, 100 ), - 'message' => substr( $message, 0, 2000 ), - 'meta_json' => ! empty( $meta ) ? wp_json_encode( $meta ) : null, - 'created_at' => current_time( 'mysql' ), - ] ); + $wpdb->insert( + $table, + array( + 'level' => $label, + 'context' => substr( $context, 0, 100 ), + 'message' => substr( $message, 0, 2000 ), + 'meta_json' => ! empty( $meta ) ? wp_json_encode( $meta ) : null, + 'created_at' => current_time( 'mysql' ), + ) + ); } /** @@ -161,8 +164,8 @@ class PRAutoBlogger_Logger { ): array { global $wpdb; $table = $wpdb->prefix . 'prautoblogger_event_log'; - $where = []; - $params = []; + $where = array(); + $params = array(); if ( 'all' !== $level_filter && isset( self::LEVEL_MAP[ $level_filter ] ) ) { $where[] = 'level = %s'; @@ -201,7 +204,10 @@ class PRAutoBlogger_Logger { ARRAY_A ); - return [ 'rows' => $rows ?: [], 'total' => $total ]; + return array( + 'rows' => $rows ?: array(), + 'total' => $total, + ); } /** diff --git a/includes/core/class-metrics-collector.php b/includes/core/class-metrics-collector.php index 7932b08..dab14fb 100755 --- a/includes/core/class-metrics-collector.php +++ b/includes/core/class-metrics-collector.php @@ -35,8 +35,8 @@ class PRAutoBlogger_Metrics_Collector { } $ga4_client = new PRAutoBlogger_GA4_Client(); - $ga4_data = $ga4_client->fetch_data( $posts ); - $scored = 0; + $ga4_data = $ga4_client->fetch_data( $posts ); + $scored = 0; foreach ( $posts as $post ) { $post_id = (int) $post->ID; @@ -47,11 +47,11 @@ class PRAutoBlogger_Metrics_Collector { continue; } - $ga_metrics = $ga4_data[ $post_id ] ?? []; + $ga_metrics = $ga4_data[ $post_id ] ?? array(); $score = $this->compute_composite_score( $wp_metrics, $ga_metrics, $post ); $this->store_score( $post_id, $wp_metrics, $ga_metrics, $score ); - $scored++; + ++$scored; } PRAutoBlogger_Logger::instance()->info( sprintf( 'Metrics collected for %d posts.', $scored ), 'metrics' ); @@ -64,15 +64,17 @@ class PRAutoBlogger_Metrics_Collector { * @return \WP_Post[] */ private function get_generated_posts(): array { - $query = new \WP_Query( [ - 'post_type' => 'post', - 'post_status' => 'publish', - 'meta_key' => '_prautoblogger_generated', - 'meta_value' => '1', - 'posts_per_page' => 100, - 'orderby' => 'date', - 'order' => 'DESC', - ] ); + $query = new \WP_Query( + array( + 'post_type' => 'post', + 'post_status' => 'publish', + 'meta_key' => '_prautoblogger_generated', + 'meta_value' => '1', + 'posts_per_page' => 100, + 'orderby' => 'date', + 'order' => 'DESC', + ) + ); return $query->posts; } @@ -93,10 +95,10 @@ class PRAutoBlogger_Metrics_Collector { return null; } - return [ + return array( 'comment_count' => (int) ( $post->comment_count ?? 0 ), 'days_published' => max( 1, (int) ( ( time() - strtotime( $post->post_date ) ) / DAY_IN_SECONDS ) ), - ]; + ); } @@ -110,10 +112,10 @@ class PRAutoBlogger_Metrics_Collector { * @return array{score: float, factors: array} */ private function compute_composite_score( array $wp_metrics, array $ga_metrics, \WP_Post $post ): array { - $factors = []; + $factors = array(); // Comment engagement (0-25 points). - $comments_per_day = $wp_metrics['comment_count'] / max( 1, $wp_metrics['days_published'] ); + $comments_per_day = $wp_metrics['comment_count'] / max( 1, $wp_metrics['days_published'] ); $factors['comments'] = min( 25.0, $comments_per_day * 25.0 ); // Pageview performance (0-30 points, if GA4 available). @@ -142,10 +144,10 @@ class PRAutoBlogger_Metrics_Collector { $total = array_sum( $factors ); - return [ + return array( 'score' => round( $total, 2 ), 'factors' => $factors, - ]; + ); } /** @@ -162,16 +164,18 @@ class PRAutoBlogger_Metrics_Collector { global $wpdb; $table = $wpdb->prefix . 'prautoblogger_content_scores'; - $entry = new PRAutoBlogger_Content_Score( [ - 'post_id' => $post_id, - 'pageviews' => $ga_metrics['pageviews'] ?? 0, - 'avg_time_on_page' => $ga_metrics['avg_time_on_page'] ?? 0.0, - 'bounce_rate' => $ga_metrics['bounce_rate'] ?? 0.0, - 'comment_count' => $wp_metrics['comment_count'] ?? 0, - 'composite_score' => $score_data['score'], - 'score_factors' => $score_data['factors'], - 'measured_at' => current_time( 'mysql' ), - ] ); + $entry = new PRAutoBlogger_Content_Score( + array( + 'post_id' => $post_id, + 'pageviews' => $ga_metrics['pageviews'] ?? 0, + 'avg_time_on_page' => $ga_metrics['avg_time_on_page'] ?? 0.0, + 'bounce_rate' => $ga_metrics['bounce_rate'] ?? 0.0, + 'comment_count' => $wp_metrics['comment_count'] ?? 0, + 'composite_score' => $score_data['score'], + 'score_factors' => $score_data['factors'], + 'measured_at' => current_time( 'mysql' ), + ) + ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $wpdb->insert( $table, $entry->to_db_row() ); diff --git a/includes/core/class-peptide-linker.php b/includes/core/class-peptide-linker.php index c45a4ab..6ef15de 100644 --- a/includes/core/class-peptide-linker.php +++ b/includes/core/class-peptide-linker.php @@ -38,13 +38,19 @@ class PRAutoBlogger_Peptide_Linker { // Build a single regex alternation of all peptide names, longest first // so "BPC-157" matches before a hypothetical "BPC" would. $names = array_keys( $link_map ); - usort( $names, static function ( string $a, string $b ): int { - return strlen( $b ) - strlen( $a ); - } ); + usort( + $names, + static function ( string $a, string $b ): int { + return strlen( $b ) - strlen( $a ); + } + ); - $escaped = array_map( static function ( string $name ): string { - return preg_quote( $name, '/' ); - }, $names ); + $escaped = array_map( + static function ( string $name ): string { + return preg_quote( $name, '/' ); + }, + $names + ); // Word-boundary match, case-insensitive. $pattern = '/\b(' . implode( '|', $escaped ) . ')\b/iu'; @@ -63,16 +69,18 @@ class PRAutoBlogger_Peptide_Linker { * @return array Name → URL pairs, case-preserved keys. */ private static function build_link_map(): array { - $peptides = get_posts( [ - 'post_type' => 'pr_peptide', - 'post_status' => 'publish', - 'posts_per_page' => 200, - 'orderby' => 'title', - 'order' => 'ASC', - 'fields' => 'ids', - ] ); + $peptides = get_posts( + array( + 'post_type' => 'pr_peptide', + 'post_status' => 'publish', + 'posts_per_page' => 200, + 'orderby' => 'title', + 'order' => 'ASC', + 'fields' => 'ids', + ) + ); - $map = []; + $map = array(); foreach ( $peptides as $peptide_id ) { $title = get_the_title( $peptide_id ); $url = get_permalink( $peptide_id ); @@ -86,7 +94,7 @@ class PRAutoBlogger_Peptide_Linker { // If the name contains hyphens, also match the space-separated // variant (e.g., "BPC 157" → same URL as "BPC-157"). if ( strpos( $title, '-' ) !== false ) { - $space_variant = str_replace( '-', ' ', $title ); + $space_variant = str_replace( '-', ' ', $title ); $map[ $space_variant ] = $url; } } @@ -115,7 +123,7 @@ class PRAutoBlogger_Peptide_Linker { } // Build a lowercase → URL lookup for case-insensitive matching. - $lower_map = []; + $lower_map = array(); foreach ( $link_map as $name => $url ) { $lower_map[ mb_strtolower( $name ) ] = $url; } diff --git a/includes/core/class-pipeline-runner.php b/includes/core/class-pipeline-runner.php index a1b575f..3b89626 100755 --- a/includes/core/class-pipeline-runner.php +++ b/includes/core/class-pipeline-runner.php @@ -63,7 +63,12 @@ class PRAutoBlogger_Pipeline_Runner { $ideas = $this->orchestrate( $cost_tracker ); if ( empty( $ideas ) ) { - return [ 'generated' => 0, 'published' => 0, 'rejected' => 0, 'cost' => 0.0 ]; + return array( + 'generated' => 0, + 'published' => 0, + 'rejected' => 0, + 'cost' => 0.0, + ); } // Generate article 1 in this process — always fits within time limit. @@ -156,7 +161,7 @@ class PRAutoBlogger_Pipeline_Runner { private function orchestrate( PRAutoBlogger_Cost_Tracker $cost_tracker ): array { $target = absint( get_option( 'prautoblogger_daily_article_target', 1 ) ); - $enabled = json_decode( get_option( 'prautoblogger_enabled_sources', '["reddit"]' ), true ); + $enabled = json_decode( get_option( 'prautoblogger_enabled_sources', '["reddit"]' ), true ); $source_labels = is_array( $enabled ) ? implode( ', ', $enabled ) : 'reddit'; /* translators: %s is a comma-separated list of enabled source names, e.g. "reddit, llm_research". */ $this->broadcast_stage( sprintf( __( 'Collecting sources from %s…', 'prautoblogger' ), $source_labels ) ); @@ -197,11 +202,11 @@ class PRAutoBlogger_Pipeline_Runner { $ideas ); - $queue = [ + $queue = array( 'run_id' => $run_id, 'ideas' => $serialized, 'results' => $first, - ]; + ); update_option( self::QUEUE_KEY, $queue, false ); $this->update_queue_status( $queue ); @@ -221,7 +226,11 @@ class PRAutoBlogger_Pipeline_Runner { spawn_cron(); wp_remote_post( site_url( 'wp-cron.php?doing_wp_cron=' . sprintf( '%.22F', microtime( true ) ) ), - [ 'timeout' => 0.01, 'blocking' => false, 'sslverify' => false ] + array( + 'timeout' => 0.01, + 'blocking' => false, + 'sslverify' => false, + ) ); } @@ -231,23 +240,31 @@ class PRAutoBlogger_Pipeline_Runner { $total = $done + count( $queue['ideas'] ); $current = get_transient( 'prautoblogger_generation_status' ); - set_transient( 'prautoblogger_generation_status', [ - 'status' => 'running', - 'stage' => sprintf( __( 'Generating article %1$d of %2$d…', 'prautoblogger' ), $done + 1, $total ), - 'started' => is_array( $current ) ? ( $current['started'] ?? time() ) : time(), - 'last_updated' => time(), - ], 600 ); + set_transient( + 'prautoblogger_generation_status', + array( + 'status' => 'running', + 'stage' => sprintf( __( 'Generating article %1$d of %2$d…', 'prautoblogger' ), $done + 1, $total ), + 'started' => is_array( $current ) ? ( $current['started'] ?? time() ) : time(), + 'last_updated' => time(), + ), + 600 + ); } /** Write the final "complete" status transient. */ private function write_final_status( array $r ): void { - set_transient( 'prautoblogger_generation_status', [ - 'status' => 'complete', - 'generated' => $r['generated'], - 'published' => $r['published'], - 'rejected' => $r['rejected'], - 'cost' => $r['cost'], - ], 600 ); + set_transient( + 'prautoblogger_generation_status', + array( + 'status' => 'complete', + 'generated' => $r['generated'], + 'published' => $r['published'], + 'rejected' => $r['rejected'], + 'cost' => $r['cost'], + ), + 600 + ); } /** Clean up a stale or empty queue. */ @@ -265,7 +282,10 @@ class PRAutoBlogger_Pipeline_Runner { PRAutoBlogger_Logger::instance()->info( sprintf( 'Pipeline complete: %d generated, %d published, %d rejected. Cost: $%.4f', - $r['generated'], $r['published'], $r['rejected'], $r['cost'] + $r['generated'], + $r['published'], + $r['rejected'], + $r['cost'] ), 'pipeline' ); diff --git a/includes/core/class-post-assembler.php b/includes/core/class-post-assembler.php index 6c18eb2..ec779bc 100644 --- a/includes/core/class-post-assembler.php +++ b/includes/core/class-post-assembler.php @@ -21,12 +21,12 @@ class PRAutoBlogger_Post_Assembler { * @param PRAutoBlogger_Article_Idea $idea Article idea with type and keywords. */ public static function assign_taxonomy_terms( int $post_id, PRAutoBlogger_Article_Idea $idea ): void { - $type_category_map = [ + $type_category_map = array( 'guide' => 'Guides', 'solution' => 'Solutions', 'comparison' => 'Comparisons', 'article' => 'Articles', - ]; + ); $category_name = $type_category_map[ $idea->get_article_type() ] ?? 'Articles'; $category = get_term_by( 'name', $category_name, 'category' ); @@ -34,10 +34,10 @@ class PRAutoBlogger_Post_Assembler { if ( ! $category ) { $result = wp_insert_term( $category_name, 'category' ); if ( ! is_wp_error( $result ) ) { - wp_set_post_categories( $post_id, [ $result['term_id'] ] ); + wp_set_post_categories( $post_id, array( $result['term_id'] ) ); } } else { - wp_set_post_categories( $post_id, [ $category->term_id ] ); + wp_set_post_categories( $post_id, array( $category->term_id ) ); } $keywords = $idea->get_target_keywords(); @@ -133,34 +133,37 @@ class PRAutoBlogger_Post_Assembler { return; // No articles produced — nothing to amortize into. } - $total_cost = (float) $research_row->estimated_cost; - $amortized_cost = $total_cost / $post_count; - $total_prompt = (int) $research_row->prompt_tokens; - $total_completion = (int) $research_row->completion_tokens; - $amortized_prompt = (int) round( $total_prompt / $post_count ); - $amortized_compl = (int) round( $total_completion / $post_count ); + $total_cost = (float) $research_row->estimated_cost; + $amortized_cost = $total_cost / $post_count; + $total_prompt = (int) $research_row->prompt_tokens; + $total_completion = (int) $research_row->completion_tokens; + $amortized_prompt = (int) round( $total_prompt / $post_count ); + $amortized_compl = (int) round( $total_completion / $post_count ); // Insert one amortized research row per article. foreach ( $post_ids as $post_id ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery - $wpdb->insert( $table, [ - 'post_id' => (int) $post_id, - 'run_id' => $run_id, - 'stage' => 'llm_research', - 'provider' => $research_row->provider, - 'model' => $research_row->model, - 'prompt_tokens' => $amortized_prompt, - 'completion_tokens' => $amortized_compl, - 'estimated_cost' => $amortized_cost, - 'response_status' => 'success', - 'error_message' => '', - 'created_at' => current_time( 'mysql' ), - ] ); + $wpdb->insert( + $table, + array( + 'post_id' => (int) $post_id, + 'run_id' => $run_id, + 'stage' => 'llm_research', + 'provider' => $research_row->provider, + 'model' => $research_row->model, + 'prompt_tokens' => $amortized_prompt, + 'completion_tokens' => $amortized_compl, + 'estimated_cost' => $amortized_cost, + 'response_status' => 'success', + 'error_message' => '', + 'created_at' => current_time( 'mysql' ), + ) + ); } // Remove the original unlinked row — it's been replaced by per-article rows. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery - $wpdb->delete( $table, [ 'id' => (int) $research_row->id ] ); + $wpdb->delete( $table, array( 'id' => (int) $research_row->id ) ); PRAutoBlogger_Logger::instance()->info( sprintf( @@ -213,7 +216,13 @@ class PRAutoBlogger_Post_Assembler { return $author_id; } - $admins = get_users( [ 'role' => 'administrator', 'number' => 1, 'fields' => 'ID' ] ); + $admins = get_users( + array( + 'role' => 'administrator', + 'number' => 1, + 'fields' => 'ID', + ) + ); return ! empty( $admins ) ? (int) $admins[0] : 1; } diff --git a/includes/core/class-publisher.php b/includes/core/class-publisher.php index 74f7119..b011a98 100755 --- a/includes/core/class-publisher.php +++ b/includes/core/class-publisher.php @@ -81,14 +81,14 @@ class PRAutoBlogger_Publisher { $clean_content = PRAutoBlogger_Post_Assembler::sanitize_llm_content( $content ); $linked_content = PRAutoBlogger_Peptide_Linker::inject_links( $clean_content ); - $post_data = [ + $post_data = array( 'post_title' => sanitize_text_field( $idea->get_suggested_title() ), 'post_content' => wp_kses_post( $linked_content ), 'post_status' => $post_status, 'post_type' => 'post', 'post_author' => PRAutoBlogger_Post_Assembler::get_default_author_id(), 'meta_input' => $this->build_meta( $idea, $review, $run_id ), - ]; + ); /** @see class-prautoblogger.php — listeners registered in main loader. */ $post_data = apply_filters( 'prautoblogger_filter_post_data', $post_data, $idea, $review ); @@ -135,7 +135,7 @@ class PRAutoBlogger_Publisher { PRAutoBlogger_Editorial_Review $review, ?string $run_id = null ): array { - $meta = [ + $meta = array( '_prautoblogger_generated' => '1', '_prautoblogger_analysis_id' => $idea->get_analysis_id(), '_prautoblogger_source_ids' => wp_json_encode( $idea->get_source_ids() ), @@ -149,7 +149,7 @@ class PRAutoBlogger_Publisher { '_prautoblogger_topic' => $idea->get_topic(), '_prautoblogger_article_type' => $idea->get_article_type(), '_prautoblogger_target_keywords' => wp_json_encode( $idea->get_target_keywords() ), - ]; + ); if ( null !== $run_id && '' !== $run_id ) { $meta['_prautoblogger_run_id'] = $run_id; } diff --git a/includes/core/class-research-reaper.php b/includes/core/class-research-reaper.php index 28ff000..9f147e2 100644 --- a/includes/core/class-research-reaper.php +++ b/includes/core/class-research-reaper.php @@ -63,7 +63,11 @@ class PRAutoBlogger_Research_Reaper { * @return array{reaped: int, deleted: int, skipped: int} */ public static function reap(): array { - $stats = [ 'reaped' => 0, 'deleted' => 0, 'skipped' => 0 ]; + $stats = array( + 'reaped' => 0, + 'deleted' => 0, + 'skipped' => 0, + ); try { global $wpdb; @@ -115,10 +119,10 @@ class PRAutoBlogger_Research_Reaper { if ( '' === $run_id ) { if ( $is_stale ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery - $wpdb->delete( $log_table, [ 'id' => (int) $orphan->id ] ); - $stats['deleted']++; + $wpdb->delete( $log_table, array( 'id' => (int) $orphan->id ) ); + ++$stats['deleted']; } else { - $stats['skipped']++; + ++$stats['skipped']; } return; } @@ -130,22 +134,22 @@ class PRAutoBlogger_Research_Reaper { sprintf( 'Reaped research cost across %d articles for run %s.', count( $post_ids ), $run_id ), 'cost-tracker' ); - $stats['reaped']++; + ++$stats['reaped']; return; } if ( $is_stale ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery - $wpdb->delete( $log_table, [ 'id' => (int) $orphan->id ] ); + $wpdb->delete( $log_table, array( 'id' => (int) $orphan->id ) ); PRAutoBlogger_Logger::instance()->info( sprintf( 'Deleted 7-day-stale orphan research row for run %s — no articles to attribute.', $run_id ), 'cost-tracker' ); - $stats['deleted']++; + ++$stats['deleted']; return; } - $stats['skipped']++; + ++$stats['skipped']; } /** @@ -156,15 +160,17 @@ class PRAutoBlogger_Research_Reaper { * @return int[] Distinct post IDs. */ private static function find_posts_for_run_id( string $run_id ): array { - $meta_ids = get_posts( [ - 'post_type' => 'any', - 'post_status' => 'any', - 'meta_key' => '_prautoblogger_run_id', - 'meta_value' => $run_id, - 'fields' => 'ids', - 'posts_per_page' => -1, - 'suppress_filters' => true, - ] ); + $meta_ids = get_posts( + array( + 'post_type' => 'any', + 'post_status' => 'any', + 'meta_key' => '_prautoblogger_run_id', + 'meta_value' => $run_id, + 'fields' => 'ids', + 'posts_per_page' => -1, + 'suppress_filters' => true, + ) + ); if ( is_array( $meta_ids ) && ! empty( $meta_ids ) ) { return array_map( 'intval', $meta_ids ); } @@ -178,6 +184,6 @@ class PRAutoBlogger_Research_Reaper { $run_id ) ); - return is_array( $ids ) ? array_map( 'intval', $ids ) : []; + return is_array( $ids ) ? array_map( 'intval', $ids ) : array(); } } diff --git a/includes/core/class-semantic-dedup.php b/includes/core/class-semantic-dedup.php index 3167fb3..7580ed7 100644 --- a/includes/core/class-semantic-dedup.php +++ b/includes/core/class-semantic-dedup.php @@ -24,13 +24,13 @@ class PRAutoBlogger_Semantic_Dedup { private const SIMILARITY_THRESHOLD = 0.72; /** @var float[][] Cached embeddings for recent post titles, keyed by index. */ - private array $title_embeddings = []; + private array $title_embeddings = array(); /** @var string[] Recent post titles. */ - private array $recent_titles = []; + private array $recent_titles = array(); /** @var float[][] Cached embeddings for accepted ideas, accumulated per-batch. */ - private array $accepted_embeddings = []; + private array $accepted_embeddings = array(); /** @var bool Whether embeddings are available (false after API failure). */ private bool $embeddings_available = true; @@ -158,7 +158,7 @@ class PRAutoBlogger_Semantic_Dedup { if ( null === $this->provider ) { $this->provider = new PRAutoBlogger_OpenRouter_Embedding_Provider(); } - $result = $this->provider->get_embeddings( [ $text ] ); + $result = $this->provider->get_embeddings( array( $text ) ); return $result[0] ?? null; } catch ( \Throwable $e ) { // Degrade gracefully — one failed embed shouldn't kill the pipeline. @@ -220,18 +220,20 @@ class PRAutoBlogger_Semantic_Dedup { * @return string[] */ private function fetch_recent_post_titles(): array { - $query = new \WP_Query( [ - 'post_type' => 'post', - 'post_status' => [ 'publish', 'draft', 'pending' ], - 'meta_key' => '_prautoblogger_generated', - 'meta_value' => '1', - 'date_query' => [ [ 'after' => '30 days ago' ] ], - 'posts_per_page' => 100, - 'fields' => 'ids', - 'no_found_rows' => true, - ] ); + $query = new \WP_Query( + array( + 'post_type' => 'post', + 'post_status' => array( 'publish', 'draft', 'pending' ), + 'meta_key' => '_prautoblogger_generated', + 'meta_value' => '1', + 'date_query' => array( array( 'after' => '30 days ago' ) ), + 'posts_per_page' => 100, + 'fields' => 'ids', + 'no_found_rows' => true, + ) + ); - $titles = []; + $titles = array(); foreach ( $query->posts as $post_id ) { $titles[] = get_the_title( $post_id ); } @@ -245,27 +247,122 @@ class PRAutoBlogger_Semantic_Dedup { * @return string[] Unique lowercase keywords. */ private function extract_meaningful_keywords( string $text ): array { - static $stopwords = [ - 'a', 'an', 'the', 'and', 'or', 'but', 'is', 'are', 'was', 'were', - 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'from', 'as', - 'it', 'its', 'this', 'that', 'your', 'you', 'how', 'what', 'when', - 'why', 'where', 'which', 'who', 'do', 'does', 'did', 'not', 'no', - 'can', 'will', 'should', 'could', 'would', 'may', 'might', 'have', - 'has', 'had', 'be', 'been', 'being', 'about', 'into', 'through', - 'during', 'before', 'after', 'above', 'below', 'between', 'same', - 'up', 'down', 'out', 'off', 'over', 'under', 'again', 'then', - 'here', 'there', 'all', 'each', 'every', 'both', 'few', 'more', - 'most', 'other', 'some', 'such', 'than', 'too', 'very', 'just', - 'also', 'only', 'own', 'so', 'if', 'while', 'because', 'until', - 'vs', 'versus', 'guide', 'complete', 'ultimate', 'best', 'top', - 'new', 'first', 'need', 'know', 'everything', - ]; + static $stopwords = array( + 'a', + 'an', + 'the', + 'and', + 'or', + 'but', + 'is', + 'are', + 'was', + 'were', + 'in', + 'on', + 'at', + 'to', + 'for', + 'of', + 'with', + 'by', + 'from', + 'as', + 'it', + 'its', + 'this', + 'that', + 'your', + 'you', + 'how', + 'what', + 'when', + 'why', + 'where', + 'which', + 'who', + 'do', + 'does', + 'did', + 'not', + 'no', + 'can', + 'will', + 'should', + 'could', + 'would', + 'may', + 'might', + 'have', + 'has', + 'had', + 'be', + 'been', + 'being', + 'about', + 'into', + 'through', + 'during', + 'before', + 'after', + 'above', + 'below', + 'between', + 'same', + 'up', + 'down', + 'out', + 'off', + 'over', + 'under', + 'again', + 'then', + 'here', + 'there', + 'all', + 'each', + 'every', + 'both', + 'few', + 'more', + 'most', + 'other', + 'some', + 'such', + 'than', + 'too', + 'very', + 'just', + 'also', + 'only', + 'own', + 'so', + 'if', + 'while', + 'because', + 'until', + 'vs', + 'versus', + 'guide', + 'complete', + 'ultimate', + 'best', + 'top', + 'new', + 'first', + 'need', + 'know', + 'everything', + ); $text = strtolower( $text ); $words = preg_split( '/[^a-z0-9-]+/', $text, -1, PREG_SPLIT_NO_EMPTY ); - $words = array_filter( $words, static function ( string $w ) use ( $stopwords ): bool { - return strlen( $w ) >= 2 && ! in_array( $w, $stopwords, true ); - } ); + $words = array_filter( + $words, + static function ( string $w ) use ( $stopwords ): bool { + return strlen( $w ) >= 2 && ! in_array( $w, $stopwords, true ); + } + ); return array_values( array_unique( $words ) ); } diff --git a/includes/core/class-source-collector.php b/includes/core/class-source-collector.php index 672446a..ce25a0e 100755 --- a/includes/core/class-source-collector.php +++ b/includes/core/class-source-collector.php @@ -51,7 +51,7 @@ class PRAutoBlogger_Source_Collector { // Only fall back to reddit if the option is corrupt (non-JSON). // An empty array '[]' is a valid choice — the user disabled all sources. if ( ! is_array( $enabled ) ) { - $enabled = [ 'reddit' ]; + $enabled = array( 'reddit' ); } $total_inserted = 0; @@ -64,9 +64,9 @@ class PRAutoBlogger_Source_Collector { } try { - $data = $provider->collect_data( $this->get_config_for_source( $source_type ) ); - $inserted = $this->store_data( $data ); - $refreshed = count( $data ) - $inserted; + $data = $provider->collect_data( $this->get_config_for_source( $source_type ) ); + $inserted = $this->store_data( $data ); + $refreshed = count( $data ) - $inserted; $total_inserted += $inserted; PRAutoBlogger_Logger::instance()->info( @@ -117,10 +117,10 @@ class PRAutoBlogger_Source_Collector { return null; } - return [ + return array( 'title' => $row['title'] ?? 'Reddit Discussion', 'selftext' => $row['content'] ?? '', - ]; + ); } /** @@ -175,7 +175,7 @@ class PRAutoBlogger_Source_Collector { // ON DUPLICATE KEY UPDATE returns 2 for updates, 1 for inserts. // Only count genuine inserts toward the "new" tally. if ( false !== $result && 1 === (int) $result ) { - $inserted++; + ++$inserted; } } @@ -190,10 +190,10 @@ class PRAutoBlogger_Source_Collector { * @return PRAutoBlogger_Source_Provider_Interface|null */ private function get_provider( string $source_type ): ?PRAutoBlogger_Source_Provider_Interface { - $providers = [ + $providers = array( 'reddit' => PRAutoBlogger_Reddit_Provider::class, 'llm_research' => PRAutoBlogger_LLM_Research_Provider::class, - ]; + ); /** * Filter the registered source providers. @@ -230,20 +230,20 @@ class PRAutoBlogger_Source_Collector { */ private function get_config_for_source( string $source_type ): array { if ( 'reddit' === $source_type ) { - return [ - 'subreddits' => json_decode( get_option( 'prautoblogger_target_subreddits', '[]' ), true ) ?: [], + return array( + 'subreddits' => json_decode( get_option( 'prautoblogger_target_subreddits', '[]' ), true ) ?: array(), 'limit' => 25, 'time_filter' => 'day', 'include_comments' => true, 'comments_per_post' => 10, - ]; + ); } if ( 'llm_research' === $source_type ) { - $config = [ + $config = array( 'model' => get_option( 'prautoblogger_research_model', PRAUTOBLOGGER_DEFAULT_ANALYSIS_MODEL ), 'prompt' => get_option( 'prautoblogger_research_prompt', '' ), - ]; + ); // Pass the pipeline's cost tracker so research costs get tagged // with the run_id for post-pipeline amortization across articles. if ( null !== $this->cost_tracker ) { @@ -252,6 +252,6 @@ class PRAutoBlogger_Source_Collector { return $config; } - return []; + return array(); } } diff --git a/includes/frontend/class-article-typography.php b/includes/frontend/class-article-typography.php index 424c70e..e4f7ada 100644 --- a/includes/frontend/class-article-typography.php +++ b/includes/frontend/class-article-typography.php @@ -63,7 +63,7 @@ class PRAutoBlogger_Article_Typography { * @return string CSS rules, or empty string if all defaults. */ private function build_css(): string { - $rules = []; + $rules = array(); $font_family = $this->get_font_family_stack(); if ( '' !== $font_family ) { @@ -84,60 +84,66 @@ class PRAutoBlogger_Article_Typography { // Restore bullet points — the theme's global reset strips // list-style from all ul/ol, which removes bullets from article // content. This re-applies them inside .entry-content only. - $rules[] = implode( "\n", [ - '.entry-content ul {', - "\tlist-style: disc;", - "\tpadding-left: 1.5em;", - "\tmargin: 1em 0;", - '}', - '.entry-content ol {', - "\tlist-style: decimal;", - "\tpadding-left: 1.5em;", - "\tmargin: 1em 0;", - '}', - '.entry-content li {', - "\tmargin-bottom: 0.4em;", - '}', - ] ); + $rules[] = implode( + "\n", + array( + '.entry-content ul {', + "\tlist-style: disc;", + "\tpadding-left: 1.5em;", + "\tmargin: 1em 0;", + '}', + '.entry-content ol {', + "\tlist-style: decimal;", + "\tpadding-left: 1.5em;", + "\tmargin: 1em 0;", + '}', + '.entry-content li {', + "\tmargin-bottom: 0.4em;", + '}', + ) + ); $table_borders = get_option( self::OPT_TABLE_BORDERS, '1' ); if ( '1' === $table_borders ) { // Uses theme CSS custom properties for dark mode compatibility. // --color-border-default, --color-bg-secondary, --color-bg-primary, // --color-text-primary are set by PR Theme for both light and dark. - $rules[] = implode( "\n", [ - '.entry-content .prab-table-wrap {', - "\toverflow-x: auto;", - "\t-webkit-overflow-scrolling: touch;", - "\tmargin: 1.5em 0;", - '}', - '.entry-content table {', - "\tborder-collapse: collapse;", - "\twidth: 100%;", - "\tmin-width: 480px;", - '}', - '.entry-content th,', - '.entry-content td {', - "\tborder: 1px solid var(--color-border-default, #d1d5db);", - "\tpadding: 0.6em 1em;", - "\ttext-align: left;", - "\tcolor: var(--color-text-primary, #111827);", - '}', - '.entry-content thead th {', - "\tbackground: var(--color-bg-secondary, #f3f4f6);", - "\tfont-weight: 600;", - '}', - '.entry-content tbody tr:nth-child(even) {', - "\tbackground: var(--color-bg-secondary, #f9fafb);", - '}', - '@media (max-width: 600px) {', - "\t.entry-content th,", - "\t.entry-content td {", - "\t\tpadding: 0.4em 0.6em;", - "\t\tfont-size: 14px;", - "\t}", - '}', - ] ); + $rules[] = implode( + "\n", + array( + '.entry-content .prab-table-wrap {', + "\toverflow-x: auto;", + "\t-webkit-overflow-scrolling: touch;", + "\tmargin: 1.5em 0;", + '}', + '.entry-content table {', + "\tborder-collapse: collapse;", + "\twidth: 100%;", + "\tmin-width: 480px;", + '}', + '.entry-content th,', + '.entry-content td {', + "\tborder: 1px solid var(--color-border-default, #d1d5db);", + "\tpadding: 0.6em 1em;", + "\ttext-align: left;", + "\tcolor: var(--color-text-primary, #111827);", + '}', + '.entry-content thead th {', + "\tbackground: var(--color-bg-secondary, #f3f4f6);", + "\tfont-weight: 600;", + '}', + '.entry-content tbody tr:nth-child(even) {', + "\tbackground: var(--color-bg-secondary, #f9fafb);", + '}', + '@media (max-width: 600px) {', + "\t.entry-content th,", + "\t.entry-content td {", + "\t\tpadding: 0.4em 0.6em;", + "\t\tfont-size: 14px;", + "\t}", + '}', + ) + ); } return implode( "\n\n", $rules ); @@ -153,16 +159,16 @@ class PRAutoBlogger_Article_Typography { private function get_font_family_stack(): string { $key = sanitize_text_field( get_option( self::OPT_FONT_FAMILY, 'default' ) ); - $stacks = [ - 'default' => '', - 'inter' => '"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', - 'georgia' => '"Georgia", "Times New Roman", Times, serif', + $stacks = array( + 'default' => '', + 'inter' => '"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', + 'georgia' => '"Georgia", "Times New Roman", Times, serif', 'merriweather' => '"Merriweather", Georgia, "Times New Roman", serif', - 'lora' => '"Lora", Georgia, "Times New Roman", serif', - 'open_sans' => '"Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', - 'roboto' => '"Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', - 'system' => '-apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", sans-serif', - ]; + 'lora' => '"Lora", Georgia, "Times New Roman", serif', + 'open_sans' => '"Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', + 'roboto' => '"Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', + 'system' => '-apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", sans-serif', + ); return $stacks[ $key ] ?? ''; } @@ -173,7 +179,7 @@ class PRAutoBlogger_Article_Typography { * @return array Map of key => display label. */ public static function get_font_choices(): array { - return [ + return array( 'default' => __( 'Theme Default (Inter)', 'prautoblogger' ), 'inter' => __( 'Inter (Sans-serif)', 'prautoblogger' ), 'georgia' => __( 'Georgia (Serif)', 'prautoblogger' ), @@ -182,7 +188,7 @@ class PRAutoBlogger_Article_Typography { 'open_sans' => __( 'Open Sans (Sans-serif)', 'prautoblogger' ), 'roboto' => __( 'Roboto (Sans-serif)', 'prautoblogger' ), 'system' => __( 'System Default', 'prautoblogger' ), - ]; + ); } /** @@ -202,18 +208,18 @@ class PRAutoBlogger_Article_Typography { $font = sanitize_text_field( get_option( self::OPT_FONT_FAMILY, 'default' ) ); // Map font keys to Google Fonts URLs. Inter is already loaded by the theme. - $google_fonts = [ + $google_fonts = array( 'merriweather' => 'https://fonts.googleapis.com/css2?family=Merriweather:wght@400;700&display=swap', 'lora' => 'https://fonts.googleapis.com/css2?family=Lora:wght@400;700&display=swap', 'open_sans' => 'https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap', 'roboto' => 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap', - ]; + ); if ( isset( $google_fonts[ $font ] ) ) { wp_enqueue_style( 'prautoblogger-google-font', $google_fonts[ $font ], - [], + array(), null // No version for external CDN URLs. ); } diff --git a/includes/frontend/class-posts-widget.php b/includes/frontend/class-posts-widget.php index d89d591..dd7cb1a 100644 --- a/includes/frontend/class-posts-widget.php +++ b/includes/frontend/class-posts-widget.php @@ -43,7 +43,7 @@ class PRAutoBlogger_Posts_Widget { * @return void */ public function on_register_shortcode(): void { - add_shortcode( 'prautoblogger_posts', [ $this, 'render_shortcode' ] ); + add_shortcode( 'prautoblogger_posts', array( $this, 'render_shortcode' ) ); } /** @@ -59,9 +59,9 @@ class PRAutoBlogger_Posts_Widget { register_rest_route( self::REST_NAMESPACE, self::REST_ROUTE, - [ + array( 'methods' => \WP_REST_Server::READABLE, - 'callback' => [ $this, 'handle_rest_request' ], + 'callback' => array( $this, 'handle_rest_request' ), 'permission_callback' => function () { /** * Filter whether the posts widget REST endpoint is publicly accessible. @@ -73,21 +73,21 @@ class PRAutoBlogger_Posts_Widget { */ return (bool) apply_filters( 'prautoblogger_rest_posts_public', true ); }, - 'args' => [ - 'per_page' => [ + 'args' => array( + 'per_page' => array( 'type' => 'integer', 'default' => 6, 'minimum' => 1, 'maximum' => self::MAX_POSTS_PER_REQUEST, 'sanitize_callback' => 'absint', - ], - 'category' => [ + ), + 'category' => array( 'type' => 'string', 'default' => '', 'sanitize_callback' => 'sanitize_text_field', - ], - ], - ] + ), + ), + ) ); } @@ -109,12 +109,12 @@ class PRAutoBlogger_Posts_Widget { */ public function render_shortcode( $atts ): string { $atts = shortcode_atts( - [ + array( 'count' => '6', 'category' => '', 'title' => __( 'Latest Research & Insights', 'prautoblogger' ), 'subtitle' => __( 'Evidence-based articles on peptides, protocols, and emerging research', 'prautoblogger' ), - ], + ), $atts, 'prautoblogger_posts' ); @@ -148,14 +148,14 @@ class PRAutoBlogger_Posts_Widget { wp_enqueue_style( 'prautoblogger-posts-widget', PRAUTOBLOGGER_PLUGIN_URL . 'assets/css/posts-widget.css', - [], + array(), $version ); wp_enqueue_script( 'prautoblogger-posts-widget', PRAUTOBLOGGER_PLUGIN_URL . 'assets/js/posts-widget.js', - [ 'wp-element' ], // WordPress-bundled React. + array( 'wp-element' ), // WordPress-bundled React. $version, true // Load in footer for performance. ); @@ -163,14 +163,14 @@ class PRAutoBlogger_Posts_Widget { wp_localize_script( 'prautoblogger-posts-widget', 'prabPostsWidget', - [ + array( 'restUrl' => esc_url_raw( rest_url( self::REST_NAMESPACE . self::REST_ROUTE ) ), 'count' => $count, 'category' => sanitize_text_field( $atts['category'] ), 'title' => sanitize_text_field( $atts['title'] ), 'subtitle' => sanitize_text_field( $atts['subtitle'] ), 'archiveUrl' => esc_url( get_post_type_archive_link( 'post' ) ?: '' ), - ] + ) ); } @@ -191,19 +191,19 @@ class PRAutoBlogger_Posts_Widget { } $category = sanitize_text_field( $request->get_param( 'category' ) ?? '' ); - $query_args = [ + $query_args = array( 'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => $per_page, 'orderby' => 'date', 'order' => 'DESC', - 'meta_query' => [ - [ + 'meta_query' => array( + array( 'key' => '_prautoblogger_generated', 'value' => '1', - ], - ], - ]; + ), + ), + ); // Optional category filter. if ( ! empty( $category ) ) { @@ -211,7 +211,7 @@ class PRAutoBlogger_Posts_Widget { } $query = new \WP_Query( $query_args ); - $posts = []; + $posts = array(); foreach ( $query->posts as $post ) { $posts[] = $this->format_post_for_response( $post ); @@ -249,7 +249,7 @@ class PRAutoBlogger_Posts_Widget { $title = html_entity_decode( get_the_title( $post ), ENT_QUOTES | ENT_HTML5, 'UTF-8' ); $excerpt = html_entity_decode( get_the_excerpt( $post ), ENT_QUOTES | ENT_HTML5, 'UTF-8' ); - return [ + return array( 'id' => $post->ID, 'title' => $title, 'excerpt' => $excerpt, @@ -259,6 +259,6 @@ class PRAutoBlogger_Posts_Widget { 'category_slug' => $category_slug, 'featured_image' => $featured_image ?: '', 'word_count' => $word_count, - ]; + ); } } diff --git a/includes/models/class-analysis-result.php b/includes/models/class-analysis-result.php index eab87c2..d272493 100755 --- a/includes/models/class-analysis-result.php +++ b/includes/models/class-analysis-result.php @@ -43,7 +43,7 @@ class PRAutoBlogger_Analysis_Result { $this->summary = $data['summary'] ?? null; $this->frequency = (int) ( $data['frequency'] ?? 1 ); $this->relevance_score = (float) ( $data['relevance_score'] ?? 0.0 ); - $this->source_ids = $data['source_ids'] ?? []; + $this->source_ids = $data['source_ids'] ?? array(); $this->analyzed_at = $data['analyzed_at'] ?? current_time( 'mysql' ); $this->metadata = $data['metadata'] ?? null; } @@ -88,7 +88,7 @@ class PRAutoBlogger_Analysis_Result { * @return array */ public function to_db_row(): array { - return [ + return array( 'analysis_type' => $this->analysis_type, 'topic' => $this->topic, 'summary' => $this->summary, @@ -97,6 +97,6 @@ class PRAutoBlogger_Analysis_Result { 'source_ids_json' => wp_json_encode( $this->source_ids ), 'analyzed_at' => $this->analyzed_at, 'metadata_json' => null !== $this->metadata ? wp_json_encode( $this->metadata ) : null, - ]; + ); } } diff --git a/includes/models/class-article-idea.php b/includes/models/class-article-idea.php index af95b98..d134f7f 100755 --- a/includes/models/class-article-idea.php +++ b/includes/models/class-article-idea.php @@ -38,15 +38,15 @@ class PRAutoBlogger_Article_Idea { * } $data */ public function __construct( array $data ) { - $this->topic = $data['topic']; - $this->article_type = $data['article_type']; - $this->suggested_title = $data['suggested_title']; - $this->summary = $data['summary']; - $this->score = (float) ( $data['score'] ?? 0.0 ); - $this->analysis_id = (int) ( $data['analysis_id'] ?? 0 ); - $this->source_ids = $data['source_ids'] ?? []; - $this->key_points = $data['key_points'] ?? []; - $this->target_keywords = $data['target_keywords'] ?? []; + $this->topic = $data['topic']; + $this->article_type = $data['article_type']; + $this->suggested_title = $data['suggested_title']; + $this->summary = $data['summary']; + $this->score = (float) ( $data['score'] ?? 0.0 ); + $this->analysis_id = (int) ( $data['analysis_id'] ?? 0 ); + $this->source_ids = $data['source_ids'] ?? array(); + $this->key_points = $data['key_points'] ?? array(); + $this->target_keywords = $data['target_keywords'] ?? array(); } public function get_topic(): string { @@ -93,7 +93,7 @@ class PRAutoBlogger_Article_Idea { * @return array Constructor-compatible array. */ public function to_array(): array { - return [ + return array( 'topic' => $this->topic, 'article_type' => $this->article_type, 'suggested_title' => $this->suggested_title, @@ -103,6 +103,6 @@ class PRAutoBlogger_Article_Idea { 'source_ids' => $this->source_ids, 'key_points' => $this->key_points, 'target_keywords' => $this->target_keywords, - ]; + ); } } diff --git a/includes/models/class-content-request.php b/includes/models/class-content-request.php index 5ee90ef..3726d01 100755 --- a/includes/models/class-content-request.php +++ b/includes/models/class-content-request.php @@ -30,7 +30,7 @@ class PRAutoBlogger_Content_Request { int $min_word_count, int $max_word_count, string $niche_description, - array $topic_exclusions = [], + array $topic_exclusions = array(), string $writing_instructions = '' ) { $this->idea = $idea; diff --git a/includes/models/class-content-score.php b/includes/models/class-content-score.php index 6260dee..7fd9d65 100755 --- a/includes/models/class-content-score.php +++ b/includes/models/class-content-score.php @@ -37,21 +37,30 @@ class PRAutoBlogger_Content_Score { $this->measured_at = $data['measured_at'] ?? current_time( 'mysql' ); } - public function get_id(): int { return $this->id; } - public function get_post_id(): int { return $this->post_id; } - public function get_pageviews(): int { return $this->pageviews; } - public function get_avg_time_on_page(): float { return $this->avg_time_on_page; } - public function get_bounce_rate(): float { return $this->bounce_rate; } - public function get_comment_count(): int { return $this->comment_count; } - public function get_composite_score(): float { return $this->composite_score; } - public function get_score_factors(): ?array { return $this->score_factors; } - public function get_measured_at(): string { return $this->measured_at; } + public function get_id(): int { + return $this->id; } + public function get_post_id(): int { + return $this->post_id; } + public function get_pageviews(): int { + return $this->pageviews; } + public function get_avg_time_on_page(): float { + return $this->avg_time_on_page; } + public function get_bounce_rate(): float { + return $this->bounce_rate; } + public function get_comment_count(): int { + return $this->comment_count; } + public function get_composite_score(): float { + return $this->composite_score; } + public function get_score_factors(): ?array { + return $this->score_factors; } + public function get_measured_at(): string { + return $this->measured_at; } /** * @return array */ public function to_db_row(): array { - return [ + return array( 'post_id' => $this->post_id, 'pageviews' => $this->pageviews, 'avg_time_on_page' => $this->avg_time_on_page, @@ -60,6 +69,6 @@ class PRAutoBlogger_Content_Score { 'composite_score' => $this->composite_score, 'score_factors_json' => null !== $this->score_factors ? wp_json_encode( $this->score_factors ) : null, 'measured_at' => $this->measured_at, - ]; + ); } } diff --git a/includes/models/class-editorial-review.php b/includes/models/class-editorial-review.php index 7c433d0..55630cc 100755 --- a/includes/models/class-editorial-review.php +++ b/includes/models/class-editorial-review.php @@ -30,12 +30,12 @@ class PRAutoBlogger_Editorial_Review { * } $data */ public function __construct( array $data ) { - $this->verdict = $data['verdict']; // 'approved', 'revised', 'rejected' - $this->notes = $data['notes']; - $this->revised_content = $data['revised_content'] ?? null; - $this->quality_score = (float) ( $data['quality_score'] ?? 0.0 ); - $this->seo_score = (float) ( $data['seo_score'] ?? 0.0 ); - $this->issues = $data['issues'] ?? []; + $this->verdict = $data['verdict']; // 'approved', 'revised', 'rejected' + $this->notes = $data['notes']; + $this->revised_content = $data['revised_content'] ?? null; + $this->quality_score = (float) ( $data['quality_score'] ?? 0.0 ); + $this->seo_score = (float) ( $data['seo_score'] ?? 0.0 ); + $this->issues = $data['issues'] ?? array(); } public function get_verdict(): string { diff --git a/includes/models/class-generation-log.php b/includes/models/class-generation-log.php index d78b68a..f9fd5c5 100755 --- a/includes/models/class-generation-log.php +++ b/includes/models/class-generation-log.php @@ -45,25 +45,38 @@ class PRAutoBlogger_Generation_Log { $this->created_at = $data['created_at'] ?? current_time( 'mysql' ); } - public function get_id(): int { return $this->id; } - public function get_post_id(): ?int { return $this->post_id; } - public function get_run_id(): ?string { return $this->run_id; } - public function get_stage(): string { return $this->stage; } - public function get_provider(): string { return $this->provider; } - public function get_model(): string { return $this->model; } - public function get_prompt_tokens(): int { return $this->prompt_tokens; } - public function get_completion_tokens(): int { return $this->completion_tokens; } - public function get_estimated_cost(): float { return $this->estimated_cost; } - public function get_request_json(): ?string { return $this->request_json; } - public function get_response_status(): string { return $this->response_status; } - public function get_error_message(): ?string { return $this->error_message; } - public function get_created_at(): string { return $this->created_at; } + public function get_id(): int { + return $this->id; } + public function get_post_id(): ?int { + return $this->post_id; } + public function get_run_id(): ?string { + return $this->run_id; } + public function get_stage(): string { + return $this->stage; } + public function get_provider(): string { + return $this->provider; } + public function get_model(): string { + return $this->model; } + public function get_prompt_tokens(): int { + return $this->prompt_tokens; } + public function get_completion_tokens(): int { + return $this->completion_tokens; } + public function get_estimated_cost(): float { + return $this->estimated_cost; } + public function get_request_json(): ?string { + return $this->request_json; } + public function get_response_status(): string { + return $this->response_status; } + public function get_error_message(): ?string { + return $this->error_message; } + public function get_created_at(): string { + return $this->created_at; } /** * @return array */ public function to_db_row(): array { - return [ + return array( 'post_id' => $this->post_id, 'run_id' => $this->run_id, 'stage' => $this->stage, @@ -76,6 +89,6 @@ class PRAutoBlogger_Generation_Log { 'response_status' => $this->response_status, 'error_message' => $this->error_message, 'created_at' => $this->created_at, - ]; + ); } } diff --git a/includes/models/class-source-data.php b/includes/models/class-source-data.php index f812e9d..b52662f 100755 --- a/includes/models/class-source-data.php +++ b/includes/models/class-source-data.php @@ -111,7 +111,7 @@ class PRAutoBlogger_Source_Data { * @return array */ public function to_db_row(): array { - return [ + return array( 'source_type' => $this->source_type, 'source_id' => $this->source_id, 'subreddit' => $this->subreddit, @@ -123,6 +123,6 @@ class PRAutoBlogger_Source_Data { 'permalink' => $this->permalink, 'collected_at' => $this->collected_at, 'metadata_json' => null !== $this->metadata ? wp_json_encode( $this->metadata ) : null, - ]; + ); } } diff --git a/includes/providers/class-llm-research-provider.php b/includes/providers/class-llm-research-provider.php index b42318f..52495af 100644 --- a/includes/providers/class-llm-research-provider.php +++ b/includes/providers/class-llm-research-provider.php @@ -45,7 +45,7 @@ class PRAutoBlogger_LLM_Research_Provider implements PRAutoBlogger_Source_Provid if ( '' === trim( $prompt ) ) { PRAutoBlogger_Logger::instance()->warning( 'LLM Research prompt is empty. Skipping.', 'llm-research' ); - return []; + return array(); } $system_prompt = $this->build_system_prompt(); @@ -53,16 +53,22 @@ class PRAutoBlogger_LLM_Research_Provider implements PRAutoBlogger_Source_Provid $llm = new PRAutoBlogger_OpenRouter_Provider(); $response = $llm->send_chat_completion( - [ - [ 'role' => 'system', 'content' => $system_prompt ], - [ 'role' => 'user', 'content' => $user_prompt ], - ], + array( + array( + 'role' => 'system', + 'content' => $system_prompt, + ), + array( + 'role' => 'user', + 'content' => $user_prompt, + ), + ), $model, - [ + array( 'temperature' => 0.7, 'max_tokens' => 8000, - 'response_format' => [ 'type' => 'json_object' ], - ] + 'response_format' => array( 'type' => 'json_object' ), + ) ); // Use the pipeline's cost tracker if provided (for run_id tagging), @@ -102,11 +108,11 @@ class PRAutoBlogger_LLM_Research_Provider implements PRAutoBlogger_Source_Provid * @return array{remaining: int, limit: int, resets_at: string} */ public function get_rate_limit_status(): array { - return [ + return array( 'remaining' => 999, 'limit' => 999, - 'resets_at' => '', - ]; + 'resets_at' => '', + ); } /** @@ -133,7 +139,7 @@ class PRAutoBlogger_LLM_Research_Provider implements PRAutoBlogger_Source_Provid . "Respond with valid JSON only (no preamble, no markdown fences):\n" . '{"findings": [{"title": "string", "content": "string (2-3 paragraphs)", ' . '"relevance_score": 0-100, "category": "question|trend|comparison|guide|misconception|safety"}]}' . "\n\n" - . "Generate 8-12 findings. Prioritize depth over breadth. Avoid generic or surface-level topics."; + . 'Generate 8-12 findings. Prioritize depth over breadth. Avoid generic or surface-level topics.'; } /** @@ -164,16 +170,16 @@ class PRAutoBlogger_LLM_Research_Provider implements PRAutoBlogger_Source_Provid . mb_substr( $content, 0, 500 ), 'llm-research' ); - return []; + return array(); } - $items = []; + $items = array(); $run_date = gmdate( 'Y-m-d' ); foreach ( $data['findings'] as $index => $finding ) { - $title = sanitize_text_field( $finding['title'] ?? '' ); - $body = sanitize_textarea_field( $finding['content'] ?? '' ); - $score = min( 100, max( 0, (int) ( $finding['relevance_score'] ?? 50 ) ) ); + $title = sanitize_text_field( $finding['title'] ?? '' ); + $body = sanitize_textarea_field( $finding['content'] ?? '' ); + $score = min( 100, max( 0, (int) ( $finding['relevance_score'] ?? 50 ) ) ); $category = sanitize_text_field( $finding['category'] ?? 'guide' ); if ( '' === $title || '' === $body ) { @@ -184,23 +190,25 @@ class PRAutoBlogger_LLM_Research_Provider implements PRAutoBlogger_Source_Provid // but a new day produces fresh entries. $source_id = 'llm_' . $run_date . '_' . $index; - $items[] = new PRAutoBlogger_Source_Data( [ - 'source_type' => self::SOURCE_TYPE, - 'source_id' => $source_id, - 'subreddit' => null, - 'title' => $title, - 'content' => $body, - 'author' => $model, - 'score' => $score, - 'comment_count' => 0, - 'permalink' => null, - 'collected_at' => current_time( 'mysql' ), - 'metadata' => [ - 'category' => $category, - 'data_source' => 'llm_research', - 'model' => $model, - ], - ] ); + $items[] = new PRAutoBlogger_Source_Data( + array( + 'source_type' => self::SOURCE_TYPE, + 'source_id' => $source_id, + 'subreddit' => null, + 'title' => $title, + 'content' => $body, + 'author' => $model, + 'score' => $score, + 'comment_count' => 0, + 'permalink' => null, + 'collected_at' => current_time( 'mysql' ), + 'metadata' => array( + 'category' => $category, + 'data_source' => 'llm_research', + 'model' => $model, + ), + ) + ); } PRAutoBlogger_Logger::instance()->info( diff --git a/includes/providers/class-open-router-embedding-provider.php b/includes/providers/class-open-router-embedding-provider.php index 57d6b0f..fb75b6d 100644 --- a/includes/providers/class-open-router-embedding-provider.php +++ b/includes/providers/class-open-router-embedding-provider.php @@ -41,7 +41,7 @@ class PRAutoBlogger_OpenRouter_Embedding_Provider { */ public function get_embeddings( array $texts, string $model = '' ): array { if ( empty( $texts ) ) { - return []; + return array(); } $api_key = $this->get_api_key(); @@ -64,14 +64,16 @@ class PRAutoBlogger_OpenRouter_Embedding_Provider { try { $response = wp_remote_post( $base_url . '/embeddings', - [ + array( 'timeout' => 30, 'headers' => $request_headers, - 'body' => wp_json_encode( [ - 'model' => $model, - 'input' => array_values( $texts ), - ] ), - ] + 'body' => wp_json_encode( + array( + 'model' => $model, + 'input' => array_values( $texts ), + ) + ), + ) ); if ( is_wp_error( $response ) ) { @@ -149,11 +151,14 @@ class PRAutoBlogger_OpenRouter_Embedding_Provider { } // Sort by index to match input order (API may return out of order). - usort( $body['data'], static function ( array $a, array $b ): int { - return ( $a['index'] ?? 0 ) <=> ( $b['index'] ?? 0 ); - } ); + usort( + $body['data'], + static function ( array $a, array $b ): int { + return ( $a['index'] ?? 0 ) <=> ( $b['index'] ?? 0 ); + } + ); - $embeddings = []; + $embeddings = array(); foreach ( $body['data'] as $item ) { if ( ! isset( $item['embedding'] ) || ! is_array( $item['embedding'] ) ) { throw new \RuntimeException( 'Embedding item missing "embedding" array.' ); diff --git a/includes/providers/class-open-router-image-batch.php b/includes/providers/class-open-router-image-batch.php index 5703f5b..0e08b6c 100644 --- a/includes/providers/class-open-router-image-batch.php +++ b/includes/providers/class-open-router-image-batch.php @@ -73,7 +73,7 @@ class PRAutoBlogger_OpenRouter_Image_Batch { */ public function execute( array $requests ): array { if ( empty( $requests ) ) { - return []; + return array(); } $api_key = $this->support->get_api_key(); @@ -86,15 +86,15 @@ class PRAutoBlogger_OpenRouter_Image_Batch { ); // Convert associative headers to curl-style indexed array. - $curl_headers = []; + $curl_headers = array(); foreach ( $headers as $name => $value ) { $curl_headers[] = $name . ': ' . $value; } // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_multi_init $multi_handle = curl_multi_init(); - $handles = []; - $start_times = []; + $handles = array(); + $start_times = array(); foreach ( $requests as $key => $req ) { $model = $this->pricing->resolve_model( (string) ( $req['options']['model'] ?? '' ) ); @@ -119,7 +119,11 @@ class PRAutoBlogger_OpenRouter_Image_Batch { // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_multi_add_handle curl_multi_add_handle( $multi_handle, $ch ); - $handles[ $key ] = [ 'handle' => $ch, 'model' => $model, 'req' => $req ]; + $handles[ $key ] = array( + 'handle' => $ch, + 'model' => $model, + 'req' => $req, + ); $start_times[ $key ] = microtime( true ); } @@ -127,7 +131,7 @@ class PRAutoBlogger_OpenRouter_Image_Batch { $this->run_multi( $multi_handle ); // Collect results. - $results = []; + $results = array(); foreach ( $handles as $key => $entry ) { $results[ $key ] = $this->collect_result( (string) $key, @@ -200,7 +204,7 @@ class PRAutoBlogger_OpenRouter_Image_Batch { $detail ); PRAutoBlogger_Logger::instance()->error( $msg, 'openrouter-image-batch' ); - return [ 'error' => $msg ]; + return array( 'error' => $msg ); } // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_getinfo @@ -216,7 +220,7 @@ class PRAutoBlogger_OpenRouter_Image_Batch { substr( $raw, 0, 300 ) ); PRAutoBlogger_Logger::instance()->error( $msg, 'openrouter-image-batch' ); - return [ 'error' => $msg ]; + return array( 'error' => $msg ); } try { @@ -228,10 +232,10 @@ class PRAutoBlogger_OpenRouter_Image_Batch { $e->getMessage() ); PRAutoBlogger_Logger::instance()->error( $msg, 'openrouter-image-batch' ); - return [ 'error' => $msg ]; + return array( 'error' => $msg ); } - return [ + return array( 'bytes' => $image_bytes, 'mime_type' => 'image/png', 'width' => $req['width'], @@ -240,7 +244,7 @@ class PRAutoBlogger_OpenRouter_Image_Batch { 'seed' => null, 'cost_usd' => $this->pricing->estimate_cost( $req['width'], $req['height'], $model ), 'latency_ms' => $latency_ms, - ]; + ); } /** @@ -259,17 +263,45 @@ class PRAutoBlogger_OpenRouter_Image_Batch { $target = $height > 0 ? (float) $width / (float) $height : 1.0; // Snap to nearest standard aspect ratio. - $aspects = [ - [ 'w' => 1, 'h' => 1, 'r' => 1.0 ], - [ 'w' => 3, 'h' => 2, 'r' => 1.5 ], - [ 'w' => 2, 'h' => 3, 'r' => 0.6667 ], - [ 'w' => 4, 'h' => 3, 'r' => 1.3333 ], - [ 'w' => 3, 'h' => 4, 'r' => 0.75 ], - [ 'w' => 16, 'h' => 9, 'r' => 1.7778 ], - [ 'w' => 9, 'h' => 16, 'r' => 0.5625 ], - ]; - $best = $aspects[0]; - $best_d = abs( $target - $best['r'] ); + $aspects = array( + array( + 'w' => 1, + 'h' => 1, + 'r' => 1.0, + ), + array( + 'w' => 3, + 'h' => 2, + 'r' => 1.5, + ), + array( + 'w' => 2, + 'h' => 3, + 'r' => 0.6667, + ), + array( + 'w' => 4, + 'h' => 3, + 'r' => 1.3333, + ), + array( + 'w' => 3, + 'h' => 4, + 'r' => 0.75, + ), + array( + 'w' => 16, + 'h' => 9, + 'r' => 1.7778, + ), + array( + 'w' => 9, + 'h' => 16, + 'r' => 0.5625, + ), + ); + $best = $aspects[0]; + $best_d = abs( $target - $best['r'] ); foreach ( $aspects as $c ) { $d = abs( $target - $c['r'] ); if ( $d < $best_d ) { @@ -279,16 +311,16 @@ class PRAutoBlogger_OpenRouter_Image_Batch { } $aspect = $best['w'] . ':' . $best['h']; - return [ + return array( 'model' => $model, - 'messages' => [ - [ + 'messages' => array( + array( 'role' => 'user', 'content' => 'Generate an image: ' . $prompt, - ], - ], - 'modalities' => [ 'image', 'text' ], - 'image_config' => [ 'aspect_ratio' => $aspect ], - ]; + ), + ), + 'modalities' => array( 'image', 'text' ), + 'image_config' => array( 'aspect_ratio' => $aspect ), + ); } } diff --git a/includes/providers/class-open-router-image-pricing.php b/includes/providers/class-open-router-image-pricing.php index 9613744..5d60b7e 100644 --- a/includes/providers/class-open-router-image-pricing.php +++ b/includes/providers/class-open-router-image-pricing.php @@ -22,13 +22,13 @@ class PRAutoBlogger_OpenRouter_Image_Pricing { * * @var array */ - private const COST_PER_IMAGE = [ - 'google/gemini-2.5-flash-image' => 0.005, - 'google/gemini-3.1-flash-image-preview' => 0.008, - 'google/gemini-3-pro-image-preview' => 0.03, - 'openai/gpt-5-image-mini' => 0.02, - 'openai/gpt-5-image' => 0.08, - ]; + private const COST_PER_IMAGE = array( + 'google/gemini-2.5-flash-image' => 0.005, + 'google/gemini-3.1-flash-image-preview' => 0.008, + 'google/gemini-3-pro-image-preview' => 0.03, + 'openai/gpt-5-image-mini' => 0.02, + 'openai/gpt-5-image' => 0.08, + ); /** * Resolve the model identifier from a hint, falling back to site option, diff --git a/includes/providers/class-open-router-image-provider.php b/includes/providers/class-open-router-image-provider.php index 786d678..928bc2b 100644 --- a/includes/providers/class-open-router-image-provider.php +++ b/includes/providers/class-open-router-image-provider.php @@ -43,7 +43,7 @@ class PRAutoBlogger_OpenRouter_Image_Provider implements PRAutoBlogger_Image_Pro * * Retries 5xx/429 with exponential backoff; 4xx (except 429) fail immediately. */ - public function generate_image( string $prompt, int $width, int $height, array $options = [] ): array { + public function generate_image( string $prompt, int $width, int $height, array $options = array() ): array { $this->assert_valid_dimensions( $width, $height ); $prompt = trim( $prompt ); if ( '' === $prompt ) { @@ -74,11 +74,14 @@ class PRAutoBlogger_OpenRouter_Image_Provider implements PRAutoBlogger_Image_Pro try { for ( $attempt = 1; $attempt <= PRAUTOBLOGGER_MAX_RETRIES; $attempt++ ) { - $response = wp_remote_post( $url, [ - 'timeout' => PRAUTOBLOGGER_API_TIMEOUT_SECONDS, - 'headers' => $headers, - 'body' => wp_json_encode( $body ), - ] ); + $response = wp_remote_post( + $url, + array( + 'timeout' => PRAUTOBLOGGER_API_TIMEOUT_SECONDS, + 'headers' => $headers, + 'body' => wp_json_encode( $body ), + ) + ); if ( is_wp_error( $response ) ) { $last_error = $response->get_error_message(); @@ -116,7 +119,7 @@ class PRAutoBlogger_OpenRouter_Image_Provider implements PRAutoBlogger_Image_Pro $image_bytes = $this->support->extract_image_bytes( $raw ); - return [ + return array( 'bytes' => $image_bytes, 'mime_type' => 'image/png', 'width' => $width, @@ -125,7 +128,7 @@ class PRAutoBlogger_OpenRouter_Image_Provider implements PRAutoBlogger_Image_Pro 'seed' => null, 'cost_usd' => $this->pricing->estimate_cost( $width, $height, $model ), 'latency_ms' => (int) ( ( microtime( true ) - $started_at ) * 1000 ), - ]; + ); } } finally { remove_action( 'http_api_curl', $curl_filter, 99 ); @@ -176,7 +179,7 @@ class PRAutoBlogger_OpenRouter_Image_Provider implements PRAutoBlogger_Image_Pro } /** {@inheritDoc} */ - public function estimate_cost( int $width, int $height, array $options = [] ): float { + public function estimate_cost( int $width, int $height, array $options = array() ): float { $model = $this->pricing->resolve_model( (string) ( $options['model'] ?? '' ) ); return $this->pricing->estimate_cost( $width, $height, $model ); } @@ -191,32 +194,41 @@ class PRAutoBlogger_OpenRouter_Image_Provider implements PRAutoBlogger_Image_Pro try { $api_key = $this->support->get_api_key(); } catch ( \RuntimeException $e ) { - return [ 'status' => 'error', 'message' => $e->getMessage() ]; + return array( + 'status' => 'error', + 'message' => $e->getMessage(), + ); } - $response = wp_remote_get( 'https://openrouter.ai/api/v1/auth/key', [ - 'timeout' => 15, - 'headers' => [ 'Authorization' => 'Bearer ' . $api_key ], - ] ); + $response = wp_remote_get( + 'https://openrouter.ai/api/v1/auth/key', + array( + 'timeout' => 15, + 'headers' => array( 'Authorization' => 'Bearer ' . $api_key ), + ) + ); if ( is_wp_error( $response ) ) { - return [ + return array( 'status' => 'error', 'message' => __( 'Could not reach OpenRouter API.', 'prautoblogger' ), 'debug' => $response->get_error_message(), - ]; + ); } $status = (int) wp_remote_retrieve_response_code( $response ); if ( 200 === $status ) { - return [ 'status' => 'ok', 'message' => __( 'OpenRouter API key valid.', 'prautoblogger' ) ]; + return array( + 'status' => 'ok', + 'message' => __( 'OpenRouter API key valid.', 'prautoblogger' ), + ); } - return [ + return array( 'status' => 'error', 'message' => sprintf( __( 'OpenRouter returned HTTP %d.', 'prautoblogger' ), $status ), 'debug' => substr( (string) wp_remote_retrieve_body( $response ), 0, 200 ), - ]; + ); } /** @@ -224,34 +236,62 @@ class PRAutoBlogger_OpenRouter_Image_Provider implements PRAutoBlogger_Image_Pro * * @var array */ - private const STANDARD_ASPECTS = [ - [ 'w' => 1, 'h' => 1, 'ratio' => 1.0 ], - [ 'w' => 3, 'h' => 2, 'ratio' => 1.5 ], - [ 'w' => 2, 'h' => 3, 'ratio' => 0.6667 ], - [ 'w' => 4, 'h' => 3, 'ratio' => 1.3333 ], - [ 'w' => 3, 'h' => 4, 'ratio' => 0.75 ], - [ 'w' => 16, 'h' => 9, 'ratio' => 1.7778 ], - [ 'w' => 9, 'h' => 16, 'ratio' => 0.5625 ], - ]; + private const STANDARD_ASPECTS = array( + array( + 'w' => 1, + 'h' => 1, + 'ratio' => 1.0, + ), + array( + 'w' => 3, + 'h' => 2, + 'ratio' => 1.5, + ), + array( + 'w' => 2, + 'h' => 3, + 'ratio' => 0.6667, + ), + array( + 'w' => 4, + 'h' => 3, + 'ratio' => 1.3333, + ), + array( + 'w' => 3, + 'h' => 4, + 'ratio' => 0.75, + ), + array( + 'w' => 16, + 'h' => 9, + 'ratio' => 1.7778, + ), + array( + 'w' => 9, + 'h' => 16, + 'ratio' => 0.5625, + ), + ); private function build_request_body( string $prompt, int $width, int $height, string $model ): array { $aspect = $this->snap_aspect_ratio( $width, $height ); - return [ - 'model' => $model, - 'messages' => [ - [ + return array( + 'model' => $model, + 'messages' => array( + array( 'role' => 'user', 'content' => 'Generate an image: ' . $prompt, - ], - ], + ), + ), // Use ["image", "text"] — some providers (Gemini) require both // modalities even when we only want the image output. - 'modalities' => [ 'image', 'text' ], - 'image_config' => [ + 'modalities' => array( 'image', 'text' ), + 'image_config' => array( 'aspect_ratio' => $aspect, - ], - ]; + ), + ); } /** @@ -262,9 +302,9 @@ class PRAutoBlogger_OpenRouter_Image_Provider implements PRAutoBlogger_Image_Pro * @return string Aspect ratio string like "16:9". */ private function snap_aspect_ratio( int $width, int $height ): string { - $target = $height > 0 ? (float) $width / (float) $height : 1.0; - $best = self::STANDARD_ASPECTS[0]; - $best_d = abs( $target - $best['ratio'] ); + $target = $height > 0 ? (float) $width / (float) $height : 1.0; + $best = self::STANDARD_ASPECTS[0]; + $best_d = abs( $target - $best['ratio'] ); foreach ( self::STANDARD_ASPECTS as $candidate ) { $d = abs( $target - $candidate['ratio'] ); @@ -292,7 +332,10 @@ class PRAutoBlogger_OpenRouter_Image_Provider implements PRAutoBlogger_Image_Pro throw new \InvalidArgumentException( sprintf( esc_html__( 'Image dimensions %1$dx%2$d outside supported range (%3$d–%4$d px).', 'prautoblogger' ), - $width, $height, self::MIN_DIMENSION_PX, self::MAX_DIMENSION_PX + $width, + $height, + self::MIN_DIMENSION_PX, + self::MAX_DIMENSION_PX ) ); } diff --git a/includes/providers/class-open-router-image-support.php b/includes/providers/class-open-router-image-support.php index b1addbb..3d73e8d 100644 --- a/includes/providers/class-open-router-image-support.php +++ b/includes/providers/class-open-router-image-support.php @@ -69,7 +69,7 @@ class PRAutoBlogger_OpenRouter_Image_Support { ); } - $images = $decoded['choices'][0]['message']['images'] ?? []; + $images = $decoded['choices'][0]['message']['images'] ?? array(); if ( empty( $images ) ) { throw new \RuntimeException( esc_html__( 'OpenRouter response contained no images.', 'prautoblogger' ) diff --git a/includes/providers/class-open-router-pricing.php b/includes/providers/class-open-router-pricing.php index 09e4c60..acbe06b 100644 --- a/includes/providers/class-open-router-pricing.php +++ b/includes/providers/class-open-router-pricing.php @@ -21,15 +21,36 @@ class PRAutoBlogger_OpenRouter_Pricing { * * @var array */ - private const MODEL_PRICING = [ - 'anthropic/claude-3.5-haiku' => [ 'prompt' => 0.80, 'completion' => 4.00 ], - 'anthropic/claude-sonnet-4' => [ 'prompt' => 3.00, 'completion' => 15.00 ], - 'anthropic/claude-opus-4' => [ 'prompt' => 15.00, 'completion' => 75.00 ], - 'openai/gpt-4o' => [ 'prompt' => 2.50, 'completion' => 10.00 ], - 'openai/gpt-4o-mini' => [ 'prompt' => 0.15, 'completion' => 0.60 ], - 'google/gemini-2.0-flash' => [ 'prompt' => 0.10, 'completion' => 0.40 ], - 'meta-llama/llama-3.3-70b' => [ 'prompt' => 0.40, 'completion' => 0.40 ], - ]; + private const MODEL_PRICING = array( + 'anthropic/claude-3.5-haiku' => array( + 'prompt' => 0.80, + 'completion' => 4.00, + ), + 'anthropic/claude-sonnet-4' => array( + 'prompt' => 3.00, + 'completion' => 15.00, + ), + 'anthropic/claude-opus-4' => array( + 'prompt' => 15.00, + 'completion' => 75.00, + ), + 'openai/gpt-4o' => array( + 'prompt' => 2.50, + 'completion' => 10.00, + ), + 'openai/gpt-4o-mini' => array( + 'prompt' => 0.15, + 'completion' => 0.60, + ), + 'google/gemini-2.0-flash' => array( + 'prompt' => 0.10, + 'completion' => 0.40, + ), + 'meta-llama/llama-3.3-70b' => array( + 'prompt' => 0.40, + 'completion' => 0.40, + ), + ); /** * Get available models from OpenRouter's /models endpoint. @@ -48,7 +69,7 @@ class PRAutoBlogger_OpenRouter_Pricing { $api_key = $this->get_api_key(); if ( '' === $api_key ) { - return []; + return array(); } // Belt-and-suspenders: inject Authorization at cURL level (see OpenRouter_Provider). @@ -58,43 +79,47 @@ class PRAutoBlogger_OpenRouter_Pricing { return; } // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt - curl_setopt( $handle, CURLOPT_HTTPHEADER, [ - 'Authorization: ' . $auth_header_value, - ] ); + curl_setopt( + $handle, + CURLOPT_HTTPHEADER, + array( + 'Authorization: ' . $auth_header_value, + ) + ); }; add_action( 'http_api_curl', $curl_auth_filter_mod, 99, 3 ); $response = wp_remote_get( 'https://openrouter.ai/api/v1/models', - [ + array( 'timeout' => 30, - 'headers' => [ + 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, - ], - ] + ), + ) ); remove_action( 'http_api_curl', $curl_auth_filter_mod, 99 ); if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { PRAutoBlogger_Logger::instance()->warning( 'Failed to fetch OpenRouter models list.', 'openrouter' ); - return []; + return array(); } $data = json_decode( wp_remote_retrieve_body( $response ), true ); - $models = []; + $models = array(); if ( isset( $data['data'] ) && is_array( $data['data'] ) ) { foreach ( $data['data'] as $model ) { - $models[] = [ + $models[] = array( 'id' => $model['id'] ?? '', 'name' => $model['name'] ?? $model['id'] ?? '', 'context_length' => (int) ( $model['context_length'] ?? 0 ), - 'pricing' => [ + 'pricing' => array( 'prompt' => (float) ( $model['pricing']['prompt'] ?? 0 ) * 1000000, 'completion' => (float) ( $model['pricing']['completion'] ?? 0 ) * 1000000, - ], - ]; + ), + ); } } @@ -135,7 +160,10 @@ class PRAutoBlogger_OpenRouter_Pricing { if ( null === $pricing ) { // Unknown model — use a conservative estimate. PRAutoBlogger_Logger::instance()->warning( "Unknown model pricing for '{$model}'. Using conservative estimate.", 'openrouter' ); - $pricing = [ 'prompt' => 10.0, 'completion' => 30.0 ]; + $pricing = array( + 'prompt' => 10.0, + 'completion' => 30.0, + ); } return ( $prompt_tokens * $pricing['prompt'] / 1000000 ) diff --git a/includes/providers/class-open-router-provider.php b/includes/providers/class-open-router-provider.php index 4b4354a..be203c6 100644 --- a/includes/providers/class-open-router-provider.php +++ b/includes/providers/class-open-router-provider.php @@ -50,7 +50,7 @@ class PRAutoBlogger_OpenRouter_Provider implements PRAutoBlogger_LLM_Provider_In * * @throws \RuntimeException On API error after retries exhausted. */ - public function send_chat_completion( array $messages, string $model, array $options = [] ): array { + public function send_chat_completion( array $messages, string $model, array $options = array() ): array { $api_key = $this->get_api_key(); if ( '' === $api_key ) { throw new \RuntimeException( @@ -74,10 +74,10 @@ class PRAutoBlogger_OpenRouter_Provider implements PRAutoBlogger_LLM_Provider_In ); } - $body = [ + $body = array( 'model' => $model, 'messages' => $messages, - ]; + ); if ( isset( $options['temperature'] ) ) { $body['temperature'] = $options['temperature']; @@ -93,10 +93,10 @@ class PRAutoBlogger_OpenRouter_Provider implements PRAutoBlogger_LLM_Provider_In if ( isset( $options['reasoning'] ) ) { $body['reasoning'] = $options['reasoning']; } elseif ( '1' === get_option( 'prautoblogger_reasoning_enabled', '0' ) ) { - $body['reasoning'] = [ + $body['reasoning'] = array( 'enabled' => true, 'effort' => get_option( 'prautoblogger_reasoning_effort', 'medium' ), - ]; + ); } $last_error = ''; @@ -107,8 +107,8 @@ class PRAutoBlogger_OpenRouter_Provider implements PRAutoBlogger_LLM_Provider_In $cache_ttl = $config->get_cache_ttl_seconds(); $via_gateway = $config->is_via_gateway(); - $builder = new PRAutoBlogger_OpenRouter_Request_Builder(); - $request_headers = $builder->build_headers( $api_key, $via_gateway, $cache_ttl ); + $builder = new PRAutoBlogger_OpenRouter_Request_Builder(); + $request_headers = $builder->build_headers( $api_key, $via_gateway, $cache_ttl ); $curl_auth_filter = $builder->register_curl_auth_filter( $request_headers, $base_host ); try { @@ -117,11 +117,11 @@ class PRAutoBlogger_OpenRouter_Provider implements PRAutoBlogger_LLM_Provider_In for ( $attempt = 1; $attempt <= PRAUTOBLOGGER_MAX_RETRIES; $attempt++ ) { $response = wp_remote_post( $base_url . '/chat/completions', - [ + array( 'timeout' => PRAUTOBLOGGER_API_TIMEOUT_SECONDS, 'headers' => $request_headers, 'body' => wp_json_encode( $body ), - ] + ) ); if ( is_wp_error( $response ) ) { diff --git a/includes/providers/class-open-router-request-builder.php b/includes/providers/class-open-router-request-builder.php index 09116c5..683ad89 100644 --- a/includes/providers/class-open-router-request-builder.php +++ b/includes/providers/class-open-router-request-builder.php @@ -29,12 +29,12 @@ class PRAutoBlogger_OpenRouter_Request_Builder { * @return array HTTP headers ready for wp_remote_post(). */ public function build_headers( string $api_key, bool $via_gateway, int $cache_ttl ): array { - $headers = [ + $headers = array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', 'HTTP-Referer' => home_url(), 'X-Title' => 'PRAutoBlogger WordPress Plugin', - ]; + ); if ( $via_gateway && $cache_ttl > 0 ) { $headers['cf-aig-cache-ttl'] = (string) $cache_ttl; @@ -66,7 +66,7 @@ class PRAutoBlogger_OpenRouter_Request_Builder { if ( '' === $base_host || false === strpos( (string) $url, $base_host ) ) { return; } - $curl_headers = []; + $curl_headers = array(); foreach ( $request_headers as $name => $value ) { $curl_headers[] = $name . ': ' . $value; } diff --git a/includes/providers/class-open-router-response-parser.php b/includes/providers/class-open-router-response-parser.php index 9915cbb..b942590 100644 --- a/includes/providers/class-open-router-response-parser.php +++ b/includes/providers/class-open-router-response-parser.php @@ -94,12 +94,12 @@ class PRAutoBlogger_OpenRouter_Response_Parser { $content = ''; } - $usage = $data['usage'] ?? []; + $usage = $data['usage'] ?? array(); // Reasoning content lives alongside 'content' in the message object. $reasoning_content = $data['choices'][0]['message']['reasoning'] ?? ''; - return [ + return array( 'content' => (string) $content, 'model' => $data['model'] ?? $model, 'prompt_tokens' => (int) ( $usage['prompt_tokens'] ?? 0 ), @@ -108,7 +108,7 @@ class PRAutoBlogger_OpenRouter_Response_Parser { 'total_tokens' => (int) ( $usage['total_tokens'] ?? 0 ), 'finish_reason' => $data['choices'][0]['finish_reason'] ?? 'unknown', 'reasoning_content' => (string) $reasoning_content, - ]; + ); } /** diff --git a/includes/providers/class-open-router-validator.php b/includes/providers/class-open-router-validator.php index c10c478..864e6e5 100644 --- a/includes/providers/class-open-router-validator.php +++ b/includes/providers/class-open-router-validator.php @@ -79,20 +79,24 @@ class PRAutoBlogger_OpenRouter_Validator { return; } // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt - curl_setopt( $handle, CURLOPT_HTTPHEADER, [ - 'Authorization: ' . $auth_header_value, - ] ); + curl_setopt( + $handle, + CURLOPT_HTTPHEADER, + array( + 'Authorization: ' . $auth_header_value, + ) + ); }; add_action( 'http_api_curl', $curl_auth_filter_cred, 99, 3 ); $response = wp_remote_get( $base_url . '/auth/key', - [ + array( 'timeout' => self::TIMEOUT_SECONDS, - 'headers' => [ + 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, - ], - ] + ), + ) ); remove_action( 'http_api_curl', $curl_auth_filter_cred, 99 ); @@ -115,10 +119,10 @@ class PRAutoBlogger_OpenRouter_Validator { $status_code = wp_remote_retrieve_response_code( $response ); if ( 200 === $status_code ) { - return [ + return array( 'status' => 'ok', 'message' => __( 'OpenRouter connected.', 'prautoblogger' ), - ]; + ); } $body_raw = wp_remote_retrieve_body( $response ); @@ -143,10 +147,10 @@ class PRAutoBlogger_OpenRouter_Validator { * @return array{status: string, message: string, debug: string} */ private function err( string $debug, string $message ): array { - return [ + return array( 'status' => 'error', 'message' => $message, 'debug' => $debug, - ]; + ); } } diff --git a/includes/providers/class-reddit-availability.php b/includes/providers/class-reddit-availability.php index 46b5801..f622261 100644 --- a/includes/providers/class-reddit-availability.php +++ b/includes/providers/class-reddit-availability.php @@ -63,12 +63,12 @@ class PRAutoBlogger_Reddit_Availability { $url = self::BASE_URL . '/r/all/hot.rss?limit=1'; $response = wp_remote_get( $url, - [ + array( 'timeout' => 10, - 'headers' => [ + 'headers' => array( 'User-Agent' => self::USER_AGENT, - ], - ] + ), + ) ); if ( is_wp_error( $response ) ) { @@ -91,12 +91,12 @@ class PRAutoBlogger_Reddit_Availability { $url = self::BASE_URL . '/r/all/hot.json?limit=1'; $response = wp_remote_get( $url, - [ + array( 'timeout' => 10, - 'headers' => [ + 'headers' => array( 'User-Agent' => self::USER_AGENT, - ], - ] + ), + ) ); if ( is_wp_error( $response ) ) { @@ -121,11 +121,11 @@ class PRAutoBlogger_Reddit_Availability { return $status; } - return [ + return array( 'remaining' => 10, 'limit' => 10, 'resets_at' => '', - ]; + ); } /** @@ -143,13 +143,13 @@ class PRAutoBlogger_Reddit_Availability { public function api_get( string $url ): ?array { $response = wp_remote_get( $url, - [ + array( 'timeout' => 30, - 'headers' => [ + 'headers' => array( 'User-Agent' => self::USER_AGENT, 'Accept' => 'application/json', - ], - ] + ), + ) ); if ( is_wp_error( $response ) ) { @@ -168,11 +168,11 @@ class PRAutoBlogger_Reddit_Availability { if ( '' !== $rate_remaining ) { set_transient( self::RATE_LIMIT_TRANSIENT, - [ + array( 'remaining' => (int) $rate_remaining, 'limit' => (int) $rate_used + (int) $rate_remaining, 'resets_at' => gmdate( 'Y-m-d H:i:s', time() + (int) $rate_reset ), - ], + ), 120 ); } diff --git a/includes/providers/class-reddit-json-client.php b/includes/providers/class-reddit-json-client.php index 2b3218b..4d75e6b 100644 --- a/includes/providers/class-reddit-json-client.php +++ b/includes/providers/class-reddit-json-client.php @@ -97,13 +97,13 @@ class PRAutoBlogger_Reddit_JSON_Client { $response = wp_remote_get( $url, - [ + array( 'timeout' => self::TIMEOUT_SECONDS, - 'headers' => [ + 'headers' => array( 'User-Agent' => self::USER_AGENT, 'Accept' => 'application/atom+xml, application/rss+xml', - ], - ] + ), + ) ); if ( is_wp_error( $response ) ) { @@ -111,7 +111,7 @@ class PRAutoBlogger_Reddit_JSON_Client { 'Reddit RSS GET failed: ' . $response->get_error_message(), 'reddit' ); - return []; + return array(); } $status_code = wp_remote_retrieve_response_code( $response ); @@ -120,10 +120,10 @@ class PRAutoBlogger_Reddit_JSON_Client { sprintf( 'Reddit RSS HTTP %d for r/%s', $status_code, $subreddit ), 'reddit' ); - return []; + return array(); } - $body = wp_remote_retrieve_body( $response ); + $body = wp_remote_retrieve_body( $response ); $parser = new PRAutoBlogger_Reddit_RSS_Parser(); return $parser->parse( $body, $subreddit ); } @@ -154,15 +154,15 @@ class PRAutoBlogger_Reddit_JSON_Client { $response = $this->api_get( $url ); if ( null === $response || ! isset( $response['data']['children'] ) ) { - return []; + return array(); } - $posts = []; + $posts = array(); foreach ( $response['data']['children'] as $child ) { if ( isset( $child['data'] ) ) { - $post = $child['data']; + $post = $child['data']; $post['data_source'] = 'reddit_json'; - $posts[] = $post; + $posts[] = $post; } } @@ -197,10 +197,10 @@ class PRAutoBlogger_Reddit_JSON_Client { // Comments endpoint returns [post_listing, comments_listing]. if ( ! is_array( $response ) || ! isset( $response[1]['data']['children'] ) ) { - return []; + return array(); } - $comments = []; + $comments = array(); foreach ( $response[1]['data']['children'] as $child ) { // Filter out "more" type entries, keep only actual comments (kind=t1). if ( isset( $child['data'] ) && 't1' === ( $child['kind'] ?? '' ) ) { diff --git a/includes/providers/class-reddit-provider.php b/includes/providers/class-reddit-provider.php index d1dd3f1..5b393e8 100755 --- a/includes/providers/class-reddit-provider.php +++ b/includes/providers/class-reddit-provider.php @@ -47,7 +47,7 @@ class PRAutoBlogger_Reddit_Provider implements PRAutoBlogger_Source_Provider_Int $comments_limit = $config['comments_per_post'] ?? 5; $client = new PRAutoBlogger_Reddit_JSON_Client(); - $collected = []; + $collected = array(); PRAutoBlogger_Logger::instance()->info( sprintf( @@ -72,26 +72,28 @@ class PRAutoBlogger_Reddit_Provider implements PRAutoBlogger_Source_Provider_Int foreach ( $posts as $post ) { $data_source = $post['data_source'] ?? 'reddit'; - $collected[] = new PRAutoBlogger_Source_Data( [ - 'source_type' => 'reddit', - 'source_id' => 't3_' . ( $post['id'] ?? '' ), - 'subreddit' => $subreddit, - 'title' => $post['title'] ?? '', - 'content' => $post['selftext'] ?? '', - 'author' => $post['author'] ?? '[deleted]', - 'score' => (int) ( $post['score'] ?? 0 ), - 'comment_count' => (int) ( $post['num_comments'] ?? 0 ), - 'permalink' => 'https://reddit.com' . ( $post['permalink'] ?? '' ), - 'collected_at' => current_time( 'mysql' ), - 'metadata' => [ - 'post_type' => ( $post['is_self'] ?? false ) ? 'self' : 'link', - 'flair' => $post['link_flair_text'] ?? null, - 'created_utc' => $post['created_utc'] ?? null, - 'upvote_ratio' => $post['upvote_ratio'] ?? null, - 'is_original' => $post['is_original_content'] ?? false, - 'data_source' => $data_source, - ], - ] ); + $collected[] = new PRAutoBlogger_Source_Data( + array( + 'source_type' => 'reddit', + 'source_id' => 't3_' . ( $post['id'] ?? '' ), + 'subreddit' => $subreddit, + 'title' => $post['title'] ?? '', + 'content' => $post['selftext'] ?? '', + 'author' => $post['author'] ?? '[deleted]', + 'score' => (int) ( $post['score'] ?? 0 ), + 'comment_count' => (int) ( $post['num_comments'] ?? 0 ), + 'permalink' => 'https://reddit.com' . ( $post['permalink'] ?? '' ), + 'collected_at' => current_time( 'mysql' ), + 'metadata' => array( + 'post_type' => ( $post['is_self'] ?? false ) ? 'self' : 'link', + 'flair' => $post['link_flair_text'] ?? null, + 'created_utc' => $post['created_utc'] ?? null, + 'upvote_ratio' => $post['upvote_ratio'] ?? null, + 'is_original' => $post['is_original_content'] ?? false, + 'data_source' => $data_source, + ), + ) + ); // Fetch comments for high-engagement posts via .json // (comments are not available in RSS feeds). @@ -100,25 +102,27 @@ class PRAutoBlogger_Reddit_Provider implements PRAutoBlogger_Source_Provider_Int $comments = $client->fetch_comments( $subreddit, $post_id, $comments_limit ); foreach ( $comments as $comment ) { - $collected[] = new PRAutoBlogger_Source_Data( [ - 'source_type' => 'reddit', - 'source_id' => 't1_' . ( $comment['id'] ?? '' ), - 'subreddit' => $subreddit, - 'title' => null, - 'content' => $comment['body'] ?? '', - 'author' => $comment['author'] ?? '[deleted]', - 'score' => (int) ( $comment['score'] ?? 0 ), - 'comment_count' => 0, - 'permalink' => 'https://reddit.com' . ( $comment['permalink'] ?? '' ), - 'collected_at' => current_time( 'mysql' ), - 'metadata' => [ - 'parent_post_id' => 't3_' . $post_id, - 'parent_title' => $post['title'] ?? '', - 'is_comment' => true, - 'created_utc' => $comment['created_utc'] ?? null, - 'data_source' => 'reddit_json', - ], - ] ); + $collected[] = new PRAutoBlogger_Source_Data( + array( + 'source_type' => 'reddit', + 'source_id' => 't1_' . ( $comment['id'] ?? '' ), + 'subreddit' => $subreddit, + 'title' => null, + 'content' => $comment['body'] ?? '', + 'author' => $comment['author'] ?? '[deleted]', + 'score' => (int) ( $comment['score'] ?? 0 ), + 'comment_count' => 0, + 'permalink' => 'https://reddit.com' . ( $comment['permalink'] ?? '' ), + 'collected_at' => current_time( 'mysql' ), + 'metadata' => array( + 'parent_post_id' => 't3_' . $post_id, + 'parent_title' => $post['title'] ?? '', + 'is_comment' => true, + 'created_utc' => $comment['created_utc'] ?? null, + 'data_source' => 'reddit_json', + ), + ) + ); } } } @@ -184,6 +188,6 @@ class PRAutoBlogger_Reddit_Provider implements PRAutoBlogger_Source_Provider_Int private function get_configured_subreddits(): array { $json = get_option( 'prautoblogger_target_subreddits', '' ); $list = json_decode( $json, true ); - return is_array( $list ) ? $list : []; + return is_array( $list ) ? $list : array(); } } diff --git a/includes/providers/class-reddit-rss-parser.php b/includes/providers/class-reddit-rss-parser.php index 669e35f..5262167 100644 --- a/includes/providers/class-reddit-rss-parser.php +++ b/includes/providers/class-reddit-rss-parser.php @@ -41,7 +41,7 @@ class PRAutoBlogger_Reddit_RSS_Parser { if ( false === $feed ) { PRAutoBlogger_Logger::instance()->error( 'Failed to parse Reddit RSS XML.', 'reddit' ); - return []; + return array(); } // Register the Atom namespace. @@ -49,10 +49,10 @@ class PRAutoBlogger_Reddit_RSS_Parser { $entries = $feed->xpath( '//atom:entry' ); if ( empty( $entries ) ) { - return []; + return array(); } - $posts = []; + $posts = array(); foreach ( $entries as $entry ) { $post = $this->parse_entry( $entry, $subreddit ); if ( null !== $post ) { @@ -118,7 +118,7 @@ class PRAutoBlogger_Reddit_RSS_Parser { $permalink = $parsed['path'] ?? ''; } - return [ + return array( 'id' => $post_id, 'title' => $title, 'selftext' => $content, @@ -132,6 +132,6 @@ class PRAutoBlogger_Reddit_RSS_Parser { 'upvote_ratio' => null, 'is_original_content' => false, 'data_source' => 'reddit_rss', - ]; + ); } } diff --git a/includes/providers/class-runware-image-batch.php b/includes/providers/class-runware-image-batch.php index 49ba9ef..6769633 100644 --- a/includes/providers/class-runware-image-batch.php +++ b/includes/providers/class-runware-image-batch.php @@ -59,17 +59,17 @@ class PRAutoBlogger_Runware_Image_Batch { */ public function execute( array $requests ): array { if ( empty( $requests ) ) { - return []; + return array(); } $api_key = $this->support->get_api_key(); $round1 = $this->round_one_inference( $api_key, $requests ); - $results = []; - $to_download = []; + $results = array(); + $to_download = array(); foreach ( $round1 as $key => $entry ) { if ( isset( $entry['error'] ) ) { - $results[ $key ] = [ 'error' => $entry['error'] ]; + $results[ $key ] = array( 'error' => $entry['error'] ); continue; } $to_download[ $key ] = $entry; @@ -82,10 +82,10 @@ class PRAutoBlogger_Runware_Image_Batch { $bytes_map = $this->round_two_download( $to_download ); foreach ( $to_download as $key => $entry ) { if ( isset( $bytes_map[ $key ]['error'] ) ) { - $results[ $key ] = [ 'error' => $bytes_map[ $key ]['error'] ]; + $results[ $key ] = array( 'error' => $bytes_map[ $key ]['error'] ); continue; } - $results[ $key ] = [ + $results[ $key ] = array( 'bytes' => $bytes_map[ $key ]['bytes'], 'mime_type' => 'image/png', 'width' => $entry['width'], @@ -94,7 +94,7 @@ class PRAutoBlogger_Runware_Image_Batch { 'seed' => $entry['seed'], 'cost_usd' => $this->pricing->estimate_cost( $entry['width'], $entry['height'], $entry['model'] ), 'latency_ms' => (int) ( ( microtime( true ) - $entry['started_at'] ) * 1000 ), - ]; + ); } return $results; @@ -108,10 +108,10 @@ class PRAutoBlogger_Runware_Image_Batch { * @return array Map of key => {error} | {image_url, width, height, model, seed, started_at}. */ private function round_one_inference( string $api_key, array $requests ): array { - $headers = [ 'Content-Type: application/json' ]; + $headers = array( 'Content-Type: application/json' ); $mh = curl_multi_init(); - $handles = []; - $start_times = []; + $handles = array(); + $start_times = array(); foreach ( $requests as $key => $req ) { $model = $this->pricing->resolve_model( (string) ( $req['options']['model'] ?? '' ) ); @@ -123,28 +123,32 @@ class PRAutoBlogger_Runware_Image_Batch { $ch = curl_init(); curl_setopt( $ch, CURLOPT_URL, PRAutoBlogger_Runware_Image_Support::API_URL ); curl_setopt( $ch, CURLOPT_POST, true ); - curl_setopt( $ch, CURLOPT_POSTFIELDS, wp_json_encode( - $this->build_payload( $api_key, (string) $req['prompt'], $snap_w, $snap_h, $model, $seed, $steps ) - ) ); + curl_setopt( + $ch, + CURLOPT_POSTFIELDS, + wp_json_encode( + $this->build_payload( $api_key, (string) $req['prompt'], $snap_w, $snap_h, $model, $seed, $steps ) + ) + ); curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers ); curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); curl_setopt( $ch, CURLOPT_TIMEOUT, PRAUTOBLOGGER_API_TIMEOUT_SECONDS ); curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 10 ); curl_multi_add_handle( $mh, $ch ); - $handles[ $key ] = [ + $handles[ $key ] = array( 'handle' => $ch, 'model' => $model, 'width' => $snap_w, 'height' => $snap_h, 'seed' => $seed, - ]; + ); $start_times[ $key ] = microtime( true ); } $this->run_multi( $mh ); - $out = []; + $out = array(); foreach ( $handles as $key => $entry ) { $out[ $key ] = $this->collect_inference_result( (string) $key, $entry, $start_times[ $key ] ); curl_multi_remove_handle( $mh, $entry['handle'] ); @@ -163,7 +167,7 @@ class PRAutoBlogger_Runware_Image_Batch { */ private function round_two_download( array $inferences ): array { $mh = curl_multi_init(); - $handles = []; + $handles = array(); foreach ( $inferences as $key => $entry ) { $ch = curl_init(); @@ -177,22 +181,22 @@ class PRAutoBlogger_Runware_Image_Batch { $this->run_multi( $mh ); - $out = []; + $out = array(); foreach ( $handles as $key => $ch ) { $errno = curl_errno( $ch ); if ( 0 !== $errno ) { $msg = sprintf( 'Runware image download cURL error %d for "%s": %s', $errno, $key, curl_error( $ch ) ); PRAutoBlogger_Logger::instance()->error( $msg, 'runware-image-batch' ); - $out[ $key ] = [ 'error' => $msg ]; + $out[ $key ] = array( 'error' => $msg ); } else { $code = (int) curl_getinfo( $ch, CURLINFO_HTTP_CODE ); $body = (string) curl_multi_getcontent( $ch ); if ( 200 !== $code || '' === $body ) { $msg = sprintf( 'Runware image download HTTP %d for "%s" (%d bytes)', $code, $key, strlen( $body ) ); PRAutoBlogger_Logger::instance()->error( $msg, 'runware-image-batch' ); - $out[ $key ] = [ 'error' => $msg ]; + $out[ $key ] = array( 'error' => $msg ); } else { - $out[ $key ] = [ 'bytes' => $body ]; + $out[ $key ] = array( 'bytes' => $body ); } } curl_multi_remove_handle( $mh, $ch ); @@ -231,9 +235,12 @@ class PRAutoBlogger_Runware_Image_Batch { * @return array> */ private function build_payload( string $api_key, string $prompt, int $width, int $height, string $model, int $seed, int $steps ): array { - return [ - [ 'taskType' => 'authentication', 'apiKey' => $api_key ], - [ + return array( + array( + 'taskType' => 'authentication', + 'apiKey' => $api_key, + ), + array( 'taskType' => 'imageInference', 'taskUUID' => wp_generate_uuid4(), 'positivePrompt' => $prompt, @@ -245,8 +252,8 @@ class PRAutoBlogger_Runware_Image_Batch { 'outputFormat' => 'PNG', 'outputType' => 'URL', 'seed' => $seed, - ], - ]; + ), + ); } /** @@ -263,7 +270,7 @@ class PRAutoBlogger_Runware_Image_Batch { if ( 0 !== $errno ) { $msg = sprintf( 'Runware batch inference cURL error %d for "%s": %s', $errno, $key, curl_error( $ch ) ); PRAutoBlogger_Logger::instance()->error( $msg, 'runware-image-batch' ); - return [ 'error' => $msg ]; + return array( 'error' => $msg ); } $http_code = (int) curl_getinfo( $ch, CURLINFO_HTTP_CODE ); @@ -271,7 +278,7 @@ class PRAutoBlogger_Runware_Image_Batch { if ( $http_code >= 400 ) { $msg = sprintf( 'Runware batch inference HTTP %d for "%s": %s', $http_code, $key, substr( $raw, 0, 300 ) ); PRAutoBlogger_Logger::instance()->error( $msg, 'runware-image-batch' ); - return [ 'error' => $msg ]; + return array( 'error' => $msg ); } try { @@ -279,16 +286,16 @@ class PRAutoBlogger_Runware_Image_Batch { } catch ( \Throwable $e ) { $msg = sprintf( 'Runware batch inference parse error for "%s": %s', $key, $e->getMessage() ); PRAutoBlogger_Logger::instance()->error( $msg, 'runware-image-batch' ); - return [ 'error' => $msg ]; + return array( 'error' => $msg ); } - return [ + return array( 'image_url' => $image_url, 'width' => (int) $entry['width'], 'height' => (int) $entry['height'], 'model' => (string) $entry['model'], 'seed' => (int) $entry['seed'], 'started_at' => $start, - ]; + ); } } diff --git a/includes/providers/class-runware-image-pricing.php b/includes/providers/class-runware-image-pricing.php index 14a0f4e..6f925b9 100644 --- a/includes/providers/class-runware-image-pricing.php +++ b/includes/providers/class-runware-image-pricing.php @@ -26,12 +26,12 @@ class PRAutoBlogger_Runware_Image_Pricing { * * @var array */ - private const COST_PER_IMAGE = [ + private const COST_PER_IMAGE = array( // FLUX.1 schnell — 4-step distilled. Our new default (2026-04-21). 'runware:100@1' => 0.0006, // FLUX.1 dev — 28-step full model. Higher fidelity, ~30x cost. 'runware:101@1' => 0.02, - ]; + ); /** * Default number of inference steps per model. Runware bills per image @@ -39,10 +39,10 @@ class PRAutoBlogger_Runware_Image_Pricing { * * @var array */ - private const DEFAULT_STEPS = [ + private const DEFAULT_STEPS = array( 'runware:100@1' => 4, 'runware:101@1' => 28, - ]; + ); /** * Resolve the model identifier from a hint, falling back to site option, diff --git a/includes/providers/class-runware-image-provider.php b/includes/providers/class-runware-image-provider.php index a43b2c7..2803ad9 100644 --- a/includes/providers/class-runware-image-provider.php +++ b/includes/providers/class-runware-image-provider.php @@ -45,7 +45,7 @@ class PRAutoBlogger_Runware_Image_Provider implements PRAutoBlogger_Image_Provid * backoff; 4xx (except 429) fail immediately. The image download GET * is not retried — signed URLs are short-lived. */ - public function generate_image( string $prompt, int $width, int $height, array $options = [] ): array { + public function generate_image( string $prompt, int $width, int $height, array $options = array() ): array { $this->assert_valid_dimensions( $width, $height ); $prompt = trim( $prompt ); if ( '' === $prompt ) { @@ -61,16 +61,19 @@ class PRAutoBlogger_Runware_Image_Provider implements PRAutoBlogger_Image_Provid $seed = $this->support->normalize_seed( isset( $options['seed'] ) ? (int) $options['seed'] : null ); $steps = isset( $options['steps'] ) ? (int) $options['steps'] : $this->pricing->default_steps( $model ); $body = $this->build_request_body( $api_key, $prompt, $snap_w, $snap_h, $model, $seed, $steps ); - $headers = [ 'Content-Type' => 'application/json' ]; + $headers = array( 'Content-Type' => 'application/json' ); $started_at = microtime( true ); $last_error = ''; for ( $attempt = 1; $attempt <= PRAUTOBLOGGER_MAX_RETRIES; $attempt++ ) { - $response = wp_remote_post( PRAutoBlogger_Runware_Image_Support::API_URL, [ - 'timeout' => PRAUTOBLOGGER_API_TIMEOUT_SECONDS, - 'headers' => $headers, - 'body' => wp_json_encode( $body ), - ] ); + $response = wp_remote_post( + PRAutoBlogger_Runware_Image_Support::API_URL, + array( + 'timeout' => PRAUTOBLOGGER_API_TIMEOUT_SECONDS, + 'headers' => $headers, + 'body' => wp_json_encode( $body ), + ) + ); if ( is_wp_error( $response ) ) { $last_error = $response->get_error_message(); @@ -109,7 +112,7 @@ class PRAutoBlogger_Runware_Image_Provider implements PRAutoBlogger_Image_Provid $image_url = $this->support->extract_image_url( $raw ); $image_bytes = $this->support->download_image_bytes( $image_url ); - return [ + return array( 'bytes' => $image_bytes, 'mime_type' => 'image/png', 'width' => $snap_w, @@ -118,7 +121,7 @@ class PRAutoBlogger_Runware_Image_Provider implements PRAutoBlogger_Image_Provid 'seed' => $seed, 'cost_usd' => $this->pricing->estimate_cost( $snap_w, $snap_h, $model ), 'latency_ms' => (int) ( ( microtime( true ) - $started_at ) * 1000 ), - ]; + ); } throw new \RuntimeException( @@ -160,7 +163,7 @@ class PRAutoBlogger_Runware_Image_Provider implements PRAutoBlogger_Image_Provid } /** {@inheritDoc} */ - public function estimate_cost( int $width, int $height, array $options = [] ): float { + public function estimate_cost( int $width, int $height, array $options = array() ): float { $model = $this->pricing->resolve_model( (string) ( $options['model'] ?? '' ) ); return $this->pricing->estimate_cost( $width, $height, $model ); } @@ -181,50 +184,62 @@ class PRAutoBlogger_Runware_Image_Provider implements PRAutoBlogger_Image_Provid try { $api_key = $this->support->get_api_key(); } catch ( \RuntimeException $e ) { - return [ 'status' => 'error', 'message' => $e->getMessage() ]; + return array( + 'status' => 'error', + 'message' => $e->getMessage(), + ); } - $body = [ - [ 'taskType' => 'authentication', 'apiKey' => $api_key ], - ]; + $body = array( + array( + 'taskType' => 'authentication', + 'apiKey' => $api_key, + ), + ); - $response = wp_remote_post( PRAutoBlogger_Runware_Image_Support::API_URL, [ - 'timeout' => 15, - 'headers' => [ 'Content-Type' => 'application/json' ], - 'body' => wp_json_encode( $body ), - ] ); + $response = wp_remote_post( + PRAutoBlogger_Runware_Image_Support::API_URL, + array( + 'timeout' => 15, + 'headers' => array( 'Content-Type' => 'application/json' ), + 'body' => wp_json_encode( $body ), + ) + ); if ( is_wp_error( $response ) ) { - return [ + return array( 'status' => 'error', 'message' => __( 'Could not reach Runware API.', 'prautoblogger' ), 'debug' => $response->get_error_message(), - ]; + ); } $status = (int) wp_remote_retrieve_response_code( $response ); $raw = (string) wp_remote_retrieve_body( $response ); if ( 200 !== $status ) { - return [ + return array( 'status' => 'error', 'message' => sprintf( __( 'Runware returned HTTP %d.', 'prautoblogger' ), $status ), 'debug' => substr( $raw, 0, 200 ), - ]; + ); } $decoded = json_decode( $raw, true ); if ( is_array( $decoded ) && isset( $decoded['errors'] ) && ! empty( $decoded['errors'] ) ) { - $first = $decoded['errors'][0] ?? []; + $first = $decoded['errors'][0] ?? array(); $msg = is_array( $first ) ? (string) ( $first['message'] ?? '' ) : (string) $first; - return [ + return array( 'status' => 'error', 'message' => __( 'Runware rejected the API key.', 'prautoblogger' ), 'debug' => substr( $msg, 0, 200 ), - ]; + ); } - return [ 'status' => 'ok', 'message' => __( 'Runware API key valid.', 'prautoblogger' ) ]; + return array( + 'status' => 'ok', + 'message' => __( 'Runware API key valid.', 'prautoblogger' ), + ); } /** @@ -250,12 +265,12 @@ class PRAutoBlogger_Runware_Image_Provider implements PRAutoBlogger_Image_Provid int $seed, int $steps ): array { - return [ - [ + return array( + array( 'taskType' => 'authentication', 'apiKey' => $api_key, - ], - [ + ), + array( 'taskType' => 'imageInference', 'taskUUID' => wp_generate_uuid4(), 'positivePrompt' => $prompt, @@ -267,8 +282,8 @@ class PRAutoBlogger_Runware_Image_Provider implements PRAutoBlogger_Image_Provid 'outputFormat' => 'PNG', 'outputType' => 'URL', 'seed' => $seed, - ], - ]; + ), + ); } /** @@ -286,7 +301,10 @@ class PRAutoBlogger_Runware_Image_Provider implements PRAutoBlogger_Image_Provid throw new \InvalidArgumentException( sprintf( esc_html__( 'Image dimensions %1$dx%2$d outside supported range (%3$d–%4$d px).', 'prautoblogger' ), - $width, $height, self::MIN_DIMENSION_PX, self::MAX_DIMENSION_PX + $width, + $height, + self::MIN_DIMENSION_PX, + self::MAX_DIMENSION_PX ) ); } diff --git a/includes/providers/class-runware-image-support.php b/includes/providers/class-runware-image-support.php index 46bd39b..07e194e 100644 --- a/includes/providers/class-runware-image-support.php +++ b/includes/providers/class-runware-image-support.php @@ -68,7 +68,7 @@ class PRAutoBlogger_Runware_Image_Support { // Runware wraps errors in an `errors` array. if ( isset( $decoded['errors'] ) && is_array( $decoded['errors'] ) && ! empty( $decoded['errors'] ) ) { - $first = $decoded['errors'][0] ?? []; + $first = $decoded['errors'][0] ?? array(); $msg = is_array( $first ) ? (string) ( $first['message'] ?? wp_json_encode( $first ) ) : (string) $first; @@ -80,7 +80,7 @@ class PRAutoBlogger_Runware_Image_Support { ); } - $data = $decoded['data'] ?? []; + $data = $decoded['data'] ?? array(); if ( ! is_array( $data ) || empty( $data ) ) { throw new \RuntimeException( esc_html__( 'Runware response contained no data.', 'prautoblogger' ) @@ -115,9 +115,12 @@ class PRAutoBlogger_Runware_Image_Support { * @throws \RuntimeException On HTTP error or empty body. */ public function download_image_bytes( string $image_url ): string { - $response = wp_remote_get( $image_url, [ - 'timeout' => 30, - ] ); + $response = wp_remote_get( + $image_url, + array( + 'timeout' => 30, + ) + ); if ( is_wp_error( $response ) ) { throw new \RuntimeException( diff --git a/includes/providers/interface-image-provider.php b/includes/providers/interface-image-provider.php index 7a6a8d3..fd769fa 100644 --- a/includes/providers/interface-image-provider.php +++ b/includes/providers/interface-image-provider.php @@ -61,7 +61,7 @@ interface PRAutoBlogger_Image_Provider_Interface { * an invalid response shape. * @throws \InvalidArgumentException If dimensions are out of range. */ - public function generate_image( string $prompt, int $width, int $height, array $options = [] ): array; + public function generate_image( string $prompt, int $width, int $height, array $options = array() ): array; /** * Estimate the USD cost of a single generation call before making it. @@ -75,7 +75,7 @@ interface PRAutoBlogger_Image_Provider_Interface { * * @return float Estimated cost in USD for a single image at the given dimensions. */ - public function estimate_cost( int $width, int $height, array $options = [] ): float; + public function estimate_cost( int $width, int $height, array $options = array() ): float; /** * Machine-readable provider identifier used in logs and settings. diff --git a/includes/providers/interface-llm-provider.php b/includes/providers/interface-llm-provider.php index 28ce07e..07ad867 100755 --- a/includes/providers/interface-llm-provider.php +++ b/includes/providers/interface-llm-provider.php @@ -35,7 +35,7 @@ interface PRAutoBlogger_LLM_Provider_Interface { * * @throws \RuntimeException On API error after retries exhausted. */ - public function send_chat_completion( array $messages, string $model, array $options = [] ): array; + public function send_chat_completion( array $messages, string $model, array $options = array() ): array; /** * Get the list of available models from the provider. diff --git a/includes/services/class-open-router-model-normalizer.php b/includes/services/class-open-router-model-normalizer.php index 1086867..c582a29 100644 --- a/includes/services/class-open-router-model-normalizer.php +++ b/includes/services/class-open-router-model-normalizer.php @@ -23,15 +23,36 @@ class PRAutoBlogger_OpenRouter_Model_Normalizer { * * @var array */ - private const CAPABILITY_MAP = [ - 'text→text' => [ 'in' => [ 'text' ], 'out' => [ 'text' ] ], - 'text+image→text' => [ 'in' => [ 'text', 'image' ], 'out' => [ 'text' ] ], - 'text+audio→text' => [ 'in' => [ 'text', 'audio' ], 'out' => [ 'text' ] ], - 'text→image' => [ 'in' => [ 'text' ], 'out' => [ 'image' ] ], - 'text→audio' => [ 'in' => [ 'text' ], 'out' => [ 'audio' ] ], - 'text→video' => [ 'in' => [ 'text' ], 'out' => [ 'video' ] ], - 'text→embedding' => [ 'in' => [ 'text' ], 'out' => [ 'embedding' ] ], - ]; + private const CAPABILITY_MAP = array( + 'text→text' => array( + 'in' => array( 'text' ), + 'out' => array( 'text' ), + ), + 'text+image→text' => array( + 'in' => array( 'text', 'image' ), + 'out' => array( 'text' ), + ), + 'text+audio→text' => array( + 'in' => array( 'text', 'audio' ), + 'out' => array( 'text' ), + ), + 'text→image' => array( + 'in' => array( 'text' ), + 'out' => array( 'image' ), + ), + 'text→audio' => array( + 'in' => array( 'text' ), + 'out' => array( 'audio' ), + ), + 'text→video' => array( + 'in' => array( 'text' ), + 'out' => array( 'video' ), + ), + 'text→embedding' => array( + 'in' => array( 'text' ), + 'out' => array( 'embedding' ), + ), + ); /** * Normalize raw OpenRouter model records into the standardized shape. @@ -54,15 +75,15 @@ class PRAutoBlogger_OpenRouter_Model_Normalizer { * }> Normalized records, sorted by name ascending. */ public function normalize( array $raw_models ): array { - $normalized = []; + $normalized = array(); foreach ( $raw_models as $model ) { if ( ! is_array( $model ) || ! isset( $model['id'] ) ) { continue; } - $input_modalities = (array) ( $model['architecture']['input_modalities'] ?? [ 'text' ] ); - $output_modalities = (array) ( $model['architecture']['output_modalities'] ?? [ 'text' ] ); + $input_modalities = (array) ( $model['architecture']['input_modalities'] ?? array( 'text' ) ); + $output_modalities = (array) ( $model['architecture']['output_modalities'] ?? array( 'text' ) ); $name_parts = explode( '/', (string) $model['id'], 2 ); @@ -70,7 +91,7 @@ class PRAutoBlogger_OpenRouter_Model_Normalizer { $prompt_price = (float) ( $model['pricing']['prompt'] ?? 0 ); $completion_price = (float) ( $model['pricing']['completion'] ?? 0 ); - $normalized[] = [ + $normalized[] = array( 'id' => (string) $model['id'], 'name' => (string) ( $model['name'] ?? $model['id'] ), 'provider' => $name_parts[0] ?? 'unknown', @@ -80,12 +101,15 @@ class PRAutoBlogger_OpenRouter_Model_Normalizer { 'capabilities' => $this->derive_capabilities( $input_modalities, $output_modalities ), 'deprecated' => false, 'updated_at' => (int) ( $model['created'] ?? 0 ), - ]; + ); } - usort( $normalized, static function ( array $a, array $b ): int { - return strcasecmp( $a['name'], $b['name'] ); - } ); + usort( + $normalized, + static function ( array $a, array $b ): int { + return strcasecmp( $a['name'], $b['name'] ); + } + ); return $normalized; } @@ -99,7 +123,7 @@ class PRAutoBlogger_OpenRouter_Model_Normalizer { * @return string[] Matched capability labels. Defaults to ['text→text']. */ private function derive_capabilities( array $input_modalities, array $output_modalities ): array { - $caps = []; + $caps = array(); foreach ( self::CAPABILITY_MAP as $label => $requirements ) { $input_match = empty( array_diff( $requirements['in'], $input_modalities ) ); @@ -109,6 +133,6 @@ class PRAutoBlogger_OpenRouter_Model_Normalizer { } } - return empty( $caps ) ? [ 'text→text' ] : $caps; + return empty( $caps ) ? array( 'text→text' ) : $caps; } } diff --git a/includes/services/class-open-router-model-registry.php b/includes/services/class-open-router-model-registry.php index 15611a0..9378441 100644 --- a/includes/services/class-open-router-model-registry.php +++ b/includes/services/class-open-router-model-registry.php @@ -52,11 +52,11 @@ class PRAutoBlogger_OpenRouter_Model_Registry implements PRAutoBlogger_Model_Reg ) { $this->option_name = $option_name; $this->fetched_at_option = $option_name . '_fetched_at'; - $this->transient_name = $transient_name; - $this->endpoint = $endpoint; - $this->cache_ttl = $cache_ttl_seconds; + $this->transient_name = $transient_name; + $this->endpoint = $endpoint; + $this->cache_ttl = $cache_ttl_seconds; $this->idempotency_window = $idempotency_seconds; - $this->normalizer = new PRAutoBlogger_OpenRouter_Model_Normalizer(); + $this->normalizer = new PRAutoBlogger_OpenRouter_Model_Normalizer(); } /** {@inheritDoc} */ @@ -70,7 +70,7 @@ class PRAutoBlogger_OpenRouter_Model_Registry implements PRAutoBlogger_Model_Reg array_filter( $this->load_payload(), static function ( array $model ) use ( $capability ): bool { - return in_array( $capability, $model['capabilities'] ?? [], true ); + return in_array( $capability, $model['capabilities'] ?? array(), true ); } ) ); @@ -92,14 +92,20 @@ class PRAutoBlogger_OpenRouter_Model_Registry implements PRAutoBlogger_Model_Reg if ( ! $force && $fetched_at > 0 && ( time() - $fetched_at ) < $this->idempotency_window ) { $payload = $this->load_payload(); - return [ 'count' => count( $payload ), 'fetched_at' => $fetched_at ]; + return array( + 'count' => count( $payload ), + 'fetched_at' => $fetched_at, + ); } $raw_models = $this->fetch_from_api(); if ( null === $raw_models ) { $this->flag_stale(); $stale = $this->load_from_option(); - return [ 'count' => count( $stale ), 'fetched_at' => $fetched_at ]; + return array( + 'count' => count( $stale ), + 'fetched_at' => $fetched_at, + ); } $normalized = $this->normalizer->normalize( $raw_models ); @@ -113,7 +119,10 @@ class PRAutoBlogger_OpenRouter_Model_Registry implements PRAutoBlogger_Model_Reg self::LOG_CONTEXT ); - return [ 'count' => count( $normalized ), 'fetched_at' => $now ]; + return array( + 'count' => count( $normalized ), + 'fetched_at' => $now, + ); } /** {@inheritDoc} */ @@ -141,8 +150,8 @@ class PRAutoBlogger_OpenRouter_Model_Registry implements PRAutoBlogger_Model_Reg /** @return array */ private function load_from_option(): array { - $data = get_option( $this->option_name, [] ); - return is_array( $data ) ? $data : []; + $data = get_option( $this->option_name, array() ); + return is_array( $data ) ? $data : array(); } private function save_payload( array $payload, int $now ): void { @@ -161,7 +170,7 @@ class PRAutoBlogger_OpenRouter_Model_Registry implements PRAutoBlogger_Model_Reg $base_delay = defined( 'PRAUTOBLOGGER_RETRY_BASE_DELAY_SECONDS' ) ? PRAUTOBLOGGER_RETRY_BASE_DELAY_SECONDS : 2; for ( $attempt = 1; $attempt <= $max_retries; $attempt++ ) { - $response = wp_remote_get( $this->endpoint, [ 'timeout' => self::HTTP_TIMEOUT ] ); + $response = wp_remote_get( $this->endpoint, array( 'timeout' => self::HTTP_TIMEOUT ) ); if ( is_wp_error( $response ) ) { PRAutoBlogger_Logger::instance()->warning( diff --git a/prautoblogger.php b/prautoblogger.php index 0557da1..11f4be3 100644 --- a/prautoblogger.php +++ b/prautoblogger.php @@ -91,8 +91,8 @@ require_once PRAUTOBLOGGER_PLUGIN_DIR . 'includes/class-prautoblogger.php'; |-------------------------------------------------------------------------- */ -register_activation_hook( __FILE__, [ 'PRAutoBlogger_Activator', 'activate' ] ); -register_deactivation_hook( __FILE__, [ 'PRAutoBlogger_Deactivator', 'deactivate' ] ); +register_activation_hook( __FILE__, array( 'PRAutoBlogger_Activator', 'activate' ) ); +register_deactivation_hook( __FILE__, array( 'PRAutoBlogger_Deactivator', 'deactivate' ) ); /* |-------------------------------------------------------------------------- @@ -116,6 +116,9 @@ function prautoblogger(): PRAutoBlogger { } // Initialize on plugins_loaded so all dependencies are available. -add_action( 'plugins_loaded', static function (): void { - prautoblogger()->run(); -} ); +add_action( + 'plugins_loaded', + static function (): void { + prautoblogger()->run(); + } +); diff --git a/uninstall.php b/uninstall.php index 865ecac..b5d38e0 100755 --- a/uninstall.php +++ b/uninstall.php @@ -24,13 +24,13 @@ global $wpdb; */ $prefix = $wpdb->prefix . 'prautoblogger_'; -$tables = [ +$tables = array( $prefix . 'source_data', $prefix . 'analysis_results', $prefix . 'generation_log', $prefix . 'content_scores', $prefix . 'event_log', -]; +); foreach ( $tables as $table ) { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table names are hardcoded above, not user input. @@ -77,10 +77,10 @@ $wpdb->query( |-------------------------------------------------------------------------- */ -$hooks = [ +$hooks = array( 'prautoblogger_daily_generation', 'prautoblogger_collect_metrics', -]; +); foreach ( $hooks as $hook ) { $timestamp = wp_next_scheduled( $hook );