PluginProbe
Post Grid Gutenberg Blocks – PostX / 5.1.0
Post Grid Gutenberg Blocks – PostX v5.1.0
5.1.1 5.1.0 5.0.41 5.0.39 5.0.38 5.0.37 5.0.36 5.0.35 5.0.34 5.0.33 5.0.32 5.0.31 5.0.30 5.0.29 5.0.28 5.0.27 5.0.26 5.0.25 5.0.23 5.0.24 5.0.22 5.0.21 5.0.20 5.0.19 5.0.18 All 240 releases
ultimate-post / includes / durbin / class-durbin-client.php

class-durbin-client.php in Post Grid Gutenberg Blocks – PostX 5.1.0, at includes/durbin/class-durbin-client.php

184 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ULTP\Includes\Durbin;
4
5 defined( 'ABSPATH' ) || exit;
6
7 /**
8 * Class Durbin_Client
9 */
10 class DurbinClient {
11
12 // Do not change these constants
13 const DEACTIVATE_ACTION = 'deactive';
14 const ACTIVATE_ACTION = 'active';
15 const WIZARD_ACTION = 'wizard';
16
17 const PLUGIN_SLUG = 'ultimate-post';
18 const URL = 'https://inside.wpxpo.com/wp-json/durbin/v1/analytics';
19
20 /**
21 * Send data to Durbin
22 *
23 * @param DurbinClient::DEACTIVATE_ACTION|DurbinClient::ACTIVATE_ACTION|DurbinClient::WIZARD_ACTION $action_type action type.
24 * @return void
25 */
26 public static function send( $action_type ) {
27 if ( ! current_user_can( 'manage_options' ) ) {
28 return;
29 }
30
31 if ( ! in_array( $action_type, array( self::DEACTIVATE_ACTION, self::ACTIVATE_ACTION, self::WIZARD_ACTION ), true ) ) {
32 return;
33 }
34
35 $data = self::get_common_data();
36
37 $data['action_type'] = $action_type;
38
39 if ( self::DEACTIVATE_ACTION === $action_type ) {
40
41 $id = isset( $_POST['cause_id'] ) ? sanitize_key( wp_unslash( $_POST['cause_id'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce checked by caller (Deactive::send_plugin_data).
42
43 if ( ! empty( $id ) ) {
44 $data['feedback'] = array(
45 'id' => $id,
46 'details' => isset( $_POST['cause_details'] ) ? sanitize_text_field( wp_unslash( $_POST['cause_details'] ) ) : null, // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce checked by caller (Deactive::send_plugin_data).
47 );
48 }
49 }
50
51 if ( self::WIZARD_ACTION === $action_type ) {
52 $data['data'] = array(
53 'site_type' => isset( $_POST['siteType'] ) ? sanitize_text_field( wp_unslash( $_POST['siteType'] ) ) : get_option( '__ultp_site_type', 'other' ), // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce checked by caller (Dashboard wizard callbacks).
54 );
55 }
56
57 wp_remote_post(
58 self::URL,
59 array(
60 'timeout' => 30,
61 'redirection' => 5,
62 'headers' => array(
63 'user-agent' => 'wpxpo/' . md5( esc_url( home_url() ) ) . ';',
64 'Accept' => 'application/json',
65 ),
66 'blocking' => true,
67 'httpversion' => '1.0',
68 'body' => $data,
69 )
70 );
71 }
72
73 /**
74 * Get All the Installed Plugin Data
75 *
76 * @return array
77 */
78 private static function get_installed_plugins() {
79 if ( ! function_exists( 'get_plugins' ) ) {
80 include ABSPATH . '/wp-admin/includes/plugin.php';
81 }
82
83 $active = array();
84 $inactive = array();
85 $all_plugins = get_plugins();
86 $active_plugins = get_option( 'active_plugins', array() );
87 if ( is_multisite() ) {
88 $active_plugins = array_merge( $active_plugins, array_keys( get_site_option( 'active_sitewide_plugins', array() ) ) );
89 }
90
91 foreach ( $all_plugins as $key => $plugin ) {
92 $slug = dirname( $key );
93 if ( empty( $slug ) || self::PLUGIN_SLUG === $slug ) {
94 continue;
95 }
96
97 $arr = array(
98 'title' => $plugin['Name'] ?? null,
99 'slug' => $slug,
100 );
101
102 if ( in_array( $key, $active_plugins ) ) {
103 $active[] = $arr;
104 } else {
105 $inactive[] = $arr;
106 }
107 }
108
109 return array(
110 'active' => $active,
111 'inactive' => $inactive,
112 );
113 }
114
115 /**
116 * Get Country Code
117 *
118 * Calls ipinfo.io, a third-party service, and caches the result for 180 days.
119 * Disclosed in readme.txt under == Privacy ==.
120 *
121 * ⚠ Guideline 7 requires explicit consent before contacting an external
122 * server; readme disclosure satisfies the guideline's "should" but not its
123 * "may not". No consent gate exists on this path — see F01b. Kept knowingly,
124 * at the maintainer's decision, not by oversight.
125 *
126 * @return string|null
127 */
128 private static function get_country_code() {
129
130 $cached = get_transient( 'durbin_country_code' );
131
132 if ( false !== $cached ) {
133 return $cached;
134 }
135
136 $res = wp_remote_get(
137 'https://ipinfo.io/json',
138 array( 'timeout' => 30 )
139 );
140
141 if ( is_wp_error( $res ) || 200 !== wp_remote_retrieve_response_code( $res ) ) {
142 return null;
143 }
144
145 $body = wp_remote_retrieve_body( $res );
146 $data = json_decode( $body, true );
147
148 $country = isset( $data['country'] ) ? $data['country'] : null;
149
150 if ( ! empty( $country ) ) {
151 set_transient( 'durbin_country_code', $country, 180 * DAY_IN_SECONDS );
152 }
153
154 return $country;
155 }
156
157 /**
158 * Get common data
159 *
160 * @return array
161 */
162 private static function get_common_data() {
163 $user = wp_get_current_user();
164 $plugins_data = self::get_installed_plugins();
165 $user_name = $user->user_firstname ? $user->user_firstname . ( $user->user_lastname ? ' ' . $user->user_lastname : '' ) : $user->display_name;
166
167 // Every field here is named in the data-collection policy the consent
168 // notice links, and all of them are disclosed in readme.txt under
169 // == Privacy ==. country_code comes from a third-party lookup; see
170 // get_country_code() for the guideline 7 caveat that applies to it.
171 $data = array(
172 'email' => $user->user_email,
173 'name' => $user_name,
174 'site_url' => esc_url( home_url() ),
175 'plugin' => self::PLUGIN_SLUG,
176 'theme' => get_stylesheet(),
177 'plugins' => $plugins_data,
178 'country_code' => self::get_country_code(),
179 );
180
181 return $data;
182 }
183 }
184