1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Games Collector BoardGameGeek API integration. |
4
|
|
|
* |
5
|
|
|
* Integrates BoardGameGeek's XML API into Games Collector to allow game data to be imported. |
6
|
|
|
* |
7
|
|
|
* @package GC\GamesCollector\BGG |
8
|
|
|
* @since 1.2.0 |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace GC\GamesCollector\BGG; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Return the BGG v1 API endpoint. |
15
|
|
|
* |
16
|
|
|
* @since 1.2.0 |
17
|
|
|
* @return string The BGG v1 endpoint. |
18
|
|
|
*/ |
19
|
|
|
function bgg_api() { |
20
|
1 |
|
return esc_url( 'https://www.boardgamegeek.com/xmlapi/' ); |
21
|
|
|
} |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Return the BGG v2 (beta) API endpoint. |
25
|
|
|
* |
26
|
|
|
* @since 1.2.0 |
27
|
|
|
* @return string The BGG v2 endpoint. |
28
|
|
|
*/ |
29
|
|
|
function bgg_api2() { |
30
|
1 |
|
return esc_url( 'https://www.boardgamegeek.com/xmlapi2/' ); |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Return the BGG search endpoint for a particular query. |
35
|
|
|
* |
36
|
|
|
* @since 1.2.0 |
37
|
|
|
* @param string $query The search query. |
38
|
|
|
* @param string $type The type of search (optional). Allowed values are rpgitem, videogame, boardgame, boardgameaccessory or boardgameexpansion. |
39
|
|
|
* @return string The BGG search API URL. |
40
|
|
|
*/ |
41
|
|
|
function bgg_search( string $query, $type = 'boardgame' ) { |
42
|
1 |
|
$query = str_replace( ' ', '+', $query ); |
43
|
1 |
|
$type = in_array( $type, [ 'rpgitem', 'videogame', 'boardgame', 'boardgameaccessory', 'boardgameexpansion' ] ) ? $type : 'boardgame'; |
44
|
|
|
|
45
|
1 |
|
return esc_url_raw( sprintf( |
46
|
1 |
|
'%1$ssearch?search=%2$s&type=%3$s', |
47
|
1 |
|
bgg_api(), |
48
|
1 |
|
esc_html( $query ), |
49
|
1 |
|
esc_html( $type ) |
50
|
|
|
) ); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Return the BGG API endpoint for a single game/entity. |
55
|
|
|
* |
56
|
|
|
* @since 1.2.0 |
57
|
|
|
* @param int $id The BGG entity ID. |
58
|
|
|
* @return string The BGG URL. |
59
|
|
|
*/ |
60
|
|
|
function bgg_game( int $id ) { |
61
|
1 |
|
return esc_url( bgg_api2() . 'thing?id=' . $id ); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Return the search results for a given query. |
66
|
|
|
* |
67
|
|
|
* @since 1.2.0 |
68
|
|
|
* @param string $query A search query for a game. |
69
|
|
|
* @return array An array of possible matches. |
70
|
|
|
*/ |
71
|
|
|
function get_bgg_search_results( $query ) { |
72
|
1 |
|
$response = wp_remote_get( bgg_search( $query ) ); |
73
|
1 |
|
$results = []; |
74
|
|
|
|
75
|
1 |
|
if ( isset( $response['response'] ) && 200 === $response['response']['code'] ) { |
76
|
1 |
|
$xml = simplexml_load_string( wp_remote_retrieve_body( $response ) ); |
77
|
|
|
|
78
|
1 |
|
if ( isset( $xml->boardgame ) ) { |
79
|
1 |
|
foreach ( $xml->boardgame as $game ) { |
80
|
1 |
|
$game = (array) $game; |
81
|
|
|
|
82
|
1 |
|
$results[] = [ |
83
|
1 |
|
'id' => ( isset( $game['@attributes']['objectid'] ) ) ? (int) $game['@attributes']['objectid'] : '', |
84
|
1 |
|
'name' => ( isset( $game['name'] ) ) ? $game['name'] : '', |
85
|
1 |
|
'year' => ( isset( $game['yearpublished'] ) ) ? $game['yearpublished'] : '', |
86
|
|
|
]; |
87
|
|
|
} |
88
|
|
|
} |
89
|
|
|
} |
90
|
|
|
|
91
|
1 |
|
return $results; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Return the BGG data that maps to data used in Games Collector for a game. |
96
|
|
|
* |
97
|
|
|
* @since 1.2.0 |
98
|
|
|
* @param int $id The BGG game id. |
99
|
|
|
* @return array An array of game information pulled from the entry on Board Game Geek. |
100
|
|
|
*/ |
101
|
|
|
function get_bgg_game( $id ) { |
102
|
1 |
|
$response = wp_remote_get( bgg_game( $id ) ); |
103
|
1 |
|
$data = []; |
104
|
|
|
|
105
|
1 |
|
if ( isset( $response['response'] ) && 200 === $response['response']['code'] ) { |
106
|
1 |
|
$xml = simplexml_load_string( wp_remote_retrieve_body( $response ) ); |
107
|
1 |
|
$game = $xml->item; |
|
|
|
|
108
|
|
|
$data = [ |
109
|
1 |
|
'title' => (string) $game->name->attributes()['value'], |
110
|
1 |
|
'image' => (string) $game->image, |
111
|
1 |
|
'minplayers' => (int) $game->minplayers->attributes()['value'], |
112
|
1 |
|
'maxplayers' => (int) $game->maxplayers->attributes()['value'], |
113
|
1 |
|
'minplaytime' => (int) $game->minplaytime->attributes()['value'], |
114
|
1 |
|
'maxplaytime' => (int) $game->maxplaytime->attributes()['value'], |
115
|
1 |
|
'minage' => (int) $game->minage->attributes()['value'], |
116
|
|
|
'categories' => [], |
117
|
|
|
]; |
118
|
|
|
|
119
|
1 |
|
$categories = []; |
120
|
|
|
|
121
|
1 |
|
foreach ( $game->link as $metadata ) { |
122
|
1 |
|
if ( 'boardgamecategory' === (string) $metadata->attributes()['type'] ) { |
123
|
1 |
|
$categories[] = (string) $metadata->attributes()['value']; |
124
|
|
|
} |
125
|
|
|
} |
126
|
|
|
|
127
|
1 |
|
$data['categories'] = ! empty( $categories ) ? $categories : []; |
128
|
|
|
} |
129
|
|
|
|
130
|
1 |
|
return $data; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* CMB2 field for BGG Search. |
135
|
|
|
* |
136
|
|
|
* @since 1.2.0 |
137
|
|
|
*/ |
138
|
|
|
function fields() { |
|
|
|
|
139
|
|
|
$search_results = get_transient( 'gc_last_bgg_search' ); |
140
|
|
|
|
141
|
|
|
// First run. |
142
|
|
|
if ( ! $search_results || isset( $_GET['reset_search'] ) ) { |
143
|
|
|
|
144
|
|
|
// If we're clearing the search, delete the transient and start over. |
145
|
|
|
if ( isset( $_GET['bgg_search_reset_nonce'] ) && |
146
|
|
|
wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['bgg_search_reset_nonce'] ) ), 'bgg_search_reset_nonce' ) ) { |
147
|
|
|
delete_transient( 'gc_last_bgg_search' ); |
148
|
|
|
add_action( 'admin_notices', __NAMESPACE__ . '\\search_cleared_notice' ); |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
$cmb = new_cmb2_box( [ |
152
|
|
|
'id' => 'bgg-search', |
153
|
|
|
'title' => __( 'Add game from Board Game Geek', 'games-collector' ), |
154
|
|
|
'object_types' => [ 'options-page' ], |
155
|
|
|
'option_key' => 'add_from_bgg', |
156
|
|
|
'parent_slug' => 'edit.php?post_type=gc_game', |
157
|
|
|
'menu_title' => __( 'Add New From BGG', 'games-collector' ), |
158
|
|
|
'save_button' => __( 'Search for Game', 'games-collector' ), |
159
|
|
|
] ); |
160
|
|
|
|
161
|
|
|
$cmb->add_field( [ |
162
|
|
|
'name' => __( 'Search', 'games-collector' ), |
163
|
|
|
'id' => 'bgg_searchform', |
164
|
|
|
'type' => 'bgg_search', |
165
|
|
|
'desc' => __( 'Type in the title of a game to search for that game on Board Game Geek.', 'games-collector' ), |
166
|
|
|
] ); |
167
|
|
|
} else { |
168
|
|
|
// Choose the right game. |
169
|
|
|
$cmb = new_cmb2_box( [ |
170
|
|
|
'id' => 'bgg-search-2', |
171
|
|
|
'title' => __( 'Add game from Board Game Geek — Step 2', 'games-collector' ), |
172
|
|
|
'object_types' => [ 'options-page' ], |
173
|
|
|
'option_key' => 'add_from_bgg', |
174
|
|
|
'parent_slug' => 'edit.php?post_type=gc_game', |
175
|
|
|
'menu_title' => __( 'Add New From BGG', 'games-collector' ), |
176
|
|
|
'save_button' => __( 'Add Game', 'games-collector' ), |
177
|
|
|
] ); |
178
|
|
|
|
179
|
|
|
$cmb->add_field( [ |
180
|
|
|
'name' => __( 'Search Results', 'games-collector' ), |
181
|
|
|
'id' => 'bgg_search_results', |
182
|
|
|
'type' => 'radio', |
183
|
|
|
'desc' => __( 'Select the game that matches your search.', 'games-collector' ), |
184
|
|
|
'options' => bgg_search_results_options( $search_results ), |
185
|
|
|
] ); |
186
|
|
|
|
187
|
|
|
$cmb->add_field( [ |
188
|
|
|
'id' => 'bgg_search_results_hidden', |
189
|
|
|
'type' => 'hidden', |
190
|
|
|
'attributes' => [ |
191
|
|
|
'name' => 'action', |
192
|
|
|
'value' => 'bgg_insert_game', |
193
|
|
|
], |
194
|
|
|
] ); |
195
|
|
|
|
196
|
|
|
$cmb->add_field( [ |
197
|
|
|
'id' => 'bgg_search_reset', |
198
|
|
|
'type' => 'bgg_search_reset', |
199
|
|
|
'button_name' => __( 'Reset Search', 'games-collector' ), |
200
|
|
|
] ); |
201
|
|
|
} |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Render the BGG search field in CMB2. |
206
|
|
|
* |
207
|
|
|
* @since 1.2.0 |
208
|
|
|
* @param string $field Not used. |
209
|
|
|
* @param string $escaped_value Not used. |
210
|
|
|
* @param int $object_id Not used. |
211
|
|
|
* @param string $object_type Not used. |
212
|
|
|
* @param object $field_type_object The CMB2 field type object. |
213
|
|
|
*/ |
214
|
|
|
function render_cmb2_bgg_search( $field, $escaped_value, $object_id, $object_type, $field_type_object ) { |
|
|
|
|
215
|
|
|
$description = '<p class="description">' . esc_html( $field_type_object->field->args()['desc'] ) . '</p>'; |
216
|
|
|
$form = sprintf( '<input id="%1$s" class="regular-text" name="%2$s" value="" placeholder="%3$s" type="text">', |
217
|
|
|
esc_attr( $field_type_object->field->args()['id'] ), |
218
|
|
|
esc_attr( $field_type_object->field->args()['id'] ), |
219
|
|
|
__( 'A game title or search, e.g. “betrayal house hill”', 'usat' ) |
220
|
|
|
); |
221
|
|
|
$hidden = '<input type="hidden" name="action" value="bgg_search_response">'; |
222
|
|
|
$output = $hidden . $form . $description; |
223
|
|
|
|
224
|
|
|
echo wp_kses( $output, [ |
225
|
|
|
'p' => [ |
226
|
|
|
'class' => [], |
227
|
|
|
], |
228
|
|
|
'input' => [ |
229
|
|
|
'id' => [], |
230
|
|
|
'class' => [], |
231
|
|
|
'name' => [], |
232
|
|
|
'value' => [], |
233
|
|
|
'type' => [], |
234
|
|
|
'placeholder' => [], |
235
|
|
|
], |
236
|
|
|
] ); |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* Render the bgg_search_reset field in CMB2. |
241
|
|
|
* |
242
|
|
|
* This adds a link styled like a button which will clear out the current BGG game search. |
243
|
|
|
* |
244
|
|
|
* @since 1.2.0 |
245
|
|
|
* @param string $field Not used. |
246
|
|
|
* @param string $escaped_value Not used. |
247
|
|
|
* @param int $object_id Not used. |
248
|
|
|
* @param string $object_type Not used. |
249
|
|
|
* @param object $field_type_object The CMB2 field object. |
250
|
|
|
*/ |
251
|
|
|
function render_cmb2_bgg_search_reset( $field, $escaped_value, $object_id, $object_type, $field_type_object ) { |
|
|
|
|
252
|
|
|
|
253
|
|
|
$nonce = wp_create_nonce( 'bgg_search_reset_nonce' ); |
254
|
|
|
$url = add_query_arg( [ |
255
|
|
|
'post_type' => 'gc_game', |
256
|
|
|
'page' => 'add_from_bgg', |
257
|
|
|
'reset_search' => true, |
258
|
|
|
'bgg_search_reset_nonce' => $nonce, |
259
|
|
|
], admin_url( 'edit.php' ) ); |
260
|
|
|
|
261
|
|
|
ob_start(); |
262
|
|
|
?> |
263
|
|
|
<a href="<?php echo esc_url_raw( $url ); ?>"> |
264
|
|
|
<div class="button alignright" name="bgg_search_reset"> |
265
|
|
|
<?php echo esc_html( $field_type_object->field->args['button_name'] ); ?> |
266
|
|
|
</div> |
267
|
|
|
</a> |
268
|
|
|
<input type="hidden" name="action" value="bgg_search_reset" /> |
269
|
|
|
<?php |
270
|
|
|
|
271
|
|
|
echo wp_kses( ob_get_clean(), [ |
272
|
|
|
'a' => [ |
273
|
|
|
'href' => [], |
274
|
|
|
], |
275
|
|
|
'div' => [ |
276
|
|
|
'class' => [], |
277
|
|
|
], |
278
|
|
|
'input' => [ |
279
|
|
|
'type' => [], |
280
|
|
|
'name' => [], |
281
|
|
|
'value' => [], |
282
|
|
|
], |
283
|
|
|
]); |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
/** |
287
|
|
|
* Store the Board Game Geek search results in a transient so we can access it later. |
288
|
|
|
* |
289
|
|
|
* @since 1.2.0 |
290
|
|
|
* @return void|wp_die |
291
|
|
|
*/ |
292
|
|
|
function search_response() { |
293
|
|
|
if ( isset( $_POST['nonce_CMB2phpbgg-search'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce_CMB2phpbgg-search'] ) ), 'nonce_CMB2phpbgg-search' ) ) { |
294
|
|
|
|
295
|
|
|
$search_query = isset( $_POST['bgg_searchform'] ) ? sanitize_text_field( wp_unslash( $_POST['bgg_searchform'] ) ) : ''; |
296
|
|
|
$results = get_bgg_search_results( $search_query ); |
297
|
|
|
set_transient( 'gc_last_bgg_search', $results, HOUR_IN_SECONDS ); |
298
|
|
|
wp_safe_redirect( admin_url( 'edit.php?post_type=gc_game&page=add_from_bgg&step=2' ) ); |
299
|
|
|
return; |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
return wp_die( esc_html__( 'Security check failed. What were you doing?', 'games-collector' ), esc_html__( 'Nonce check failed', 'games-collector' ) ); |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
/** |
306
|
|
|
* Display a notice when the search was cleared. |
307
|
|
|
* |
308
|
|
|
* @since 1.2.0 |
309
|
|
|
*/ |
310
|
|
|
function search_cleared_notice() { |
311
|
|
|
?> |
312
|
|
|
<div class="notice updated"> |
313
|
|
|
<p> |
314
|
|
|
<?php esc_html_e( 'Board Game Geek game search reset.', 'games-collector' ); ?> |
315
|
|
|
</p> |
316
|
|
|
</div> |
317
|
|
|
<?php |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
/** |
321
|
|
|
* Rearrange the Games Collector submenu. |
322
|
|
|
* |
323
|
|
|
* This moves the Add New from BGG link to directly below Add New. |
324
|
|
|
* |
325
|
|
|
* @since 1.2.0 |
326
|
|
|
* @param bool $menu_order Returns true if successful. |
327
|
|
|
* @return bool Returns the $menu_order unchanged. |
328
|
|
|
*/ |
329
|
|
|
function submenu_order( $menu_order ) { |
330
|
|
|
global $submenu; |
|
|
|
|
331
|
|
|
|
332
|
|
|
// Store the Games Collector menu to a variable. |
333
|
|
|
$items = $submenu['edit.php?post_type=gc_game']; |
334
|
|
|
|
335
|
|
|
// Item 11 is right after Add New. Item 16 is the link for Add New from BGG. |
336
|
|
|
$submenu['edit.php?post_type=gc_game'][11] = $items[16]; // WPCS: override ok. |
337
|
|
|
// Remove item 16, the old Add New from BGG link. |
338
|
|
|
unset( $submenu['edit.php?post_type=gc_game'][16] ); |
339
|
|
|
// Re-sort the menu by index. |
340
|
|
|
ksort( $submenu['edit.php?post_type=gc_game'] ); |
341
|
|
|
|
342
|
|
|
return $menu_order; |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Dislplay the BGG search results in an option array for CMB2. |
347
|
|
|
* |
348
|
|
|
* @since 1.2.0 |
349
|
|
|
* @param array $results The array of BGG search results. |
350
|
|
|
* @return array An array of options for CMB2. |
351
|
|
|
*/ |
352
|
|
|
function bgg_search_results_options( $results ) { |
353
|
1 |
|
$options = []; |
354
|
1 |
|
foreach ( $results as $game ) { |
355
|
1 |
|
$options[ absint( $game['id'] ) ] = sprintf( '%1$s [%2$s] (%3$s)', |
356
|
1 |
|
'<strong>' . esc_html( $game['name'] ) . '</strong>', |
357
|
1 |
|
esc_html( $game['year'] ), |
358
|
1 |
|
esc_html( $game['id'] ) |
359
|
|
|
); |
360
|
|
|
} |
361
|
|
|
|
362
|
1 |
|
return $options; |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
/** |
366
|
|
|
* Insert the game using BGG data from the API. |
367
|
|
|
* |
368
|
|
|
* @since 1.2.0 |
369
|
|
|
* @return void|wp_die |
370
|
|
|
*/ |
371
|
|
|
function insert_game() { |
372
|
1 |
|
if ( isset( $_POST['nonce_CMB2phpbgg-search-2'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce_CMB2phpbgg-search-2'] ) ), 'nonce_CMB2phpbgg-search-2' ) ) { |
373
|
|
|
|
374
|
1 |
|
$game_id = isset( $_POST['bgg_search_results'] ) ? absint( wp_unslash( $_POST['bgg_search_results'] ) ) : false; |
375
|
1 |
|
$redirect_url = admin_url( 'edit.php?post_type=gc_game&page=add_from_bgg' ); |
376
|
|
|
|
377
|
1 |
|
if ( $game_id ) { |
378
|
1 |
|
$game = get_bgg_game( $game_id ); |
379
|
|
|
|
380
|
|
|
// Check if game already exists. |
381
|
1 |
|
if ( get_page_by_title( $game['title'], OBJECT, 'gc_game' ) ) { |
382
|
|
|
return wp_die( |
383
|
|
|
esc_html__( 'A game with that title already exists. Please try again.', 'games-collector' ), |
384
|
|
|
esc_html__( 'Duplicate game found', 'games-collector' ), |
385
|
|
|
[ 'back_link' => true ] |
386
|
|
|
); |
387
|
|
|
} |
388
|
|
|
|
389
|
1 |
|
$post_id = wp_insert_post( [ |
390
|
1 |
|
'post_type' => 'gc_game', |
391
|
1 |
|
'post_title' => esc_html( $game['title'] ), |
392
|
1 |
|
'post_status' => 'draft', |
393
|
|
|
] ); |
394
|
|
|
|
395
|
1 |
|
if ( ! is_wp_error( $post_id ) ) { |
396
|
1 |
|
$redirect_url = admin_url( sprintf( 'post.php?post=%d&action=edit', $post_id ) ); |
397
|
|
|
|
398
|
|
|
// Add game meta. |
399
|
1 |
|
add_post_meta( $post_id, '_gc_min_players', absint( $game['minplayers'] ) ); |
400
|
1 |
|
add_post_meta( $post_id, '_gc_max_players', absint( $game['maxplayers'] ) ); |
401
|
1 |
|
add_post_meta( $post_id, '_gc_age', absint( $game['minage'] ) ); |
402
|
1 |
|
add_post_meta( $post_id, '_gc_link', sprintf( 'https://www.boardgamegeek.com/boardgame/%d/', $game_id ) ); |
403
|
1 |
|
add_post_meta( $post_id, '_gc_bgg_id', $game_id ); |
404
|
|
|
|
405
|
1 |
|
if ( absint( $game['minplaytime'] ) === absint( $game['maxplaytime'] ) ) { |
406
|
1 |
|
add_post_meta( $post_id, '_gc_time', esc_html( $game['minplaytime'] ) ); |
407
|
|
|
} else { |
408
|
|
|
add_post_meta( $post_id, '_gc_time', esc_html( $game['minplaytime'] . '-' . $game['maxplaytime'] ) ); |
409
|
|
|
} |
410
|
|
|
|
411
|
1 |
|
if ( isset( $game['categories'] ) ) { |
412
|
1 |
|
foreach ( $game['categories'] as $game_attribute ) { |
413
|
1 |
|
$similar_attribute = get_attribute_like( $game_attribute ); |
414
|
|
|
|
415
|
|
|
// If there's an existing attribute that matches the BGG category, use that. |
416
|
1 |
|
if ( $similar_attribute ) { |
417
|
|
|
wp_set_post_terms( $post_id, [ $similar_attribute ], 'gc_attribute', true ); |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
// Otherwise insert a new term. |
421
|
1 |
|
wp_set_post_terms( $post_id, $game_attribute, 'gc_attribute', true ); |
422
|
|
|
} |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
// Sideload the image from BGG. |
426
|
1 |
|
attach_bgg_image( $post_id, $game ); |
427
|
|
|
} |
428
|
|
|
} |
429
|
|
|
|
430
|
|
|
// Delete the transient so we can do this again. |
431
|
1 |
|
delete_transient( 'gc_last_bgg_search' ); |
432
|
|
|
|
433
|
|
|
// Redirect to the edit page for this game. |
434
|
1 |
|
if ( is_user_logged_in() ) { |
435
|
|
|
wp_safe_redirect( esc_url_raw( $redirect_url ) ); |
436
|
|
|
} |
437
|
|
|
|
438
|
1 |
|
return; |
439
|
|
|
} |
440
|
|
|
|
441
|
|
|
return wp_die( esc_html__( 'Security check failed. What were you doing?', 'games-collector' ), esc_html__( 'Nonce check failed', 'games-collector' ) ); |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
/** |
445
|
|
|
* Check if an existing game attribute term exists and return the ID if it does. |
446
|
|
|
* |
447
|
|
|
* @since 1.2.0 |
448
|
|
|
* @param string $search The game attribute name. |
449
|
|
|
* @return int|bool The term ID if a matching term exists, false if it doesn't. |
450
|
|
|
*/ |
451
|
|
|
function get_attribute_like( $search ) { |
452
|
|
|
// Check if a previously cached attribute for this term exists already. |
453
|
1 |
|
$cached_term_search = get_transient( 'gc_frequently_used_attributes' ); |
454
|
1 |
|
if ( $cached_term_search && array_key_exists( $search, $cached_term_search ) ) { |
455
|
|
|
return $cached_term_search[ $search ]; |
456
|
|
|
} |
457
|
|
|
|
458
|
1 |
|
$terms = []; |
459
|
1 |
|
$all_terms = get_terms( [ |
460
|
1 |
|
'taxonomy' => 'gc_attribute', |
461
|
|
|
'hide_empty' => false, |
462
|
|
|
] ); |
463
|
|
|
|
464
|
1 |
|
foreach ( $all_terms as $term ) { |
465
|
1 |
|
similar_text( $term->name, $search, $similarity ); |
466
|
1 |
|
if ( $similarity > 75 ) { |
467
|
1 |
|
$terms[] = $term->term_id; |
468
|
|
|
} |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
|
472
|
1 |
|
if ( ! is_wp_error( $terms ) && count( $terms ) > 0 ) { |
473
|
|
|
// Cache this term combination so we can access it faster later. |
474
|
1 |
|
if ( ! $cached_term_search ) { |
475
|
1 |
|
set_transient( 'gc_frequently_used_attributes', [ |
476
|
1 |
|
$search => $terms[0], |
477
|
1 |
|
], 999 * YEAR_IN_SECONDS ); |
478
|
|
|
} else { |
479
|
|
|
$cached_term_search = array_merge( $cached_term_search, [ $search => $terms[0] ] ); |
480
|
|
|
set_transient( 'gc_frequently_used_attributes', $cached_term_search, 999 * YEAR_IN_SECONDS ); |
481
|
|
|
} |
482
|
|
|
|
483
|
1 |
|
return $terms[0]; |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
return false; |
487
|
|
|
} |
488
|
|
|
|
489
|
|
|
/** |
490
|
|
|
* Sideload image for a BGG image. |
491
|
|
|
* |
492
|
|
|
* @since 1.2.0 |
493
|
|
|
* @param int $post_id The game ID. |
494
|
|
|
* @param array $game The array of game data from BGG. |
495
|
|
|
*/ |
496
|
|
|
function attach_bgg_image( $post_id, $game ) { |
497
|
1 |
|
$image_id = media_sideload_image( esc_url_raw( $game['image'] ), $post_id, esc_html( $game['title'] ), 'id' ); |
498
|
1 |
|
set_post_thumbnail( $post_id, $image_id ); |
499
|
|
|
} |
500
|
|
|
|
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.