repo = new ViewsRepository(); } public function init(): void { add_shortcode( 'pulseviews', [ $this, 'render_shortcode' ] ); $settings = get_option( 'pulseviews_settings', [] ); $position = $settings['auto_insert'] ?? 'none'; if ( 'before' === $position ) { add_filter( 'the_content', [ $this, 'auto_insert_before' ], 10 ); } elseif ( 'after' === $position ) { add_filter( 'the_content', [ $this, 'auto_insert_after' ], 10 ); } } /** * [pulseviews] shortcode. * * Attributes: * id = post ID (defaults to current post) * style = 1|2|3|4 * variant = outline|filled|accent * period = total|today|week|month * label = custom label text, e.g. "readers" or "hits" (overrides global) * * @param array|string $atts */ public function render_shortcode( array|string $atts ): string { $settings = get_option( 'pulseviews_settings', [] ); $atts = shortcode_atts( [ 'id' => get_the_ID() ?: 0, 'style' => $settings['default_style'] ?? '1', 'variant' => $settings['default_variant'] ?? 'outline', 'period' => 'total', 'label' => $settings['views_label'] ?? 'views', ], is_array( $atts ) ? $atts : [] ); $post_id = (int) $atts['id']; if ( ! $post_id ) { return ''; } $views = $this->repo->get_post_views( $post_id, $atts['period'] ); return StyleRegistry::render( (int) $atts['style'], $views, [ 'post_id' => $post_id, 'variant' => sanitize_key( $atts['variant'] ), 'label' => sanitize_text_field( $atts['label'] ), ] ); } /** * Auto-insert before content. * Skips post types not in the display_post_types setting (e.g. pages). */ public function auto_insert_before( string $content ): string { if ( ! $this->should_display() ) { return $content; } return $this->render_shortcode( [] ) . $content; } /** * Auto-insert after content. * Skips post types not in the display_post_types setting (e.g. pages). */ public function auto_insert_after( string $content ): string { if ( ! $this->should_display() ) { return $content; } return $content . $this->render_shortcode( [] ); } // ── Private ─────────────────────────────────────────────────────────────── /** * Check whether the view badge should be displayed on the current post type. * * Tracking (counting) is separate from display — pages can be counted * without showing a badge. This controls display only. */ private function should_display(): bool { if ( ! is_singular() ) { return false; } $post = get_post(); if ( ! $post ) { return false; } $settings = get_option( 'pulseviews_settings', [] ); $display_post_types = (array) ( $settings['display_post_types'] ?? [ 'post' ] ); /** * Filter: control which post types show the view badge. * * Note: this is separate from tracked_post_types — pages can be * counted silently without showing a badge. * * @param array $display_post_types Post type slugs that show the badge. * @param \WP_Post $post Current post object. * @since 1.0.0 */ $display_post_types = (array) apply_filters( 'pulseviews/display_post_types', $display_post_types, $post ); return in_array( $post->post_type, $display_post_types, true ); } }