Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
817c2a0
Add support for campaigns to the /stats/posts API endpoint
vaurdan Mar 28, 2025
ff75eb1
Adds dynamic stats and information to the post list component.
vaurdan Apr 2, 2025
d16073b
Fix linting
vaurdan Apr 2, 2025
912185c
Merge branch 'develop' of github.com:Parsely/wp-parsely into develop
alecgeatches Apr 14, 2025
0083a92
Merge branch 'develop' into add/traffic-boost-post-list-stats
alecgeatches Apr 14, 2025
d730291
Merge branch 'add/traffic-boost' into add/traffic-boost-post-list-stats
alecgeatches Apr 18, 2025
b3359db
Merge branch 'add/traffic-boost' into add/traffic-boost-post-list-stats
alecgeatches Apr 23, 2025
11c3ab1
Fix NaN in view counts
alecgeatches Apr 24, 2025
a49e877
Fix test errors related to new canonical_url REST field
alecgeatches Apr 24, 2025
3f8297b
Fix linting errors
alecgeatches Apr 24, 2025
91f8530
More test fixes for new fields
alecgeatches Apr 24, 2025
88c7fb1
Revert REST metadata to only register when wp-parsely is fully enabled
alecgeatches Apr 29, 2025
de56de0
Return empty metadata for non-existent posts to match test setup
alecgeatches Apr 29, 2025
0fe3589
Fix order of expected meta values in tests
alecgeatches May 7, 2025
60b5f7f
Merge branch 'add/traffic-boost' into add/traffic-boost-post-list-stats
alecgeatches May 7, 2025
f773204
Fix "View"/"Edit" dropdown buttons on Traffic Boost page
alecgeatches May 7, 2025
7ddbb8c
Fix minor SonarQubeCloud complaints
alecgeatches May 7, 2025
f92e49f
Convert number value into conditional
alecgeatches May 7, 2025
26d2d3c
Perform whitespace/comment/import adjustments
acicovic May 8, 2025
9e442cb
Merge branch 'add/traffic-boost' into add/traffic-boost-post-list-stats
acicovic May 8, 2025
94872bb
Fix pluralization on suggestions bubble, use standardized date on pos…
alecgeatches May 8, 2025
5001e64
Disable inbound/outbound links UI component, suggestion count bubble,…
alecgeatches May 8, 2025
3428481
Handle missing post metadata in UI
alecgeatches May 8, 2025
ee7b092
Add an explicit group and timeout for suggestions count cache
alecgeatches May 8, 2025
08c96b2
Guard against division by zero & remove all thousands separators
alecgeatches May 8, 2025
dc404bc
Fixes for small coderabbit suggestions
alecgeatches May 8, 2025
4743152
Rebuild after an npm install
alecgeatches May 8, 2025
fb84dbf
Remove copy-paste typo
alecgeatches May 8, 2025
5063793
Merge branch 'add/traffic-boost' into add/traffic-boost-post-list-stats
acicovic May 9, 2025
b0f374c
internationalize string and improve number parsing
alecgeatches May 9, 2025
f3c3431
Merge branch 'add/traffic-boost-post-list-stats' of github.com:Parsel…
alecgeatches May 9, 2025
6389c74
Refactor wp_cache functions for consistency. Use a consistent cache g…
alecgeatches May 9, 2025
73d4020
Fix unrelated phpstan errors
alecgeatches May 9, 2025
f624d4b
Revert "Fix unrelated phpstan errors"
alecgeatches May 9, 2025
32e9869
Instead of caching whole objects, save smart link IDs and hydrate fro…
alecgeatches May 9, 2025
322d570
Add PARSELY_CACHE_GROUP to integration tests bootstrap
alecgeatches May 9, 2025
0c4edd2
Change hash function to sha256 for SonarQube
alecgeatches May 9, 2025
eb92cb3
Fix wrong `@since` versions
alecgeatches May 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/content-helper/dashboard-page-rtl.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/content-helper/dashboard-page.asset.php
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-url'), 'version' => '077f9e4111341245162f');
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-url'), 'version' => '2091307856d92e7e9ea0');
2 changes: 1 addition & 1 deletion build/content-helper/dashboard-page.css

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions build/content-helper/dashboard-page.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"@wordpress/compose": "^7.23.0",
"@wordpress/core-data": "^7.23.0",
"@wordpress/data": "^10.23.0",
"@wordpress/date": "^5.13.0",
"@wordpress/e2e-test-utils-playwright": "^1.23.0",
"@wordpress/edit-post": "^8.23.0",
"@wordpress/editor": "^14.23.0",
Expand Down
46 changes: 27 additions & 19 deletions src/Endpoints/class-rest-metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

use Parsely\Metadata;
use WP_Post;
use Parsely\Models\Smart_Link;
use Parsely\Models\Smart_Link_Status;
use Parsely\Models\Inbound_Smart_Link;

/**
* Injects Parse.ly Metadata to WordPress REST API.
Expand All @@ -28,13 +31,6 @@ class Rest_Metadata extends Metadata_Endpoint {
* @since 3.1.0
*/
public function run(): void {
/**
* Filter whether REST API support is enabled or not.
*
* @since 3.1.0
*
* @param bool $enabled True if enabled, false if not.
*/
if ( apply_filters( 'wp_parsely_enable_rest_api_support', true ) && $this->parsely->site_id_is_set() ) {
$this->register_meta();
}
Expand Down Expand Up @@ -66,32 +62,38 @@ public function register_meta(): void {
* Function to get hooked into the `get_callback` property of the `parsely`
* REST API field. It generates the `parsely` object in the REST API.
*
* @since 3.1.0
* @since 3.18.0 Added the `canonical_url` field.
*
* @param array<string, mixed> $object_data The data of the object to render the metadata for,
* usually a post or a page.
* @return array<string, mixed> The `parsely` object to be rendered in the REST API. Contains a
* version number describing the response and the `meta` object
* containing the actual metadata.
*/
public function get_callback( array $object_data ): array {
/**
* Variable.
*
* @var int
*/
/** @var int $post_id */
$post_id = $object_data['ID'] ?? $object_data['id'] ?? 0;
$post = WP_Post::get_instance( $post_id );

$options = $this->parsely->get_options();

$response = array(
'version' => self::REST_VERSION,
'canonical_url' => \Parsely\Parsely::get_canonical_url_from_post( $post_id ),
'smart_links' => array(
'inbound' => 0,
'outbound' => 0,
),
'traffic_boost_suggestions_count' => 0,
);

if ( false === $post ) {
$metadata = '';
} else {
$metadata = ( new Metadata( $this->parsely ) )->construct_metadata( $post );
return $response;
}

$response = array(
'version' => self::REST_VERSION,
'meta' => $metadata,
);
$metadata = ( new Metadata( $this->parsely ) )->construct_metadata( $post );
$response['meta'] = $metadata;

/**
* Filter whether REST API support in rendered string format is enabled
Expand All @@ -118,6 +120,12 @@ public function get_callback( array $object_data ): array {
$response['tracker_url'] = $this->parsely->get_tracker_url();
}

// Fetch Smart Link data.
$response['smart_links'] = Smart_Link::get_link_counts( $post_id, Smart_Link_Status::APPLIED );

// Fetch Traffic Boost data.
$response['traffic_boost_suggestions_count'] = Inbound_Smart_Link::get_suggestions_count( $post_id );

return $response;
}
}
88 changes: 81 additions & 7 deletions src/Models/class-inbound-smart-link.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use WP_Post;
use WP_Error;

use const Parsely\PARSELY_CACHE_GROUP;

/**
* Model for Inbound Smart Link.
*
Expand Down Expand Up @@ -817,8 +819,8 @@ public function apply() {
return $updated_post;
}

// Flush the cache for the post.
self::flush_cache_by_post_id( $this->source_post_id );
// Flush the caches for the smart link.
$this->flush_all_cache();

// Set the applied flag to true.
$this->set_status( Smart_Link_Status::APPLIED );
Expand Down Expand Up @@ -948,7 +950,7 @@ public function remove( $restore_original_link = false, $delete_smart_link = tru
}

// Flush the cache for the post.
self::flush_cache_by_post_id( $this->source_post_id );
$this->flush_all_cache();

// Set the applied flag to false.
$this->set_status( Smart_Link_Status::PENDING );
Expand Down Expand Up @@ -1055,6 +1057,52 @@ public static function get_existing_suggestions( int $post_id ): array {
return $smart_links;
}

/**
* Gets the number of pending inbound smart link suggestions for a post.
*
* @since 3.18.0
*
* @param int $post_id The post ID.
* @return int The number of pending inbound smart links.
*/
public static function get_suggestions_count( int $post_id ): int {
$cache_key = self::get_suggestions_count_cache_key( $post_id );
$count = wp_cache_get( $cache_key, PARSELY_CACHE_GROUP );

if ( false !== $count ) {
/** @var int $count */
return $count;
}

$args = array(
'post_type' => 'parsely_smart_link',
'posts_per_page' => 0,
'fields' => 'ids',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'smart_link_destination',
'field' => 'slug',
'include_children' => false,
'terms' => (string) $post_id,
),
array(
'taxonomy' => 'smart_link_status',
'field' => 'slug',
'include_children' => false,
'terms' => Smart_Link_Status::PENDING,
),
),
);

$query = new \WP_Query( $args );

wp_cache_set( $cache_key, $query->found_posts, PARSELY_CACHE_GROUP, MONTH_IN_SECONDS );

return $query->found_posts;
}

/**
* Deletes all pending (not applied) inbound smart links suggestions for a given post.
*
Expand All @@ -1075,13 +1123,13 @@ public static function delete_pending_suggestions( int $post_id ): array {
'relation' => 'AND',
array(
'taxonomy' => 'smart_link_destination',
'field' => 'name',
'field' => 'slug',
'include_children' => false,
'terms' => (string) $post_id,
),
array(
'taxonomy' => 'smart_link_status',
'field' => 'name',
'field' => 'slug',
'include_children' => false,
'terms' => Smart_Link_Status::PENDING,
),
Expand Down Expand Up @@ -1176,13 +1224,13 @@ public static function get_smart_link_by_source_and_destination( int $source_pos
'tax_query' => array(
array(
'taxonomy' => 'smart_link_destination',
'field' => 'name',
'field' => 'slug',
'include_children' => false,
'terms' => (string) $destination_post_id,
),
array(
'taxonomy' => 'smart_link_source',
'field' => 'name',
'field' => 'slug',
'include_children' => false,
'terms' => (string) $source_post_id,
),
Expand Down Expand Up @@ -1282,6 +1330,20 @@ private function is_the_same_line( string $line1, string $line2 ): bool {
return $text1 === $text2;
}

/**
* Flushes the cache for the post.
*
* @since 3.18.0
*
* @param int $post_id The post ID.
*/
protected static function flush_cache_by_post_id( int $post_id ): void {
parent::flush_cache_by_post_id( $post_id );

$cache_key = self::get_suggestions_count_cache_key( $post_id );
wp_cache_delete( $cache_key, PARSELY_CACHE_GROUP );
}

/**
* Checks if a WP_Error from wp_update_post() is ignorable.
*
Expand All @@ -1304,4 +1366,16 @@ private function is_ignorable_update_error( WP_Error $error ): bool {

return false;
}

/**
* Gets the cache key for the traffic boost suggestions count.
*
* @since 3.19.0
*
* @param int $post_id The post ID.
* @return string The cache key.
*/
private static function get_suggestions_count_cache_key( int $post_id ): string {
return sprintf( 'traffic-boost-suggestions-count-%d', $post_id );
}
}
Loading
Loading