reports[ $report->id() ] = $report; } $this->google = $google; } /** * {@inheritDoc} * * @param Profile $site Site. * @param string $dimension Dimension. * @param string $start Start. * @param string $end End. * @param string $page Page URL filter. * @return array[] */ public function search( Profile $site, $dimension, $start, $end, $page = '' ) { if ( '' === $page ) { return (array) $this->run( 'search-console', $site, array( 'dimension' => $dimension, 'start' => $start, 'end' => $end, ) ); } $filters = array( array( 'filters' => array( array( 'dimension' => 'page', 'operator' => 'equals', 'expression' => (string) $page, ), ), ), ); return (array) $this->google->for_site( $site, Profile::SOURCE_SEARCH )->search_console()->query( $site->gsc_site, $dimension, $start, $end, $site->search_type, self::ttl( $end ), $filters, 200 ); } /** * {@inheritDoc} * * @param Profile $site Site. * @param string $start Start. * @param string $end End. * @return array */ public function events( Profile $site, $start, $end ) { return array_map( 'intval', self::arr( $this->run( 'conversions', $site, array( 'kind' => 'totals', 'start' => $start, 'end' => $end, ) ) ) ); } /** * {@inheritDoc} * * @param Profile $site Site. * @param string $start Start. * @param string $end End. * @return array */ public function landing_pages( Profile $site, $start, $end ) { $out = array(); foreach ( self::arr( $this->run( 'conversions', $site, array( 'kind' => 'pages', 'start' => $start, 'end' => $end, ) ) ) as $path => $map ) { $out[ (string) $path ] = array_map( 'intval', self::arr( $map ) ); } return $out; } /** * {@inheritDoc} * * @param Profile $site Site. * @param string $start Start. * @param string $end End. * @return int */ public function sessions( Profile $site, $start, $end ) { $rows = $this->google->for_site( $site, Profile::SOURCE_ANALYTICS )->analytics()->run_report( $site->ga_property, array( 'dateRanges' => array( array( 'startDate' => $start, 'endDate' => $end, ), ), 'metrics' => array( array( 'name' => 'sessions' ) ), 'dimensionFilter' => Filters::organic( $site ), ), self::ttl( $end ) ); return isset( $rows[0]['m'][0] ) ? (int) $rows[0]['m'][0] : 0; } /** * Runs a registered report. * * @param string $id Report ID. * @param Profile $site Site. * @param array $params Parameters. * @return mixed * @throws ApiException When the report isn't registered or Google fails. */ private function run( $id, Profile $site, array $params ) { if ( ! isset( $this->reports[ $id ] ) ) { throw new ApiException( __( 'This part of the report isn\'t available.', 'turtlereport' ), ApiException::UNSUPPORTED ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Caught by the plugin; escaped where the message is shown. } return $this->reports[ $id ]->run( $site, array_merge( array( 'segment' => '' ), $params ) ); } /** * Cache lifetime, as the reports use: a day for settled dates, else 3 hours. * * @param string $end End date. * @return int */ private static function ttl( $end ) { return $end < gmdate( 'Y-m-d', time() - 4 * DAY_IN_SECONDS ) ? DAY_IN_SECONDS : 3 * HOUR_IN_SECONDS; } /** * Decoded JSON object (stdClass or array) as an array. * * @param mixed $value Value. * @return array */ private static function arr( $value ) { if ( $value instanceof \stdClass ) { $value = get_object_vars( $value ); } return is_array( $value ) ? $value : array(); } }