Skip to content

Commit e1a6f0e

Browse files
authored
Merge pull request #11673 from google/enhancement/11433-pue-pointer
2 parents 6cf36ac + a6a3b26 commit e1a6f0e

File tree

17 files changed

+661
-49
lines changed

17 files changed

+661
-49
lines changed

assets/js/components/ScrollEffect.js renamed to assets/js/components/CoreDashboardEffects.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
2-
* ScrollEffect component.
2+
* CoreDashboardEffects component.
33
*
4-
* Site Kit by Google, Copyright 2022 Google LLC
4+
* Site Kit by Google, Copyright 2025 Google LLC
55
*
66
* Licensed under the Apache License, Version 2.0 (the "License");
77
* you may not use this file except in compliance with the License.
@@ -19,9 +19,11 @@
1919
/**
2020
* Internal dependencies
2121
*/
22+
import useOpenEmailReportingSelectionPanelEffect from '@/js/hooks/useOpenEmailReportingSelectionPanelEffect';
2223
import { useHasScrolledEffect } from '@/js/hooks/useHasScrolledEffect';
2324

24-
export default function ScrollEffect() {
25+
export default function CoreDashboardEffects() {
26+
useOpenEmailReportingSelectionPanelEffect();
2527
useHasScrolledEffect();
2628

2729
return null;

assets/js/components/DashboardEntityApp.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ import { Cell, Grid, Row } from '@/js/material-components';
5757
import PageHeader from './PageHeader';
5858
import Layout from './layout/Layout';
5959
import { CORE_WIDGETS } from '@/js/googlesitekit/widgets/datastore/constants';
60-
import ScrollEffect from './ScrollEffect';
6160
import DashboardSharingSettingsButton from './dashboard-sharing/DashboardSharingSettingsButton';
6261
import useViewOnly from '@/js/hooks/useViewOnly';
6362
import OfflineNotification from './notifications/OfflineNotification';
6463
import { useMonitorInternetConnection } from '@/js/hooks/useMonitorInternetConnection';
64+
import CoreDashboardEffects from './CoreDashboardEffects';
6565
import ModuleDashboardEffects from './ModuleDashboardEffects';
6666
import UserSettingsSelectionPanel from './email-reporting/UserSettingsSelectionPanel';
6767
import { useFeature } from '@/js/hooks/useFeature';
@@ -144,7 +144,7 @@ function DashboardEntityApp() {
144144
if ( currentEntityURL === null ) {
145145
return (
146146
<div className="googlesitekit-widget-context googlesitekit-module-page googlesitekit-entity-dashboard">
147-
<ScrollEffect />
147+
<CoreDashboardEffects />
148148
<ModuleDashboardEffects />
149149
<Grid>
150150
<Row>
@@ -217,7 +217,7 @@ function DashboardEntityApp() {
217217
}
218218
return (
219219
<Fragment>
220-
<ScrollEffect />
220+
<CoreDashboardEffects />
221221
<ModuleDashboardEffects />
222222
<Header showNavigation>
223223
<EntitySearchInput />

assets/js/components/DashboardMainApp.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ import DateRangeSelector from './DateRangeSelector';
4848
import HelpMenu from './help/HelpMenu';
4949
import SurveyViewTrigger from './surveys/SurveyViewTrigger';
5050
import CurrentSurveyPortal from './surveys/CurrentSurveyPortal';
51-
import ScrollEffect from './ScrollEffect';
5251
import MetricsSelectionPanel from './KeyMetrics/MetricsSelectionPanel';
5352
import UserSettingsSelectionPanel from './email-reporting/UserSettingsSelectionPanel';
5453
import { useFeature } from '@/js/hooks/useFeature';
@@ -68,6 +67,7 @@ import useViewOnly from '@/js/hooks/useViewOnly';
6867
import { CORE_FORMS } from '@/js/googlesitekit/datastore/forms/constants';
6968
import OfflineNotification from './notifications/OfflineNotification';
7069
import ModuleDashboardEffects from './ModuleDashboardEffects';
70+
import CoreDashboardEffects from './CoreDashboardEffects';
7171
import { useBreakpoint } from '@/js/hooks/useBreakpoint';
7272
import { useMonitorInternetConnection } from '@/js/hooks/useMonitorInternetConnection';
7373
import useQueryArg from '@/js/hooks/useQueryArg';
@@ -248,7 +248,7 @@ export default function DashboardMainApp() {
248248

249249
return (
250250
<Fragment>
251-
<ScrollEffect />
251+
<CoreDashboardEffects />
252252
<ModuleDashboardEffects />
253253

254254
<AdminScreenTooltip />
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Open Email Reporting Selection Panel hook.
3+
*
4+
* Site Kit by Google, Copyright 2025 Google LLC
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
/**
20+
* External dependencies
21+
*/
22+
import { useMount } from 'react-use';
23+
24+
/**
25+
* Internal dependencies
26+
*/
27+
import { useDispatch } from 'googlesitekit-data';
28+
import useQueryArg from '@/js/hooks/useQueryArg';
29+
import { CORE_UI } from '@/js/googlesitekit/datastore/ui/constants';
30+
import { USER_SETTINGS_SELECTION_PANEL_OPENED_KEY } from '@/js/components/email-reporting/constants';
31+
32+
export default function useOpenEmailReportingSelectionPanelEffect() {
33+
const [ emailReportingPanelOpen, setEmailReportingPanelOpen ] = useQueryArg(
34+
'email-reporting-panel'
35+
);
36+
const { setValue: setUIValue } = useDispatch( CORE_UI );
37+
38+
useMount( () => {
39+
// If redirected from a pointer CTA or following link from email footer, open the Email Reporting selection panel.
40+
if ( emailReportingPanelOpen !== undefined ) {
41+
setUIValue( USER_SETTINGS_SELECTION_PANEL_OPENED_KEY, true );
42+
setEmailReportingPanelOpen( undefined );
43+
}
44+
} );
45+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Pointers styles for WP Dashboard
3+
*
4+
* Site Kit by Google, Copyright 2025 Google LLC
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
.googlesitekit-pointer-cta--dismiss {
20+
align-items: center;
21+
background-color: $c-white;
22+
border: none;
23+
border-radius: 50%;
24+
display: flex;
25+
justify-content: center;
26+
position: absolute;
27+
right: 10px;
28+
top: 12px;
29+
30+
&:hover {
31+
cursor: pointer;
32+
}
33+
}
34+
35+
.googlesitekit-pointer-buttons {
36+
margin-top: 55px;
37+
padding-bottom: 0;
38+
padding-left: 20px;
39+
padding-right: 20px;
40+
}
41+
42+
.googlesitekit-email-pointer {
43+
.wp-pointer-content h3::before {
44+
content: "\f466"; // Email icon
45+
font-family: dashicons, sans-serif;
46+
margin-right: 8px;
47+
}
48+
49+
.wp-pointer-content h4 {
50+
line-height: 24px;
51+
margin-bottom: 0;
52+
margin-top: 16px;
53+
}
54+
55+
.wp-pointer-content p {
56+
margin-top: 0;
57+
}
58+
}

assets/sass/wpdashboard.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
@import "components/wp-dashboard/googlesitekit-unique-visitors-chart-widget";
6666
@import "components/wp-dashboard/googlesitekit-wp-dashboard";
6767
@import "components/wp-dashboard/googlesitekit-wp-dashboard-stats";
68+
@import "components/wp-dashboard/googlesitekit-pointers";
6869

6970
// Charts
7071
@import "components/dashboard/googlesitekit-dashboard-charts";

includes/Core/Admin/Pointer.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ public function __construct( $slug, array $args ) {
6464
'target_id' => '',
6565
'position' => 'top',
6666
'active_callback' => null,
67+
'buttons' => null,
68+
'class' => '',
6769
)
6870
);
6971
}
@@ -90,6 +92,28 @@ public function get_title() {
9092
return $this->args['title'];
9193
}
9294

95+
/**
96+
* Gets the pointer buttons.
97+
*
98+
* @since n.e.x.t
99+
*
100+
* @return string Pointer buttons.
101+
*/
102+
public function get_buttons() {
103+
return $this->args['buttons'];
104+
}
105+
106+
/**
107+
* Gets the pointer custom class.
108+
*
109+
* @since n.e.x.t
110+
*
111+
* @return string|array Pointer custom class.
112+
*/
113+
public function get_class() {
114+
return $this->args['class'];
115+
}
116+
93117
/**
94118
* Gets the pointer content.
95119
*

includes/Core/Admin/Pointers.php

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ function ( Pointer $pointer ) use ( $hook_suffix ) {
6262
}
6363

6464
wp_enqueue_style( 'wp-pointer' );
65+
// Dashboard styles are required where pointers are used to ensure proper styling.
66+
wp_enqueue_style( 'googlesitekit-wp-dashboard-css' );
6567
wp_enqueue_script( 'wp-pointer' );
6668

6769
add_action(
@@ -103,6 +105,7 @@ function ( $pointer ) {
103105
* Prints script for a given pointer.
104106
*
105107
* @since 1.83.0
108+
* @since n.e.x.t Updated to support buttons and header dismiss icon.
106109
*
107110
* @param Pointer $pointer Pointer to print.
108111
*/
@@ -112,38 +115,82 @@ private function print_pointer_script( $pointer ) {
112115
return;
113116
}
114117

115-
$slug = $pointer->get_slug();
118+
$buttons = $pointer->get_buttons();
119+
if ( $buttons ) {
120+
// Content including buttons escaped below in the inline script with wp_kses.
121+
$content .= '<div class="googlesitekit-pointer-buttons">' . $buttons . '</div>';
122+
}
116123

117-
BC_Functions::wp_print_inline_script_tag(
118-
sprintf(
119-
'
120-
jQuery( function() {
121-
var options = {
122-
content: "<h3>%s</h3>%s",
123-
position: %s,
124-
pointerWidth: 420,
125-
close: function() {
126-
jQuery.post(
127-
window.ajaxurl,
128-
{
129-
pointer: "%s",
130-
action: "dismiss-wp-pointer",
131-
}
132-
);
133-
}
134-
};
135-
136-
jQuery( "#%s" ).pointer( options ).pointer( "open" );
137-
} );
138-
',
139-
esc_js( $pointer->get_title() ),
140-
$content,
141-
wp_json_encode( $pointer->get_position() ),
142-
esc_js( $slug ),
143-
esc_js( $pointer->get_target_id() )
124+
$class = array( 'wp-pointer' );
125+
if ( $pointer->get_class() ) {
126+
$class[] = $pointer->get_class();
127+
}
128+
129+
$kses_title = array(
130+
'span' => array( 'class' => array() ),
131+
'button' => array(
132+
'class' => array(),
133+
'type' => array(),
134+
'data-action' => array(),
135+
),
136+
);
137+
138+
$kses_content = array(
139+
'a' => array(
140+
'href' => array(),
141+
'class' => array(),
142+
'target' => array(),
143+
'rel' => array(),
144+
'data-action' => array(),
145+
),
146+
'h4' => array(),
147+
'p' => array( 'class' => array() ),
148+
'br' => array(),
149+
'strong' => array(),
150+
'em' => array(),
151+
'button' => array(
152+
'class' => array(),
153+
'type' => array(),
154+
'data-action' => array(),
144155
),
156+
'div' => array( 'class' => array() ),
157+
);
158+
159+
BC_Functions::wp_print_inline_script_tag(
160+
<<<'JS'
161+
(
162+
function ( $, wp, config ) {
163+
function initPointer() {
164+
const options = {
165+
content: '<h3>' + config.title + '</h3>' + config.content,
166+
position: JSON.parse( config.position ),
167+
pointerWidth: 420,
168+
pointerClass: config.class,
169+
close: function() {
170+
wp.ajax.post( 'dismiss-wp-pointer', { pointer: config.slug } );
171+
},
172+
buttons: function( event, container ) {
173+
container.pointer.on( 'click', '[data-action="dismiss"]', function() {
174+
container.element.pointer( 'close' );
175+
} );
176+
}
177+
};
178+
179+
$( '#' + config.targetId ).pointer( options ).pointer( 'open' );
180+
}
181+
182+
$( initPointer );
183+
}
184+
)( window.jQuery, window.wp, { ...document.currentScript.dataset } );
185+
JS
186+
,
145187
array(
146-
'id' => $slug,
188+
'data-slug' => $pointer->get_slug(),
189+
'data-class' => implode( ' ', $class ),
190+
'data-target-id' => $pointer->get_target_id(),
191+
'data-title' => wp_kses( $pointer->get_title(), $kses_title ),
192+
'data-content' => wp_kses( $content, $kses_content ),
193+
'data-position' => wp_json_encode( $pointer->get_position() ),
147194
)
148195
);
149196
}

includes/Core/Dashboard_Sharing/Dashboard_Sharing.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
namespace Google\Site_Kit\Core\Dashboard_Sharing;
1212

13+
use Google\Site_Kit\Context;
14+
1315
/**
1416
* Class for handling Dashboard Sharing.
1517
*
@@ -31,9 +33,12 @@ class Dashboard_Sharing {
3133
*
3234
* @since 1.82.0
3335
* @since 1.158.0 Remove $user_options and $context params.
36+
* @since n.e.x.t Restore $context param.
37+
*
38+
* @param Context $context Plugin context.
3439
*/
35-
public function __construct() {
36-
$this->view_only_pointer = new View_Only_Pointer();
40+
public function __construct( Context $context ) {
41+
$this->view_only_pointer = new View_Only_Pointer( $context );
3742
}
3843

3944
/**

0 commit comments

Comments
 (0)