PluginProbe ʕ •ᴥ•ʔ
Starter Sites & Templates by Neve / trunk
Starter Sites & Templates by Neve vtrunk
1.4.0 1.3.0 1.2.29 1.2.28 1.2.6 1.2.7 1.2.8 1.2.9 trunk 1.0.10 1.0.11 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 1.1.20 1.1.21 1.1.22 1.1.23 1.1.24 1.1.25 1.1.26 1.1.27 1.1.28 1.1.29 1.1.3 1.1.30 1.1.31 1.1.32 1.1.33 1.1.34 1.1.35 1.1.36 1.1.37 1.1.38 1.1.39 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.3 1.2.4 1.2.5
templates-patterns-collection / includes / Starter_Ranking.php
templates-patterns-collection / includes Last commit date
Importers 2 months ago Admin.php 1 week ago Editor.php 1 year ago Elementor.php 1 year ago License.php 1 year ago Logger.php 2 years ago Main.php 1 week ago Rest_Server.php 2 weeks ago Sites_Listing.php 2 weeks ago Starter_Ranking.php 1 week ago TI_Beaver.php 1 year ago WP_Cli.php 3 months ago White_Label_Config.php 3 years ago
Starter_Ranking.php
214 lines
1 <?php
2 /**
3 * Personalized starter-site ordering.
4 *
5 * @package templates-patterns-collection
6 */
7
8 namespace TIOB;
9
10 /**
11 * Class Starter_Ranking
12 */
13 class Starter_Ranking {
14
15 const DEFAULT_BASE = 'https://ai.themeisle.com';
16 const SLUG = 'neve-starter-ranking';
17 const VERSION = 'v2';
18 const CACHE_TTL = 7 * DAY_IN_SECONDS;
19 const REQUEST_BUDGET = 6;
20 const SEARCH_BUDGET = 8;
21
22 private static function base_url() {
23 if ( defined( 'TPC_AI_PROXY_URL' ) && ! empty( TPC_AI_PROXY_URL ) ) {
24 return rtrim( TPC_AI_PROXY_URL, '/' );
25 }
26
27 return rtrim( apply_filters( 'tpc_ai_proxy_url', self::DEFAULT_BASE ), '/' );
28 }
29
30 private static function cache_key( $builder ) {
31 return 'tpc_starter_order_' . self::VERSION . '_' . $builder;
32 }
33
34 public static function get_order( $builder ) {
35 $builder = ( 'elementor' === $builder ) ? 'elementor' : 'gutenberg';
36
37 return self::cached_order(
38 self::cache_key( $builder ),
39 static function () use ( $builder ) {
40 return self::fetch_order( $builder );
41 },
42 self::CACHE_TTL
43 );
44 }
45
46 private static function cached_order( $key, callable $fetch, $success_ttl ) {
47 $cached = get_transient( $key );
48 if ( is_array( $cached ) ) {
49 return $cached;
50 }
51
52 $lock = $key . '_lock';
53 if ( get_transient( $lock ) ) {
54 return array();
55 }
56
57 set_transient( $lock, 1, 2 * MINUTE_IN_SECONDS );
58
59 try {
60 $order = (array) call_user_func( $fetch );
61 } finally {
62 delete_transient( $lock );
63 }
64
65 set_transient( $key, $order, ! empty( $order ) ? $success_ttl : 2 * MINUTE_IN_SECONDS );
66
67 return $order;
68 }
69
70 public static function search( $query, $builder ) {
71 $query = trim( (string) $query );
72 if ( '' === $query ) {
73 return array();
74 }
75
76 $builder = ( 'elementor' === $builder ) ? 'elementor' : 'gutenberg';
77 $key = 'tpc_starter_search_' . self::VERSION . '_' . $builder . '_' . md5( strtolower( $query ) );
78
79 return self::cached_order(
80 $key,
81 static function () use ( $builder, $query ) {
82 return self::fetch_order( $builder, $query, self::SEARCH_BUDGET );
83 },
84 6 * HOUR_IN_SECONDS
85 );
86 }
87
88 private static function fetch_order( $builder, $query = null, $budget = null ) {
89 $deadline = time() + ( null !== $budget ? (int) $budget : self::REQUEST_BUDGET );
90 $start = self::base_url() . '/api/workflows/' . self::SLUG . '/start';
91 $body = array(
92 'site_url' => home_url(),
93 'site_title' => sanitize_text_field( get_bloginfo( 'name' ) ),
94 'builder' => $builder,
95 );
96
97 if ( null !== $query && '' !== $query ) {
98 $body['query'] = $query;
99 }
100
101 $response = wp_remote_post(
102 $start,
103 array(
104 'timeout' => 5,
105 'headers' => self::headers(),
106 'body' => wp_json_encode( $body ),
107 )
108 );
109
110 if ( is_wp_error( $response ) ) {
111 return array();
112 }
113
114 $code = (int) wp_remote_retrieve_response_code( $response );
115 $body = json_decode( wp_remote_retrieve_body( $response ), true );
116
117 $order = self::parse_order( $body );
118 if ( ! empty( $order ) ) {
119 return $order;
120 }
121
122 if ( 200 !== $code && 202 !== $code ) {
123 return array();
124 }
125
126 $workflow_id = is_array( $body ) && ! empty( $body['workflowId'] ) ? $body['workflowId'] : '';
127 if ( '' === $workflow_id ) {
128 return array();
129 }
130
131 return self::poll_order( $workflow_id, $deadline );
132 }
133
134 private static function poll_order( $workflow_id, $deadline = null ) {
135 $deadline = null !== $deadline ? (int) $deadline : ( time() + self::REQUEST_BUDGET );
136 $status_url = self::base_url() . '/api/workflows/' . self::SLUG . '/' . rawurlencode( $workflow_id );
137
138 while ( time() < $deadline ) {
139 usleep( 600000 );
140
141 $remaining = $deadline - time();
142 if ( $remaining <= 0 ) {
143 break;
144 }
145
146 $response = wp_remote_get(
147 $status_url,
148 array(
149 'timeout' => min( 5, $remaining ),
150 'headers' => self::headers(),
151 )
152 );
153 if ( is_wp_error( $response ) ) {
154 continue;
155 }
156
157 $body = json_decode( wp_remote_retrieve_body( $response ), true );
158 $status = is_array( $body ) && isset( $body['status'] ) ? $body['status'] : '';
159
160 if ( 'completed' === $status ) {
161 return self::parse_order( $body );
162 }
163
164 if ( 'failed' === $status ) {
165 return array();
166 }
167 }
168
169 return array();
170 }
171
172 private static function headers() {
173 $headers = array(
174 'Content-Type' => 'application/json',
175 'Accept' => 'application/json',
176 'X-Site-Url' => home_url(),
177 );
178
179 $license = apply_filters( 'tiob_license_key', 'free' );
180 if ( is_string( $license ) && '' !== $license && 'free' !== $license ) {
181 $headers['Authorization'] = 'Bearer ' . base64_encode( $license );
182 }
183
184 return $headers;
185 }
186
187 public static function parse_order( $body ) {
188 if ( ! is_array( $body ) ) {
189 return array();
190 }
191
192 $output = array();
193 if ( isset( $body['output'] ) ) {
194 if ( is_array( $body['output'] ) ) {
195 $output = $body['output'];
196 } elseif ( is_string( $body['output'] ) ) {
197 $decoded_output = json_decode( $body['output'], true );
198 if ( is_array( $decoded_output ) ) {
199 $output = $decoded_output;
200 }
201 }
202 }
203
204 $order = array();
205 if ( isset( $output['order'] ) && is_array( $output['order'] ) ) {
206 $order = $output['order'];
207 } elseif ( isset( $body['order'] ) && is_array( $body['order'] ) ) {
208 $order = $body['order'];
209 }
210
211 return array_values( array_filter( array_map( 'strval', $order ) ) );
212 }
213 }
214