diff --git a/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-blog-stats.php b/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-blog-stats.php index b127f64ab6b46..3ef40782d57c2 100644 --- a/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-blog-stats.php +++ b/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-blog-stats.php @@ -63,7 +63,7 @@ public function get_blog_stats( $request ) { ( new WPCOM_Stats() )->get_stats( array( 'fields' => 'stats' ) ) ); - if ( ! isset( $blog_data->stats->views ) ) { + if ( ! isset( $blog_data->stats->views ) || ! isset( $blog_data->stats->visitors ) ) { return false; } @@ -72,8 +72,9 @@ public function get_blog_stats( $request ) { } return array( - 'post-views' => $post_data->views, - 'blog-views' => $blog_data->stats->views, + 'post-views' => $post_data->views, + 'blog-visitors' => $blog_data->stats->visitors, + 'blog-views' => $blog_data->stats->views, ); } } diff --git a/projects/plugins/jetpack/changelog/add-blog-stats-visitors b/projects/plugins/jetpack/changelog/add-blog-stats-visitors new file mode 100644 index 0000000000000..47ef98f81b9a1 --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-blog-stats-visitors @@ -0,0 +1,4 @@ +Significance: minor +Type: enhancement + +Blog Stats Block: allow displaying site's number of visitors. diff --git a/projects/plugins/jetpack/extensions/blocks/blog-stats/block.json b/projects/plugins/jetpack/extensions/blocks/blog-stats/block.json index a29f588cb4d0e..7a49113967e81 100644 --- a/projects/plugins/jetpack/extensions/blocks/blog-stats/block.json +++ b/projects/plugins/jetpack/extensions/blocks/blog-stats/block.json @@ -4,7 +4,7 @@ "name": "jetpack/blog-stats", "title": "Blog Stats", "description": "Show a stats counter for your blog.", - "keywords": [ "views", "hits", "analytics", "counter" ], + "keywords": [ "views", "hits", "analytics", "counter", "visitors" ], "version": "1.0", "textdomain": "jetpack", "category": "grow", @@ -31,6 +31,10 @@ "label": { "type": "string" }, + "statsData": { + "type": "string", + "default": "views" + }, "statsOption": { "type": "string", "default": "site" diff --git a/projects/plugins/jetpack/extensions/blocks/blog-stats/blog-stats.php b/projects/plugins/jetpack/extensions/blocks/blog-stats/blog-stats.php index 81ed1209c10b0..6f39903b90168 100644 --- a/projects/plugins/jetpack/extensions/blocks/blog-stats/blog-stats.php +++ b/projects/plugins/jetpack/extensions/blocks/blog-stats/blog-stats.php @@ -44,7 +44,7 @@ function register_block() { function load_assets( $attributes ) { Jetpack_Gutenberg::load_assets_as_required( __DIR__ ); - $views = 0; + $stats = 0; // For when there's no post ID - eg. search pages. if ( $attributes['statsOption'] === 'post' && ! get_the_ID() ) { @@ -71,28 +71,32 @@ function load_assets( $attributes ) { ); if ( isset( $data->views ) ) { - $views = $data->views; + $stats = $data->views; } } else { $data = convert_stats_array_to_object( ( new WPCOM_Stats() )->get_stats( array( 'fields' => 'stats' ) ) ); - if ( isset( $data->stats->views ) ) { - $views = $data->stats->views; + if ( $attributes['statsData'] === 'views' && isset( $data->stats->views ) ) { + $stats = $data->stats->views; + } + + if ( $attributes['statsData'] === 'visitors' && isset( $data->stats->visitors ) ) { + $stats = $data->stats->visitors; } } - $label = $attributes['label'] ? $attributes['label'] : esc_html( + $fallback_label = $attributes['statsData'] === 'visitors' ? esc_html( + /* Translators: Number of visitors */ + _n( 'visitor', 'visitors', $stats, 'jetpack' ) + ) : esc_html( /* Translators: Number of views */ - _n( - 'hit', - 'hits', - $views, - 'jetpack' - ) + _n( 'hit', 'hits', $stats, 'jetpack' ) ); + $label = $attributes['label'] ? $attributes['label'] : $fallback_label; + $wrapper_attributes = \WP_Block_Supports::get_instance()->apply_block_supports(); return sprintf( @@ -100,7 +104,7 @@ function load_assets( $attributes ) { ! empty( $attributes['className'] ) ? ' ' . esc_attr( $attributes['className'] ) : '', ! empty( $wrapper_attributes['class'] ) ? ' ' . esc_attr( $wrapper_attributes['class'] ) : '', ! empty( $wrapper_attributes['style'] ) ? ' style="' . esc_attr( $wrapper_attributes['style'] ) . '"' : '', - esc_html( number_format_i18n( $views ) ), + esc_html( number_format_i18n( $stats ) ), wp_kses_post( $label ) ); } diff --git a/projects/plugins/jetpack/extensions/blocks/blog-stats/controls.js b/projects/plugins/jetpack/extensions/blocks/blog-stats/controls.js index 3b9a815979325..25da773f91709 100644 --- a/projects/plugins/jetpack/extensions/blocks/blog-stats/controls.js +++ b/projects/plugins/jetpack/extensions/blocks/blog-stats/controls.js @@ -2,9 +2,20 @@ import { PanelBody, RadioControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; export function BlogStatsInspectorControls( { attributes, setAttributes } ) { - const { statsOption } = attributes; + const { statsData, statsOption } = attributes; - const RADIO_OPTIONS = [ + const STATS_DATA_RADIO = [ + { + value: 'views', + label: __( 'Views', 'jetpack' ), + }, + { + value: 'visitors', + label: __( 'Visitors', 'jetpack' ), + }, + ]; + + const STATS_OPTION_RADIO = [ { value: 'site', label: __( 'My whole site', 'jetpack' ), @@ -18,11 +29,27 @@ export function BlogStatsInspectorControls( { attributes, setAttributes } ) { return ( <> + setAttributes( { statsData: value } ) } + options={ STATS_DATA_RADIO } + help={ __( + 'Views represent site visits, whereas visitors represent unique individuals.', + 'jetpack' + ) } + /> setAttributes( { statsOption: value } ) } - options={ RADIO_OPTIONS } + options={ STATS_OPTION_RADIO } + disabled={ statsData === 'visitors' } + help={ + statsData === 'visitors' + ? __( "Visitor counts aren't available for individual posts.", 'jetpack' ) + : null + } /> { __( 'Stats are delayed for up to 5 minutes.', 'jetpack' ) } diff --git a/projects/plugins/jetpack/extensions/blocks/blog-stats/edit.js b/projects/plugins/jetpack/extensions/blocks/blog-stats/edit.js index 1d35626a7267c..789673de74d83 100644 --- a/projects/plugins/jetpack/extensions/blocks/blog-stats/edit.js +++ b/projects/plugins/jetpack/extensions/blocks/blog-stats/edit.js @@ -11,10 +11,13 @@ import { InactiveStatsPlaceholder } from './inactive-placeholder'; function BlogStatsEdit( { attributes, className, setAttributes } ) { const { isLoadingModules, isChangingStatus, isModuleActive, changeStatus } = useModuleStatus( 'stats' ); - const { label, statsOption } = attributes; + const { label, statsData, statsOption } = attributes; const [ blogViews, setBlogViews ] = useState( null ); + const [ blogVisitors, setBlogVisitors ] = useState(); const [ postViews, setPostViews ] = useState(); - const views = statsOption === 'post' ? postViews : blogViews; + + const blogStats = statsData === 'views' ? blogViews : blogVisitors; + const stats = statsOption === 'post' ? postViews : blogStats; const postId = useSelect( select => select( 'core/editor' ).getCurrentPostId(), [] ); @@ -26,6 +29,7 @@ function BlogStatsEdit( { attributes, className, setAttributes } ) { : '/wpcom/v2/blog-stats', } ).then( response => { setBlogViews( response[ 'blog-views' ] ); + setBlogVisitors( response[ 'blog-visitors' ] ); // Display "12,345" as an obvious placeholder when we have no Post ID. // Applies to widgets, FSE templates etc. @@ -34,6 +38,13 @@ function BlogStatsEdit( { attributes, className, setAttributes } ) { } }, [ postId, isModuleActive ] ); + // We don't collect visitor data for individual posts. + useEffect( () => { + if ( statsData === 'visitors' ) { + setAttributes( { statsOption: 'site' } ); + } + }, [ statsData, setAttributes ] ); + if ( ! isModuleActive && ! isLoadingModules ) { return ( @@ -55,13 +74,10 @@ function BlogStatsEdit( { attributes, className, setAttributes } ) {

{ __( 'Loading stats…', 'jetpack' ) }

) : (

- { numberFormat( views ) } + { numberFormat( stats ) } setAttributes( { label: newLabel } ) } diff --git a/projects/plugins/jetpack/extensions/blocks/blog-stats/editor.scss b/projects/plugins/jetpack/extensions/blocks/blog-stats/editor.scss index aa02e1a34ac55..89cf6e2db37cf 100644 --- a/projects/plugins/jetpack/extensions/blocks/blog-stats/editor.scss +++ b/projects/plugins/jetpack/extensions/blocks/blog-stats/editor.scss @@ -1,5 +1,3 @@ -@import '@automattic/jetpack-base-styles/gutenberg-base-styles'; - .wp-block-jetpack-blog-stats { .jetpack-blog-stats__loading { // Same as RichText component's placeholder opacity from Core. @@ -12,5 +10,5 @@ } .jetpack-blog-stats__delay-notice { - color: $gray-700; + font-size: 12px; } diff --git a/projects/plugins/jetpack/extensions/blocks/blog-stats/test/controls.js b/projects/plugins/jetpack/extensions/blocks/blog-stats/test/controls.js index 65081051304e4..69637cfd20e97 100644 --- a/projects/plugins/jetpack/extensions/blocks/blog-stats/test/controls.js +++ b/projects/plugins/jetpack/extensions/blocks/blog-stats/test/controls.js @@ -5,6 +5,7 @@ import { BlogStatsInspectorControls } from '../controls'; describe( 'BlogStatsControls', () => { const defaultAttributes = { label: 'hits', + statsData: 'views', statsOption: 'site', }; @@ -19,10 +20,30 @@ describe( 'BlogStatsControls', () => { } ); describe( 'Inspector settings', () => { - test( 'loads and displays settings', () => { + test( 'loads and displays views or visitors settings', () => { + render( ); + + expect( screen.getByLabelText( 'Views' ) ).toBeInTheDocument(); + expect( screen.getByLabelText( 'Visitors' ) ).toBeInTheDocument(); + } ); + + test( 'defaults stats data to views', () => { + render( ); + + expect( screen.getByLabelText( 'Views' ) ).toBeChecked(); + } ); + + test( 'sets the statsData attribute', async () => { + const user = userEvent.setup(); + render( ); + await user.click( screen.getByLabelText( 'Visitors' ) ); + + expect( setAttributes ).toHaveBeenCalledWith( { statsData: 'visitors' } ); + } ); + + test( 'loads and displays option settings', () => { render( ); - expect( screen.getByText( 'Settings' ) ).toBeInTheDocument(); expect( screen.getByLabelText( 'My whole site' ) ).toBeInTheDocument(); expect( screen.getByLabelText( 'This individual post' ) ).toBeInTheDocument(); } ); diff --git a/projects/plugins/jetpack/extensions/blocks/blog-stats/test/fixtures/jetpack__blog__stats.json b/projects/plugins/jetpack/extensions/blocks/blog-stats/test/fixtures/jetpack__blog__stats.json index ee897e0720944..7d96889e5e41c 100644 --- a/projects/plugins/jetpack/extensions/blocks/blog-stats/test/fixtures/jetpack__blog__stats.json +++ b/projects/plugins/jetpack/extensions/blocks/blog-stats/test/fixtures/jetpack__blog__stats.json @@ -4,6 +4,7 @@ "name": "jetpack/blog-stats", "isValid": true, "attributes": { + "statsData": "views", "statsOption": "site" }, "innerBlocks": [],