PluginProbe
wpForo Forum / 2.4.2
wpForo Forum v2.4.2
3.1.5 3.1.4 3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 1.4.2 All 137 releases
wpforo / classes / Boards.php

Boards.php in wpForo Forum 2.4.2, at classes/Boards.php

542 lines 18.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace wpforo\classes;
4
5 use stdClass;
6 use wpforo\admin\listtables\Boards as BoardsListTable;
7
8 // Exit if accessed directly
9 if( ! defined( 'ABSPATH' ) ) exit;
10
11 class Boards {
12 public $default;
13 private $board;
14 public $list_table;
15 public $route = 'community';
16 public $full_route = 'community';
17 public $base_routes = [];
18 public $routes = [];
19 public $is_inited = [];
20
21 public function __construct() {
22 $this->init_defaults();
23 $this->reset_current();
24 $this->init_routes();
25 $this->init_hooks();
26 if( is_admin() ) add_action( 'wpforo_after_init', [ $this, 'init_list_table' ] );
27 }
28
29 public function init_hooks() {
30 add_action( 'wpforo_after_add_board', function( $board ) {
31 $this->after_save_board( $board['boardid'] );
32 } );
33 add_action( 'wpforo_after_edit_board', function( $boardid ) {
34 $this->after_save_board( $boardid );
35 } );
36 add_filter( 'wpforo_settings_init_core_info', function( $settings_info ) {
37 return array_filter( $settings_info, function( $v, $k ) {
38 return $v['base'] || $this->is_module_enabled( $k );
39 }, ARRAY_FILTER_USE_BOTH );
40 } );
41 add_filter( 'wpforo_settings_init_addons_info', function( $settings_info ) {
42 return array_filter( $settings_info, function( $v, $k ) {
43 return $v['base'] || $this->is_module_enabled( $k );
44 }, ARRAY_FILTER_USE_BOTH );
45 } );
46 }
47
48 public function init_list_table() {
49 if( wpfval( $_GET, 'page' ) === 'wpforo-boards' ) {
50 $this->list_table = new BoardsListTable();
51 $this->list_table->prepare_items();
52 }
53 }
54
55 private function init_defaults() {
56 $this->default = new stdClass();
57 $this->default->board = [
58 'boardid' => 0,
59 'title' => 'Forums',
60 'slug' => 'community',
61 'pageid' => 0,
62 'modules' => [],
63 'locale' => 'en_US',
64 'is_standalone' => false,
65 'excld_urls' => [],
66 'status' => true,
67 'settings' => [
68 'title' => 'Forum',
69 'desc' => 'Discussion Board',
70 ],
71 ];
72 $this->default->board_format = [
73 'boardid' => '%d',
74 'title' => '%s',
75 'slug' => '%s',
76 'pageid' => '%d',
77 'modules' => '%s',
78 'locale' => '%s',
79 'is_standalone' => '%d',
80 'excld_urls' => '%s',
81 'status' => '%d',
82 'settings' => '%s',
83 ];
84 $this->default->sql_select_args = [
85 'title_like' => null,
86 'title_notlike' => null,
87 'locale_like' => null,
88 'locale_notlike' => null,
89 'locale_empty' => null,
90 'is_standalone' => null,
91 'status' => null,
92 'slug_include' => [],
93 'slug_exclude' => [],
94 'boardid_include' => [],
95 'boardid_exclude' => [],
96 'pageid_include' => [],
97 'pageid_exclude' => [],
98 'orderby' => null,
99 'offset' => null,
100 'row_count' => null,
101 ];
102 }
103
104 /**
105 * @param $board
106 *
107 * @return array
108 */
109 public function decode( $board ) {
110 $board = array_merge( $this->default->board, (array) $board );
111 $board['boardid'] = intval( $board['boardid'] );
112 $board['pageid'] = wpforo_bigintval( $board['pageid'] );
113 $board['title'] = trim( strip_tags( (string) $board['title'] ) );
114 $board['is_standalone'] = (bool) intval( $board['is_standalone'] );
115 $board['status'] = (bool) intval( $board['status'] );
116 $board['slug'] = sanitize_title( $board['slug'], 'community' );
117 $board['locale'] = trim( strip_tags( (string) $board['locale'] ) );
118 $board['excld_urls'] = array_values(
119 array_unique(
120 array_filter(
121 (array) ( wpforo_is_json( $board['excld_urls'] ) ? json_decode( $board['excld_urls'], true ) : ( is_scalar( $board['excld_urls'] ) ? array_map(
122 'trim',
123 wpforo_string2array(
124 sanitize_textarea_field(
125 $board['excld_urls']
126 )
127 )
128 ) : $board['excld_urls'] ) )
129 )
130 )
131 );
132
133 // -- START -- decode board settings
134 $board['settings'] = (array) ( wpforo_is_json( $board['settings'] ) ? json_decode( $board['settings'], true ) : ( is_scalar( $board['settings'] ) ? array_map(
135 'trim',
136 wpforo_string2array(
137 sanitize_textarea_field(
138 $board['settings']
139 )
140 )
141 ) : $board['settings'] ) );
142 $board['settings'] = wpforo_array_args_cast_and_merge( $board['settings'], $this->default->board['settings'] );
143 $board['settings']['title'] = trim( strip_tags( (string) $board['settings']['title'] ) );
144 $board['settings']['desc'] = trim( strip_tags( (string) $board['settings']['desc'] ) );
145 // -- END -- decode board settings
146
147 if( ! $board['locale'] ) $board['locale'] = wpforo_get_site_default_locale();
148 if( ! $board['pageid'] ) $board['pageid'] = wpforo_get_option( 'wpforo_pageid', 0 );
149
150 $all_modules = array_map( '__return_true', wpforo_get_modules_info() );
151 $all_addons = array_map( '__return_true', wpforo_get_addons_info() );
152 $modules = (array) ( ( wpforo_is_json( $board['modules'] ) ) ? json_decode( $board['modules'], true ) : $board['modules'] );
153 $modules = array_merge( $all_modules, $all_addons, $modules );
154 $board['modules'] = array_map( function( $a ) { return (bool) intval( $a ); }, $modules );
155
156 return $board;
157 }
158
159 /**
160 * @param $board
161 *
162 * @return array
163 */
164 private function encode( $board ) {
165 $board = $this->decode( $board );
166 $board['modules'] = json_encode( $board['modules'] );
167 $board['excld_urls'] = json_encode( $board['excld_urls'] );
168 $board['settings'] = json_encode( $board['settings'] );
169 $board['is_standalone'] = intval( $board['is_standalone'] );
170 $board['status'] = intval( $board['status'] );
171
172 return $board;
173 }
174
175 /**
176 * @param $board
177 *
178 * @return false|int
179 */
180 public function add( $board ) {
181 $board = $this->encode( $board );
182 unset( $board['boardid'] );
183 $board = wpforo_array_ordered_intersect_key( $board, $this->default->board_format );
184 if( WPF()->db->insert(
185 WPF()->tables->boards,
186 $board,
187 wpforo_array_ordered_intersect_key( $this->default->board_format, $board )
188 ) ) {
189 flush_rewrite_rules( false );
190 nocache_headers();
191
192 $board['boardid'] = WPF()->db->insert_id;
193 do_action( 'wpforo_after_add_board', $board );
194
195 return $board['boardid'];
196 }
197
198 return false;
199 }
200
201 /**
202 * @param $fields
203 * @param $boardid
204 *
205 * @return bool
206 */
207 public function edit( $fields, $boardid ) {
208 $boardid = intval( $boardid );
209 $fields = wpforo_array_ordered_intersect_key( $fields, $this->default->board_format );
210 if( false !== WPF()->db->update(
211 WPF()->tables->boards,
212 $data = wpforo_array_ordered_intersect_key( $this->encode( $fields ), $fields ),
213 [ 'boardid' => $boardid ],
214 wpforo_array_ordered_intersect_key( $this->default->board_format, $fields ),
215 [ '%d' ]
216 ) ) {
217 flush_rewrite_rules( false );
218 nocache_headers();
219
220 do_action( 'wpforo_after_edit_board', $boardid, $data );
221
222 return true;
223 }
224
225 return false;
226 }
227
228 /**
229 * @param $boardid
230 *
231 * @return bool
232 */
233 public function delete( $boardid ) {
234 do_action( 'wpforo_before_delete_board', $boardid );
235
236 if( false !== WPF()->db->delete( WPF()->tables->boards, [ 'boardid' => $boardid ], [ '%d' ] ) ) {
237 flush_rewrite_rules( false );
238 nocache_headers();
239
240 do_action( 'wpforo_after_delete_board', $boardid );
241
242 return true;
243 }
244
245 return false;
246 }
247
248 private function after_save_board( $boardid ) {
249 if( $board = $this->_get_board( (int) $boardid ) ) {
250 if( $board['status'] && $board['is_standalone'] ) {
251 $sql = "UPDATE `" . WPF()->tables->boards . "` SET `is_standalone` = 0 WHERE `is_standalone` = 1 AND `boardid` <> %d";
252 WPF()->db->query( WPF()->db->prepare( $sql, $board['boardid'] ) );
253 }
254 }
255 }
256
257 private function parse_args( $args ): array {
258 $args = wpforo_parse_args( $args, $this->default->sql_select_args );
259 $args = wpforo_array_ordered_intersect_key( $args, $this->default->sql_select_args );
260 $args['slug_include'] = wpforo_parse_args( $args['slug_include'] );
261 $args['slug_exclude'] = wpforo_parse_args( $args['slug_exclude'] );
262 $args['boardid_include'] = wpforo_parse_args( $args['boardid_include'] );
263 $args['boardid_exclude'] = wpforo_parse_args( $args['boardid_exclude'] );
264 $args['pageid_include'] = wpforo_parse_args( $args['pageid_include'] );
265 $args['pageid_exclude'] = wpforo_parse_args( $args['pageid_exclude'] );
266
267 return $args;
268 }
269
270 private function build_sql_select( $args, $select = '' ): string {
271 $args = $this->parse_args( $args );
272 if( ! $select ) $select = '*';
273
274 $wheres = [];
275
276 if( ! is_null( $args['title_like'] ) ) $wheres[] = "`title` LIKE '%" . WPF()->db->esc_like( $args['title_like'] ) . "%'";
277 if( ! is_null( $args['title_notlike'] ) ) $wheres[] = "`title` NOT LIKE '%" . WPF()->db->esc_like( $args['title_notlike'] ) . "%'";
278
279 if( ! is_null( $args['locale_like'] ) ) {
280 $locale_like = "`locale` LIKE '%" . WPF()->db->esc_like( $args['locale_like'] ) . "%'";
281 if( $args['locale_empty'] ) {
282 $locale_like = "( `locale` = '' OR `locale` IS NULL OR " . $locale_like . " )";
283 }
284 $wheres[] = $locale_like;
285 }
286 if( ! is_null( $args['locale_notlike'] ) ) {
287 $locale_notlike = "`locale` NOT LIKE '%" . WPF()->db->esc_like( $args['locale_notlike'] ) . "%'";
288 if( ! is_null( $args['locale_empty'] ) ) {
289 if( $args['locale_empty'] ) {
290 $locale_notlike = "( `locale` = '' OR `locale` IS NULL OR " . $locale_notlike . " )";
291 } else {
292 $locale_notlike = "( `locale` <> '' AND `locale` IS NOT NULL AND " . $locale_notlike . " )";
293 }
294 }
295 $wheres[] = $locale_notlike;
296 }
297 if( ! is_null( $args['locale_empty'] ) && is_null( $args['locale_like'] ) && is_null( $args['locale_notlike'] ) ) {
298 if( $args['locale_empty'] ) {
299 $wheres[] = "( `locale` = '' OR `locale` IS NULL )";
300 } else {
301 $wheres[] = "( `locale` <> '' AND `locale` IS NOT NULL )";
302 }
303 }
304
305 if( ! is_null( $args['status'] ) ) $wheres[] = "`status` = '" . intval( $args['status'] ) . "'";
306 if( ! is_null( $args['is_standalone'] ) ) $wheres[] = "`is_standalone` = '" . intval( $args['is_standalone'] ) . "'";
307
308 if( ! empty( $args['slug_include'] ) ) $wheres[] = "`slug` IN('" . implode( "','", array_map( function( $_i ) { return esc_sql( trim( $_i ) ); }, $args['slug_include'] ) ) . "')";
309 if( ! empty( $args['slug_exclude'] ) ) $wheres[] = "`slug` NOT IN(" . implode( "','", array_map( function( $_i ) { return esc_sql( trim( $_i ) ); }, $args['slug_exclude'] ) ) . "')";
310
311 if( ! empty( $args['boardid_include'] ) ) $wheres[] = "`boardid` IN(" . implode( ',', array_map( 'intval', $args['boardid_include'] ) ) . ")";
312 if( ! empty( $args['boardid_exclude'] ) ) $wheres[] = "`boardid` NOT IN(" . implode( ',', array_map( 'intval', $args['boardid_exclude'] ) ) . ")";
313
314 if( ! empty( $args['pageid_include'] ) ) $wheres[] = "`pageid` IN(" . implode( ',', array_map( 'wpforo_bigintval', $args['pageid_include'] ) ) . ")";
315 if( ! empty( $args['pageid_exclude'] ) ) $wheres[] = "`pageid` NOT IN(" . implode( ',', array_map( 'wpforo_bigintval', $args['pageid_exclude'] ) ) . ")";
316
317 $wheres = array_filter( $wheres );
318
319 $sql = "SELECT $select FROM " . WPF()->tables->boards;
320 if( $wheres ) $sql .= " WHERE " . implode( " AND ", $wheres );
321 if( $args['orderby'] ) $sql .= " ORDER BY " . $args['orderby'];
322 if( $args['row_count'] ) $sql .= " LIMIT " . intval( $args['offset'] ) . "," . intval( $args['row_count'] );
323
324 return $sql;
325 }
326
327 /**
328 * @param array|numeric $args
329 *
330 * @return array
331 */
332 public function _get_board( $args ) {
333 if( wpforo_is_id( $args ) ) $args = [ 'boardid_include' => (int) $args ];
334 if( ! wpfkey( $args, 'orderby' ) ) $args['orderby'] = '`boardid` DESC';
335 if( ! wpfkey( $args, 'row_count' ) ) {
336 $args['offset'] = 0;
337 $args['row_count'] = 1;
338 }
339 $board = (array) WPF()->db->get_row( $this->build_sql_select( $args ), ARRAY_A );
340 if( $board ) $board = $this->decode( $board );
341
342 return $board;
343 }
344
345 /**
346 * @param array|numeric $args
347 *
348 * @return array
349 */
350 public function get_board( $args ) {
351 return wpforo_ram_get( [ $this, '_get_board' ], $args );
352 }
353
354 /**
355 * @param array $args
356 *
357 * @return array
358 */
359 public function _get_boards( $args = [] ) {
360 return array_map( [ $this, 'decode' ], (array) WPF()->db->get_results( $this->build_sql_select( $args ), ARRAY_A ) );
361 }
362
363 public function get_boards( $args = [] ) {
364 return wpforo_ram_get( [ $this, '_get_boards' ], $args );
365 }
366
367 /**
368 * @param array $args
369 *
370 * @return int
371 */
372 public function get_count( $args = [] ) {
373 return (int) WPF()->db->get_var( $this->build_sql_select( $args, 'COUNT(*)' ) );
374 }
375
376 public function reset_current() {
377 if( WPF()->is_installed() && ( $board0 = $this->get_board( 0 ) ) ) {
378 $this->board = $board0;
379 } else {
380 $this->board = $this->default->board;
381 }
382 }
383
384 private function init_routes() {
385 $this->base_routes = array_unique( array_merge( $this->base_routes, array_keys( WPF()->tpl->base_templates ) ) );
386 $this->base_routes = array_map( 'wpforo_settings_get_slug', $this->base_routes );
387 $slugs = [];
388 if( WPF()->is_installed() ) {
389 $boards = $this->get_boards( [ 'status' => true, 'orderby' => '`boardid` ASC' ] );
390 foreach( $boards as $board ) $slugs[] = $board['slug'];
391 if( $slug0 = wpfval( $slugs, 0 ) ) $this->route = $this->full_route = $slug0;
392 }
393 $this->routes = array_unique( array_merge( $this->base_routes, $slugs ) );
394 if( ! $this->routes ) $this->routes = (array) $this->route;
395 $this->routes = preg_replace( '#^/?index\.php/?#iu', '', $this->routes );
396 $this->routes = array_map( function( $route ) { return trim( (string) $route, '/' ); }, $this->routes );
397 }
398
399 /**
400 * @param array $args
401 */
402 public function init_current( $args = [] ) {
403 if( ! WPF()->is_installed() ) return;
404 $get = wp_unslash( array_merge( WPF()->GET, $_GET ) );
405 if( is_numeric( $args ) ) $args = [ 'boardid' => intval( $args ) ];
406 $board = [];
407 if( is_null( $boardid = wpfval( $args, 'boardid' ) ) && is_null( $boardid = wpfval( $get, 'boardid' ) ) && is_null( $boardid = wpfval( $get, 'wpforo_boardid' ) ) ) {
408 if( wpforo_is_admin() ) {
409 if( preg_match( '#^wpforo-(?:(\d*)-)?#iu', (string) wpfval( $get, 'page' ), $match ) ) {
410 if( ! $boardid = (int) wpfval( $get, 'boardid' ) ) {
411 $boardid = (int) wpfval( $match, 1 );
412 }
413 }
414 } else {
415 if( $slug = (string) wpfval( $args, 'slug' ) ) {
416 $args = [
417 'slug_include' => $slug,
418 'locale_like' => ( $locale = (string) wpfval( $args, 'locale' ) ) ? $locale : wpforo_get_site_default_locale(),
419 'locale_empty' => true,
420 'status' => true,
421 'orderby' => "( `locale` = '' OR `locale` IS NULL ) ASC, `boardid` DESC",
422 ];
423 $board = $this->get_board( $args );
424 }
425 if( ! $board && $pageid = get_the_ID() ) {
426 $args = [
427 'pageid_include' => $pageid,
428 'status' => true,
429 'orderby' => "( `locale` = '' OR `locale` IS NULL ) ASC, `boardid` DESC",
430 ];
431 if( $slug = wpforo_get_url_route() ) $args['slug_include'] = $slug;
432 $board = $this->get_board( $args );
433 }
434 if( ! $board && $slug = wpforo_get_url_route() ) {
435 $args = [
436 'slug_include' => $slug,
437 'locale_like' => ( $locale = (string) wpfval( $args, 'locale' ) ) ? $locale : wpforo_get_site_default_locale(),
438 'locale_empty' => true,
439 'status' => true,
440 'orderby' => "( `locale` = '' OR `locale` IS NULL ) ASC, `boardid` DESC",
441 ];
442 $board = $this->get_board( $args );
443 }
444 if( ! $board ) {
445 $args = [
446 'is_standalone' => true,
447 'status' => true,
448 'orderby' => "( `locale` = '' OR `locale` IS NULL ) ASC, `boardid` DESC",
449 ];
450 $board = $this->get_board( $args );
451 }
452 }
453 }
454
455 if( $board || ( $board = $this->get_board( intval( $boardid ) ) ) ) {
456 $this->board = $board;
457 } else {
458 $this->board = $this->default->board;
459 }
460
461 $this->board = apply_filters( 'wpforo_board_init_current', $this->board );
462
463 if( ! $this->board['locale'] ) $this->board['locale'] = wpforo_get_site_default_locale();
464
465 if( ! $this->board['pageid'] ) $this->board['pageid'] = wpforo_get_option( 'wpforo_pageid', 0 );
466 if( ! wpforo_is_admin() && $this->board['locale'] && WPF()->locale !== $this->board['locale'] ) {
467 if( is_wpforo_url() && is_wpforo_multiboard() ) switch_to_locale( $this->board['locale'] );
468 }
469
470 $this->route = ( ! $this->board['is_standalone'] ? $this->board['slug'] : '' );
471 $this->full_route = rtrim(
472 ( strpos( (string) get_option( 'permalink_structure', '' ), 'index.php' ) !== false ? '/index.php/' : '/' ) . $this->route,
473 '/\\'
474 );
475 ## @TODO need to test with or without lang plugins
476 // if( $lang = wpforo_get_query_var_lang() ) $this->full_route = "/$lang" . $this->full_route;
477
478 load_plugin_textdomain( 'wpforo', false, basename( WPFORO_DIR ) . '/languages' );
479
480 $this->is_inited[ $this->board['boardid'] ] = true;
481 }
482
483 /**
484 * @param string|null $field
485 *
486 * @return mixed
487 */
488 public function get_current( string $field = null ) {
489 if( is_null( $field ) ) return $this->board;
490
491 return wpfval( $this->board, $field );
492 }
493
494 /**
495 * @param string $module_key
496 * @param array $board
497 *
498 * @return bool
499 */
500 public function is_module_enabled( string $module_key, array $board = [] ): bool {
501 if( ! $board ) $board = $this->get_current();
502
503 return ! wpfkey( $board, 'modules', $module_key ) || wpfval( $board, 'modules', $module_key );
504 }
505
506 public function is_multi(): bool {
507 return 1 < $this->get_count( [ 'status' => true ] );
508 }
509
510 public function get_active_boardids(): array {
511 $boardids = [];
512 $boards = $this->get_boards( [ 'status' => true ] );
513 foreach( $boards as $board ) $boardids[] = $board['boardid'];
514
515 return $boardids;
516 }
517
518 public function dropdown( $selected = null ): string {
519 if( is_null( $selected ) ) $selected = $this->get_current( 'boardid' );
520 $selected = intval( $selected );
521
522 $html = '';
523 foreach( $this->get_boards( [ 'status' => true ] ) as $board ) {
524 $html .= sprintf(
525 '<option value="%1$d" %2$s>%3$s</option>',
526 $board['boardid'],
527 selected( $board['boardid'], $selected, false ),
528 $board['title'] . '(' . strtok( $board['locale'], '_' ) . ')'
529 );
530 }
531
532 return $html;
533 }
534
535 public function get_boards_pageids(): array {
536 $pageids = [];
537 foreach( $this->get_boards() as $board ) $pageids[] = $board['pageid'];
538
539 return array_unique( $pageids );
540 }
541 }
542