1 | <?php |
||
5 | class Jetpack_Sync_Client { |
||
6 | static $default_options_whitelist = array( 'stylesheet', '/^theme_mods_.*$/' ); |
||
|
|||
7 | static $default_constants_whitelist = array(); |
||
8 | |||
9 | private $sync_queue; |
||
10 | private $codec; |
||
11 | private $options_whitelist; |
||
12 | private $constants_whitelist; |
||
13 | private $meta_types = array( 'post' ); |
||
14 | |||
15 | // singleton functions |
||
16 | private static $instance; |
||
17 | |||
18 | public static function getInstance() { |
||
19 | if (null === static::$instance) { |
||
20 | static::$instance = new static(); |
||
21 | } |
||
22 | |||
23 | return static::$instance; |
||
24 | } |
||
25 | |||
26 | // this is necessary because you can't use "new" when you declare instance properties >:( |
||
27 | protected function __construct() { |
||
28 | $this->sync_queue = new Jetpack_Sync_Queue( 'sync', 100 ); |
||
29 | $this->codec = new Jetpack_Sync_Deflate_Codec(); |
||
30 | $this->options_whitelist = self::$default_options_whitelist; |
||
31 | $this->init(); |
||
32 | } |
||
33 | |||
34 | private function init() { |
||
35 | $handler = array( $this, 'action_handler' ); |
||
36 | |||
37 | // posts |
||
38 | add_action( 'wp_insert_post', $handler, 10, 3 ); |
||
39 | add_action( 'deleted_post', $handler, 10 ); |
||
40 | |||
41 | // comments |
||
42 | add_action( 'wp_insert_comment', $handler, 10, 2 ); |
||
43 | add_action( 'deleted_comment', $handler, 10 ); |
||
44 | add_action( 'trashed_comment', $handler, 10 ); |
||
45 | add_action( 'spammed_comment', $handler, 10 ); |
||
46 | |||
47 | // even though it's messy, we implement these hooks because |
||
48 | // the edit_comment hook doesn't include the data |
||
49 | // so this saves us a DB read for every comment event |
||
50 | foreach ( array( '', 'trackback', 'pingback' ) as $comment_type ) { |
||
51 | foreach ( array( 'unapproved', 'approved' ) as $comment_status ) { |
||
52 | add_action( "comment_{$comment_status}_{$comment_type}", $handler, 10, 2 ); |
||
53 | } |
||
54 | } |
||
55 | |||
56 | // options |
||
57 | add_action( 'added_option', $handler, 10, 2 ); |
||
58 | add_action( 'updated_option', $handler, 10, 3 ); |
||
59 | add_action( 'deleted_option', $handler, 10, 1 ); |
||
60 | |||
61 | // themes |
||
62 | add_action( 'jetpack_sync_current_theme_support', $handler, 10 ); // custom hook, see meta-hooks below |
||
63 | add_action( 'jetpack_sync_current_constants', $handler, 10 ); |
||
64 | |||
65 | // post-meta, and in the future - other meta? |
||
66 | foreach ( $this->meta_types as $meta_type ) { |
||
67 | // we need to make sure we don't commit before we receive these, |
||
68 | // because they're invoked after meta changes are saved to the DB |
||
69 | add_action( "added_{$meta_type}_meta", $handler, 99, 4 ); |
||
70 | add_action( "updated_{$meta_type}_meta", $handler, 99, 4 ); |
||
71 | add_action( "deleted_{$meta_type}_meta", $handler, 99, 4 ); |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * Other hooks - fire synthetic hooks for all the properties we need to sync, |
||
76 | * e.g. when a theme changes |
||
77 | */ |
||
78 | |||
79 | // themes |
||
80 | add_action( 'switch_theme', array( $this, 'switch_theme_handler' ) ); |
||
81 | } |
||
82 | |||
83 | function set_options_whitelist( $options ) { |
||
84 | $this->options_whitelist = $options; |
||
85 | } |
||
86 | |||
87 | function set_constants_whitelist( $constants ) { |
||
88 | $this->constants_whitelist = $constants; |
||
89 | } |
||
90 | |||
91 | function is_whitelisted_option( $option ) { |
||
92 | foreach ( $this->options_whitelist as $whitelisted_option ) { |
||
93 | if ( $whitelisted_option[0] === '/' && preg_match( $whitelisted_option, $option ) ) { |
||
94 | return true; |
||
95 | } elseif ( $whitelisted_option === $option ) { |
||
96 | return true; |
||
97 | } |
||
98 | } |
||
99 | return false; |
||
100 | } |
||
101 | |||
102 | function set_codec( iJetpack_Sync_Codec $codec ) { |
||
103 | $this->codec = $codec; |
||
104 | } |
||
105 | |||
106 | function set_sync_queue( $queue ) { |
||
107 | $this->sync_queue = $queue; |
||
108 | } |
||
109 | |||
110 | function action_handler() { |
||
111 | $current_filter = current_filter(); |
||
112 | $args = func_get_args(); |
||
113 | |||
114 | if ( $current_filter === 'wp_insert_post' && $args[1]->post_type === 'revision' ) { |
||
115 | return; |
||
116 | } |
||
117 | |||
118 | if ( in_array( $current_filter, array( 'deleted_option', 'added_option', 'updated_option' ) ) |
||
119 | && |
||
120 | ! $this->is_whitelisted_option( $args[0] ) ) { |
||
121 | return; |
||
122 | } |
||
123 | Jetpack_Sync::schedule_sync(); |
||
124 | $this->sync_queue->add( array( |
||
125 | $current_filter, |
||
126 | $args |
||
127 | ) ); |
||
128 | } |
||
129 | |||
130 | function switch_theme_handler() { |
||
131 | global $_wp_theme_features; |
||
132 | |||
133 | do_action( 'jetpack_sync_current_theme_support', $_wp_theme_features ); |
||
134 | } |
||
135 | |||
136 | function do_sync() { |
||
137 | $this->maybe_sync_constants(); |
||
138 | |||
139 | // TODO: only send buffer once, then do the rest in a cron job |
||
140 | $iters = 0; |
||
141 | while ( ( $buffer = $this->sync_queue->checkout() ) && $iters < 100 ) { |
||
142 | |||
143 | if ( !$buffer ) { |
||
144 | // buffer has no items |
||
145 | return; |
||
146 | } |
||
147 | |||
148 | if ( is_wp_error( $buffer) ) { |
||
149 | error_log("Error fetching buffer: ".$buffer->get_error_message()); |
||
150 | return; |
||
151 | } |
||
152 | |||
153 | $data = $this->codec->encode( $buffer->get_items() ); |
||
154 | |||
155 | /** |
||
156 | * Fires when data is ready to send to the server. |
||
157 | * Return false or WP_Error to abort the sync (e.g. if there's an error) |
||
158 | * The items will be automatically re-sent later |
||
159 | * |
||
160 | * @since 4.1 |
||
161 | * |
||
162 | * @param array $data The action buffer |
||
163 | */ |
||
164 | $result = apply_filters( 'jetpack_sync_client_send_data', $data ); |
||
165 | |||
166 | if ( !$result || is_wp_error( $result ) ) { |
||
167 | $this->sync_queue->checkin( $buffer ); |
||
168 | } else { |
||
169 | $this->sync_queue->close( $buffer ); |
||
170 | } |
||
171 | $iters += 1; |
||
172 | } |
||
173 | } |
||
174 | |||
175 | private function maybe_sync_constants() { |
||
184 | |||
185 | private function get_all_constants() { |
||
191 | |||
192 | private function get_constant( $constant ) { |
||
199 | |||
200 | private function get_check_sum( $values ) { |
||
203 | |||
204 | function get_actions() { |
||
208 | |||
209 | function get_all_actions() { |
||
212 | |||
213 | function reset_state() { |
||
214 | $this->codec = new Jetpack_Sync_Deflate_Codec(); |
||
215 | $this->constants_whitelist = self::$default_constants_whitelist; |
||
216 | $this->options_whitelist = self::$default_options_whitelist; |
||
217 | $this->sync_queue->reset(); |
||
218 | } |
||
219 | } |
||
220 |
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using
the property is implicitly global.
To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.