PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.8.9
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.8.9
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
desktop-mode / includes / sticky-notes / heartbeat.php

heartbeat.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.8.9, at includes/sticky-notes/heartbeat.php

247 lines 7.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop Mode — Sticky notes Heartbeat sync.
4 *
5 * Gutenberg's Guidelines experiment owns the `wp_guideline` CPT and
6 * `wp_guideline_type` taxonomy. Desktop Mode only mirrors sticky
7 * artifacts into the shell: the client subscribes with the sticky term
8 * id, known guideline ids, and a high-water modified timestamp; the
9 * server responds with changed sticky guidelines plus removals.
10 *
11 * @package WPDesktopMode
12 */
13
14 defined( 'ABSPATH' ) || exit;
15
16 const DESKTOP_MODE_STICKY_NOTES_POST_TYPE = 'wp_guideline';
17 const DESKTOP_MODE_STICKY_NOTES_TAXONOMY = 'wp_guideline_type';
18
19 /**
20 * Add sticky-note deltas to the Heartbeat response.
21 *
22 * @since 0.21.0
23 *
24 * @param array $response Pre-filtered response.
25 * @param array $data Client-sent payload.
26 * @return array
27 */
28 function desktop_mode_sticky_notes_heartbeat_received( $response, $data ) {
29 if ( ! is_array( $response ) ) {
30 $response = array();
31 }
32 if ( empty( $data['desktop_mode_sticky_notes_subscribe'] ) || ! is_array( $data['desktop_mode_sticky_notes_subscribe'] ) ) {
33 return $response;
34 }
35 if ( ! function_exists( 'desktop_mode_is_enabled' ) || ! desktop_mode_is_enabled() ) {
36 return $response;
37 }
38 if (
39 ! post_type_exists( DESKTOP_MODE_STICKY_NOTES_POST_TYPE ) ||
40 ! taxonomy_exists( DESKTOP_MODE_STICKY_NOTES_TAXONOMY )
41 ) {
42 return $response;
43 }
44
45 $sub = $data['desktop_mode_sticky_notes_subscribe'];
46 $sticky_term_id = isset( $sub['stickyTermId'] ) ? absint( $sub['stickyTermId'] ) : 0;
47 if ( $sticky_term_id <= 0 || ! term_exists( $sticky_term_id, DESKTOP_MODE_STICKY_NOTES_TAXONOMY ) ) {
48 return $response;
49 }
50
51 $known_ids = isset( $sub['knownIds'] ) && is_array( $sub['knownIds'] )
52 ? array_values( array_unique( array_filter( array_map( 'absint', $sub['knownIds'] ) ) ) )
53 : array();
54 $known_ids = array_slice( $known_ids, 0, 500 );
55
56 $version = isset( $sub['version'] ) ? max( 0, (int) $sub['version'] ) : 0;
57
58 $response['desktop_mode_sticky_notes'] = desktop_mode_sticky_notes_compute_heartbeat_delta(
59 $sticky_term_id,
60 $known_ids,
61 $version,
62 100
63 );
64
65 return $response;
66 }
67 add_filter( 'heartbeat_received', 'desktop_mode_sticky_notes_heartbeat_received', 5, 2 );
68
69 /**
70 * Compute sticky-note Heartbeat deltas.
71 *
72 * @since 0.21.0
73 *
74 * @param int $sticky_term_id Sticky term id.
75 * @param int[] $known_ids Guideline ids currently known by the client.
76 * @param int $version Last-seen modified timestamp in milliseconds.
77 * @param int $cap Maximum notes to send in one tick.
78 * @return array
79 */
80 function desktop_mode_sticky_notes_compute_heartbeat_delta( $sticky_term_id, $known_ids, $version, $cap ) {
81 $cap = max( 1, (int) $cap );
82 $query_ids = desktop_mode_sticky_notes_query_changed_ids( $sticky_term_id, $version, $cap + 1 );
83 $truncated = count( $query_ids ) > $cap;
84 if ( $truncated ) {
85 $query_ids = array_slice( $query_ids, 0, $cap );
86 }
87
88 $notes = array();
89 foreach ( $query_ids as $post_id ) {
90 if ( ! current_user_can( 'edit_post', $post_id ) ) {
91 continue;
92 }
93 $post = get_post( $post_id );
94 if ( $post instanceof WP_Post ) {
95 $notes[] = desktop_mode_sticky_notes_shape_guideline( $post );
96 }
97 }
98
99 $alive_ids = desktop_mode_sticky_notes_alive_known_ids( $sticky_term_id, $known_ids );
100 $removed = array_values( array_diff( array_map( 'intval', $known_ids ), $alive_ids ) );
101
102 return array(
103 'notes' => $notes,
104 'removed' => $removed,
105 'serverTimeMs' => (int) floor( microtime( true ) * 1000 ),
106 'truncated' => $truncated,
107 );
108 }
109
110 /**
111 * Query sticky guideline ids modified since the client's high-water mark.
112 *
113 * @since 0.21.0
114 *
115 * @param int $sticky_term_id Sticky term id.
116 * @param int $version Last-seen modified timestamp in milliseconds.
117 * @param int $limit Max ids to return.
118 * @return int[]
119 */
120 function desktop_mode_sticky_notes_query_changed_ids( $sticky_term_id, $version, $limit ) {
121 $args = array(
122 'post_type' => DESKTOP_MODE_STICKY_NOTES_POST_TYPE,
123 'post_status' => 'private',
124 'posts_per_page' => max( 1, (int) $limit ),
125 'fields' => 'ids',
126 'orderby' => 'modified',
127 'order' => 'ASC',
128 'no_found_rows' => true,
129 'tax_query' => array(
130 array(
131 'taxonomy' => DESKTOP_MODE_STICKY_NOTES_TAXONOMY,
132 'field' => 'term_id',
133 'terms' => array( (int) $sticky_term_id ),
134 ),
135 ),
136 );
137 if ( $version > 0 ) {
138 $args['date_query'] = array(
139 array(
140 'column' => 'post_modified_gmt',
141 'after' => gmdate( 'Y-m-d H:i:s', (int) floor( $version / 1000 ) ),
142 'inclusive' => true,
143 ),
144 );
145 }
146
147 $query = new WP_Query( $args );
148 $ids = array_map( 'intval', (array) $query->posts );
149 wp_reset_postdata();
150
151 return $ids;
152 }
153
154 /**
155 * Return the subset of known ids that still point at visible sticky notes.
156 *
157 * @since 0.21.0
158 *
159 * @param int $sticky_term_id Sticky term id.
160 * @param int[] $known_ids Client-known guideline ids.
161 * @return int[]
162 */
163 function desktop_mode_sticky_notes_alive_known_ids( $sticky_term_id, $known_ids ) {
164 $known_ids = array_values( array_unique( array_filter( array_map( 'absint', (array) $known_ids ) ) ) );
165 if ( empty( $known_ids ) ) {
166 return array();
167 }
168
169 $query = new WP_Query(
170 array(
171 'post_type' => DESKTOP_MODE_STICKY_NOTES_POST_TYPE,
172 'post_status' => 'private',
173 'post__in' => $known_ids,
174 'posts_per_page' => count( $known_ids ),
175 'fields' => 'ids',
176 'no_found_rows' => true,
177 'tax_query' => array(
178 array(
179 'taxonomy' => DESKTOP_MODE_STICKY_NOTES_TAXONOMY,
180 'field' => 'term_id',
181 'terms' => array( (int) $sticky_term_id ),
182 ),
183 ),
184 )
185 );
186 $ids = array();
187 foreach ( (array) $query->posts as $post_id ) {
188 $post_id = (int) $post_id;
189 if ( current_user_can( 'edit_post', $post_id ) ) {
190 $ids[] = $post_id;
191 }
192 }
193 wp_reset_postdata();
194
195 return $ids;
196 }
197
198 /**
199 * Shape a guideline like the Gutenberg REST endpoint's edit context.
200 *
201 * @since 0.21.0
202 *
203 * @param WP_Post $post Guideline post.
204 * @return array
205 */
206 function desktop_mode_sticky_notes_shape_guideline( $post ) {
207 $term_ids = wp_get_object_terms(
208 $post->ID,
209 DESKTOP_MODE_STICKY_NOTES_TAXONOMY,
210 array( 'fields' => 'ids' )
211 );
212 if ( is_wp_error( $term_ids ) ) {
213 $term_ids = array();
214 }
215
216 return array(
217 'id' => (int) $post->ID,
218 'slug' => (string) $post->post_name,
219 'status' => (string) get_post_status( $post ),
220 'title' => array(
221 'raw' => (string) get_post_field( 'post_title', $post, 'raw' ),
222 ),
223 'content' => array(
224 'raw' => (string) get_post_field( 'post_content', $post, 'raw' ),
225 ),
226 'excerpt' => array(
227 'raw' => (string) get_post_field( 'post_excerpt', $post, 'raw' ),
228 ),
229 'modified' => mysql_to_rfc3339( $post->post_modified ),
230 'desktop_mode_modified_ms' => desktop_mode_sticky_notes_modified_ms( $post ),
231 'link' => (string) get_permalink( $post ),
232 'wp_guideline_type' => array_values( array_map( 'intval', (array) $term_ids ) ),
233 );
234 }
235
236 /**
237 * Modified timestamp in milliseconds, derived from GMT post time.
238 *
239 * @since 0.21.0
240 *
241 * @param WP_Post $post Post.
242 * @return int
243 */
244 function desktop_mode_sticky_notes_modified_ms( $post ) {
245 return (int) get_post_modified_time( 'U', true, $post ) * 1000;
246 }
247