__( 'Analytics', 'saddle-analytics' ), 'product' => 'Saddle Analytics', 'version' => SADDLE_ANALYTICS_VERSION, 'summary' => __( 'Visitors, sources, pages and AI traffic, counted on this site.', 'saddle-analytics' ), 'order' => 30, 'capability' => 'manage_options', // One page (planning/ANALYTICS-ONE-PAGE.md): no sidebar, no tab row. // Settings opens from the page's gear. Core 1.5.0 ignores 'layout' // and draws Overview and Settings as two sections, which still works. 'tabs' => array( 'overview' => __( 'Overview', 'saddle-analytics' ), ), 'layout' => 'page', 'icon' => 'graph-up', // Iconoir name. 'script' => self::SCRIPT, 'content' => 'screens', 'status' => array( __CLASS__, 'status' ), 'setup' => array( __CLASS__, 'setup' ), 'settings' => array( __CLASS__, 'settings' ), ); return $modules; } /** True once any visitor row exists. Visitor rows outlive pruning. */ private static function has_visitors(): bool { global $wpdb; $t = Saddle_Analytics_Install::tables(); return null !== $wpdb->get_var( $wpdb->prepare( 'SELECT visitor_id FROM %i LIMIT 1', $t['visitors'] ) ); } /** @return array{state:string,line:string} */ public static function status(): array { if ( Saddle_Analytics_Migrate::blocking() ) { return array( 'state' => 'off', 'line' => __( 'Tracking is off', 'saddle-analytics' ), ); } if ( ! self::has_visitors() ) { return array( 'state' => 'needs-setup', 'line' => __( 'No visit counted yet', 'saddle-analytics' ), ); } $today = (int) Saddle_Analytics::report()->summary( 'today' )['visitors']; return array( 'state' => 'ready', 'line' => sprintf( /* translators: %s: number of visitors today. */ _n( '%s visitor today', '%s visitors today', $today, 'saddle-analytics' ), number_format_i18n( $today ) ), ); } /** @return array[] */ public static function setup(): array { $tracking = ! Saddle_Analytics_Migrate::blocking(); $counted = $tracking && self::has_visitors(); return array( array( 'id' => 'tracker', 'title' => __( 'Start tracking', 'saddle-analytics' ), 'done' => $tracking, 'line' => $tracking ? '' : __( 'Tracking waits while your old data moves over.', 'saddle-analytics' ), ), array( 'id' => 'first-visit', 'title' => __( 'Count your first visit', 'saddle-analytics' ), 'done' => $counted, 'line' => $counted ? '' : __( 'Open your site in a private window. Your own visits are not counted.', 'saddle-analytics' ), 'action' => array( 'label' => __( 'Open your site', 'saddle-analytics' ), 'url' => home_url( '/' ), 'external' => true, ), 'after' => 'tracker', ), ); } /** The settings Core draws on the Settings tab and shows agents. */ public static function settings(): array { $tracking = __( 'Tracking', 'saddle-analytics' ); $data = __( 'Data', 'saddle-analytics' ); return array( 'title' => 'Saddle Analytics', 'store' => array( 'get' => array( __CLASS__, 'read' ), 'set' => array( __CLASS__, 'write' ), 'options' => array( Saddle_Analytics_Settings::OPTION, 'saddle_analytics_delete_data_on_uninstall' ), ), 'fields' => array( 'remember_visitors' => array( 'type' => 'boolean', 'default' => false, 'label' => __( 'Remember returning visitors', 'saddle-analytics' ), 'help' => __( 'Off: no cookies, and a visitor is recognised for the rest of the day. On: a first-party cookie recognises them for a year. In the EU and UK this usually needs consent.', 'saddle-analytics' ), 'section' => $tracking, ), 'attribution' => array( 'type' => 'string', 'enum' => array( 'first', 'last' ), 'default' => 'first', 'label' => __( 'Credit a returning visitor to', 'saddle-analytics' ), 'help' => __( 'Source reports show the first or the last click. Both are stored. This applies only when visitors are remembered.', 'saddle-analytics' ), 'section' => $tracking, ), 'track_admins' => array( 'type' => 'boolean', 'default' => false, 'label' => __( 'Count logged-in admins', 'saddle-analytics' ), 'help' => __( 'Off, so your own visits do not inflate the numbers.', 'saddle-analytics' ), 'section' => $tracking, ), 'retention_days' => array( 'type' => 'integer', 'default' => 90, 'minimum' => Saddle_Analytics_Settings::RETENTION_MIN, 'maximum' => Saddle_Analytics_Settings::RETENTION_MAX, 'label' => __( 'Keep page views for (days)', 'saddle-analytics' ), 'help' => __( 'Older page views and crawler counts are deleted daily. Visitor totals are kept.', 'saddle-analytics' ), 'section' => $data, ), 'delete_data_on_uninstall' => array( 'type' => 'boolean', 'default' => false, 'label' => __( 'Delete all data on uninstall', 'saddle-analytics' ), 'help' => __( 'Deleting the plugin then drops its tables.', 'saddle-analytics' ), 'level' => 'advanced', 'destructive' => true, 'section' => $data, ), ), ); } public static function read(): array { return Saddle_Analytics_Settings::all(); } /** Changed keys only; Saddle_Analytics_Settings drops the unknown and coerces the rest. */ public static function write( $values ) { Saddle_Analytics_Settings::update( is_array( $values ) ? $values : array() ); return true; } }