PluginProbe
wpForo Forum / 3.1.4
wpForo Forum v3.1.4
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 3.1.4, at classes/Boards.php

622 lines 18.6 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(
122 $board['excld_urls']
123 ) ? array_map(
124 'trim',
125 wpforo_string2array(
126 sanitize_textarea_field(
127 $board['excld_urls']
128 )
129 )
130 ) : $board['excld_urls'] ) )
131 )
132 )
133 );
134
135 // -- START -- decode board settings
136 $board['settings'] = (array) ( wpforo_is_json( $board['settings'] ) ? json_decode(
137 $board['settings'],
138 true
139 ) : ( is_scalar( $board['settings'] ) ? array_map(
140 'trim',
141 wpforo_string2array(
142 sanitize_textarea_field(
143 $board['settings']
144 )
145 )
146 ) : $board['settings'] ) );
147 $board['settings'] = wpforo_array_args_cast_and_merge( $board['settings'], $this->default->board['settings'] );
148 $board['settings']['title'] = trim( strip_tags( (string) $board['settings']['title'] ) );
149 $board['settings']['desc'] = trim( strip_tags( (string) $board['settings']['desc'] ) );
150 // -- END -- decode board settings
151
152 if( ! $board['locale'] ) $board['locale'] = wpforo_get_site_default_locale();
153 if( ! $board['pageid'] ) $board['pageid'] = wpforo_get_option( 'wpforo_pageid', 0 );
154
155 $all_modules = array_map( '__return_true', wpforo_get_modules_info() );
156 $all_addons = array_map( '__return_true', wpforo_get_addons_info() );
157 $modules = (array) ( ( wpforo_is_json( $board['modules'] ) ) ? json_decode(
158 $board['modules'],
159 true
160 ) : $board['modules'] );
161 $modules = array_merge( $all_modules, $all_addons, $modules );
162 $board['modules'] = array_map( function( $a ) { return (bool) intval( $a ); }, $modules );
163
164 return $board;
165 }
166
167 /**
168 * @param $board
169 *
170 * @return array
171 */
172 private function encode( $board ) {
173 $board = $this->decode( $board );
174 $board['modules'] = wp_json_encode( $board['modules'] );
175 $board['excld_urls'] = wp_json_encode( $board['excld_urls'] );
176 $board['settings'] = wp_json_encode( $board['settings'] );
177 $board['is_standalone'] = intval( $board['is_standalone'] );
178 $board['status'] = intval( $board['status'] );
179
180 return $board;
181 }
182
183 /**
184 * @param $board
185 *
186 * @return false|int
187 */
188 public function add( $board ) {
189 $board = $this->encode( $board );
190 unset( $board['boardid'] );
191 $board = wpforo_array_ordered_intersect_key( $board, $this->default->board_format );
192 if( WPF()->db->insert(
193 WPF()->tables->boards,
194 $board,
195 wpforo_array_ordered_intersect_key( $this->default->board_format, $board )
196 ) ) {
197 flush_rewrite_rules( false );
198 nocache_headers();
199
200 $board['boardid'] = WPF()->db->insert_id;
201 do_action( 'wpforo_after_add_board', $board );
202
203 return $board['boardid'];
204 }
205
206 return false;
207 }
208
209 /**
210 * @param $fields
211 * @param $boardid
212 *
213 * @return bool
214 */
215 public function edit( $fields, $boardid ) {
216 $boardid = intval( $boardid );
217 $fields = wpforo_array_ordered_intersect_key( $fields, $this->default->board_format );
218 if( false !== WPF()->db->update(
219 WPF()->tables->boards,
220 $data = wpforo_array_ordered_intersect_key( $this->encode( $fields ), $fields ),
221 [ 'boardid' => $boardid ],
222 wpforo_array_ordered_intersect_key( $this->default->board_format, $fields ),
223 [ '%d' ]
224 ) ) {
225 flush_rewrite_rules( false );
226 nocache_headers();
227
228 do_action( 'wpforo_after_edit_board', $boardid, $data );
229
230 return true;
231 }
232
233 return false;
234 }
235
236 /**
237 * @param $boardid
238 *
239 * @return bool
240 */
241 public function delete( $boardid ) {
242 do_action( 'wpforo_before_delete_board', $boardid );
243
244 if( false !== WPF()->db->delete( WPF()->tables->boards, [ 'boardid' => $boardid ], [ '%d' ] ) ) {
245 flush_rewrite_rules( false );
246 nocache_headers();
247
248 do_action( 'wpforo_after_delete_board', $boardid );
249
250 return true;
251 }
252
253 return false;
254 }
255
256 private function after_save_board( $boardid ) {
257 if( $board = $this->_get_board( (int) $boardid ) ) {
258 if( $board['status'] && $board['is_standalone'] ) {
259 $sql = "UPDATE `" . WPF(
260 )->tables->boards . "` SET `is_standalone` = 0 WHERE `is_standalone` = 1 AND `boardid` <> %d";
261 WPF()->db->query( WPF()->db->prepare( $sql, $board['boardid'] ) );
262 }
263 }
264 }
265
266 private function parse_args( $args ): array {
267 $args = wpforo_parse_args( $args, $this->default->sql_select_args );
268 $args = wpforo_array_ordered_intersect_key( $args, $this->default->sql_select_args );
269 $args['slug_include'] = wpforo_parse_args( $args['slug_include'] );
270 $args['slug_exclude'] = wpforo_parse_args( $args['slug_exclude'] );
271 $args['boardid_include'] = wpforo_parse_args( $args['boardid_include'] );
272 $args['boardid_exclude'] = wpforo_parse_args( $args['boardid_exclude'] );
273 $args['pageid_include'] = wpforo_parse_args( $args['pageid_include'] );
274 $args['pageid_exclude'] = wpforo_parse_args( $args['pageid_exclude'] );
275
276 return $args;
277 }
278
279 private function build_sql_select( $args, $select = '' ): string {
280 $args = $this->parse_args( $args );
281 if( ! $select ) $select = '*';
282
283 $wheres = [];
284
285 if( ! is_null( $args['title_like'] ) ) $wheres[] = "`title` LIKE '%" . WPF()->db->esc_like( $args['title_like'] ) . "%'";
286 if( ! is_null( $args['title_notlike'] ) ) {
287 $wheres[] = "`title` NOT LIKE '%" . WPF()->db->esc_like(
288 $args['title_notlike']
289 ) . "%'";
290 }
291
292 if( ! is_null( $args['locale_like'] ) ) {
293 $locale_like = "`locale` LIKE '%" . WPF()->db->esc_like( $args['locale_like'] ) . "%'";
294 if( $args['locale_empty'] ) {
295 $locale_like = "( `locale` = '' OR `locale` IS NULL OR " . $locale_like . " )";
296 }
297 $wheres[] = $locale_like;
298 }
299 if( ! is_null( $args['locale_notlike'] ) ) {
300 $locale_notlike = "`locale` NOT LIKE '%" . WPF()->db->esc_like( $args['locale_notlike'] ) . "%'";
301 if( ! is_null( $args['locale_empty'] ) ) {
302 if( $args['locale_empty'] ) {
303 $locale_notlike = "( `locale` = '' OR `locale` IS NULL OR " . $locale_notlike . " )";
304 } else {
305 $locale_notlike = "( `locale` <> '' AND `locale` IS NOT NULL AND " . $locale_notlike . " )";
306 }
307 }
308 $wheres[] = $locale_notlike;
309 }
310 if( ! is_null( $args['locale_empty'] ) && is_null( $args['locale_like'] ) && is_null( $args['locale_notlike'] ) ) {
311 if( $args['locale_empty'] ) {
312 $wheres[] = "( `locale` = '' OR `locale` IS NULL )";
313 } else {
314 $wheres[] = "( `locale` <> '' AND `locale` IS NOT NULL )";
315 }
316 }
317
318 if( ! is_null( $args['status'] ) ) $wheres[] = "`status` = '" . intval( $args['status'] ) . "'";
319 if( ! is_null( $args['is_standalone'] ) ) $wheres[] = "`is_standalone` = '" . intval( $args['is_standalone'] ) . "'";
320
321 if( ! empty( $args['slug_include'] ) ) {
322 $wheres[] = "`slug` IN('" . implode(
323 "','",
324 array_map(
325 function( $_i ) {
326 return esc_sql(
327 trim( $_i )
328 );
329 },
330 $args['slug_include']
331 )
332 ) . "')";
333 }
334 if( ! empty( $args['slug_exclude'] ) ) {
335 $wheres[] = "`slug` NOT IN(" . implode(
336 "','",
337 array_map(
338 function( $_i ) {
339 return esc_sql(
340 trim( $_i )
341 );
342 },
343 $args['slug_exclude']
344 )
345 ) . "')";
346 }
347
348 if( ! empty( $args['boardid_include'] ) ) {
349 $wheres[] = "`boardid` IN(" . implode(
350 ',',
351 array_map(
352 'intval',
353 $args['boardid_include']
354 )
355 ) . ")";
356 }
357 if( ! empty( $args['boardid_exclude'] ) ) {
358 $wheres[] = "`boardid` NOT IN(" . implode(
359 ',',
360 array_map(
361 'intval',
362 $args['boardid_exclude']
363 )
364 ) . ")";
365 }
366
367 if( ! empty( $args['pageid_include'] ) ) {
368 $wheres[] = "`pageid` IN(" . implode(
369 ',',
370 array_map(
371 'wpforo_bigintval',
372 $args['pageid_include']
373 )
374 ) . ")";
375 }
376 if( ! empty( $args['pageid_exclude'] ) ) {
377 $wheres[] = "`pageid` NOT IN(" . implode(
378 ',',
379 array_map(
380 'wpforo_bigintval',
381 $args['pageid_exclude']
382 )
383 ) . ")";
384 }
385
386 $wheres = array_filter( $wheres );
387
388 $sql = "SELECT $select FROM " . WPF()->tables->boards;
389 if( $wheres ) $sql .= " WHERE " . implode( " AND ", $wheres );
390 if( $args['orderby'] ) $sql .= " ORDER BY " . $args['orderby'];
391 if( $args['row_count'] ) $sql .= " LIMIT " . intval( $args['offset'] ) . "," . intval( $args['row_count'] );
392
393 return $sql;
394 }
395
396 /**
397 * @param array|numeric $args
398 *
399 * @return array
400 */
401 public function _get_board( $args ) {
402 if( wpforo_is_id( $args ) ) $args = [ 'boardid_include' => (int) $args ];
403 if( ! wpfkey( $args, 'orderby' ) ) $args['orderby'] = '`boardid` DESC';
404 if( ! wpfkey( $args, 'row_count' ) ) {
405 $args['offset'] = 0;
406 $args['row_count'] = 1;
407 }
408 $board = (array) WPF()->db->get_row( $this->build_sql_select( $args ), ARRAY_A );
409 if( $board ) $board = $this->decode( $board );
410
411 return $board;
412 }
413
414 /**
415 * @param array|numeric $args
416 *
417 * @return array
418 */
419 public function get_board( $args ) {
420 return wpforo_ram_get( [ $this, '_get_board' ], $args );
421 }
422
423 /**
424 * @param array $args
425 *
426 * @return array
427 */
428 public function _get_boards( $args = [] ) {
429 return array_map( [ $this, 'decode' ], (array) WPF()->db->get_results( $this->build_sql_select( $args ), ARRAY_A ) );
430 }
431
432 public function get_boards( $args = [] ) {
433 return wpforo_ram_get( [ $this, '_get_boards' ], $args );
434 }
435
436 /**
437 * @param array $args
438 *
439 * @return int
440 */
441 public function get_count( $args = [] ) {
442 return (int) WPF()->db->get_var( $this->build_sql_select( $args, 'COUNT(*)' ) );
443 }
444
445 public function reset_current() {
446 if( WPF()->is_installed() && ( $board0 = $this->get_board( 0 ) ) ) {
447 $this->board = $board0;
448 } else {
449 $this->board = $this->default->board;
450 }
451 }
452
453 private function init_routes() {
454 $this->base_routes = array_unique( array_merge( $this->base_routes, array_keys( WPF()->tpl->base_templates ) ) );
455 $this->base_routes = array_map( 'wpforo_settings_get_slug', $this->base_routes );
456 $slugs = [];
457 if( WPF()->is_installed() ) {
458 $boards = $this->get_boards( [ 'status' => true, 'orderby' => '`boardid` ASC' ] );
459 foreach( $boards as $board ) $slugs[] = $board['slug'];
460 if( $slug0 = wpfval( $slugs, 0 ) ) $this->route = $this->full_route = $slug0;
461 }
462 $this->routes = array_unique( array_merge( $this->base_routes, $slugs ) );
463 if( ! $this->routes ) $this->routes = (array) $this->route;
464 $this->routes = preg_replace( '#^/?index\.php/?#iu', '', $this->routes );
465 $this->routes = array_map( function( $route ) { return trim( (string) $route, '/' ); }, $this->routes );
466 }
467
468 /**
469 * @param array $args
470 */
471 public function init_current( $args = [] ) {
472 if( ! WPF()->is_installed() ) return;
473 $get = wp_unslash( array_merge( WPF()->GET, $_GET ) );
474 if( is_numeric( $args ) ) $args = [ 'boardid' => intval( $args ) ];
475 $board = [];
476 if( is_null( $boardid = wpfval( $args, 'boardid' ) ) && is_null( $boardid = wpfval( $get, 'boardid' ) ) && is_null(
477 $boardid = wpfval( $get, 'wpforo_boardid' )
478 ) ) {
479 if( wpforo_is_admin() ) {
480 if( preg_match( '#^wpforo-(?:(\d*)-)?#iu', (string) wpfval( $get, 'page' ), $match ) ) {
481 if( ! $boardid = (int) wpfval( $get, 'boardid' ) ) {
482 $boardid = (int) wpfval( $match, 1 );
483 }
484 }
485 } else {
486 if( $slug = (string) wpfval( $args, 'slug' ) ) {
487 $args = [
488 'slug_include' => $slug,
489 'locale_like' => ( $locale = (string) wpfval(
490 $args,
491 'locale'
492 ) ) ? $locale : wpforo_get_site_default_locale(),
493 'locale_empty' => true,
494 'status' => true,
495 'orderby' => "( `locale` = '' OR `locale` IS NULL ) ASC, `boardid` DESC",
496 ];
497 $board = $this->get_board( $args );
498 }
499 if( ! $board && $pageid = get_the_ID() ) {
500 $args = [
501 'pageid_include' => $pageid,
502 'status' => true,
503 'orderby' => "( `locale` = '' OR `locale` IS NULL ) ASC, `boardid` DESC",
504 ];
505 if( $slug = wpforo_get_url_route() ) $args['slug_include'] = $slug;
506 $board = $this->get_board( $args );
507 }
508 if( ! $board && $slug = wpforo_get_url_route() ) {
509 $args = [
510 'slug_include' => $slug,
511 'locale_like' => ( $locale = (string) wpfval(
512 $args,
513 'locale'
514 ) ) ? $locale : wpforo_get_site_default_locale(),
515 'locale_empty' => true,
516 'status' => true,
517 'orderby' => "( `locale` = '' OR `locale` IS NULL ) ASC, `boardid` DESC",
518 ];
519 $board = $this->get_board( $args );
520 }
521 if( ! $board ) {
522 $args = [
523 'is_standalone' => true,
524 'status' => true,
525 'orderby' => "( `locale` = '' OR `locale` IS NULL ) ASC, `boardid` DESC",
526 ];
527 $board = $this->get_board( $args );
528 }
529 }
530 }
531
532 if( $board || ( $board = $this->get_board( intval( $boardid ) ) ) ) {
533 $this->board = $board;
534 } else {
535 $this->board = $this->default->board;
536 }
537
538 $this->board = apply_filters( 'wpforo_board_init_current', $this->board );
539
540 if( ! $this->board['locale'] ) $this->board['locale'] = wpforo_get_site_default_locale();
541
542 if( ! $this->board['pageid'] ) $this->board['pageid'] = wpforo_get_option( 'wpforo_pageid', 0 );
543 if( ! wpforo_is_admin() && $this->board['locale'] && WPF()->locale !== $this->board['locale'] ) {
544 if( is_wpforo_url() && is_wpforo_multiboard() ) switch_to_locale( $this->board['locale'] );
545 }
546
547 $this->route = ( ! $this->board['is_standalone'] ? $this->board['slug'] : '' );
548 $this->full_route = rtrim(
549 ( strpos(
550 (string) get_option( 'permalink_structure', '' ),
551 'index.php'
552 ) !== false ? '/index.php/' : '/' ) . $this->route,
553 '/\\'
554 );
555 ## @TODO need to test with or without lang plugins
556 // if( $lang = wpforo_get_query_var_lang() ) $this->full_route = "/$lang" . $this->full_route;
557
558 load_plugin_textdomain( 'wpforo', false, basename( WPFORO_DIR ) . '/languages' );
559
560 $this->is_inited[ $this->board['boardid'] ] = true;
561 }
562
563 /**
564 * @param string|null $field
565 *
566 * @return mixed
567 */
568 public function get_current( $field = null ) {
569 if( is_null( $field ) ) return $this->board;
570
571 return wpfval( $this->board, $field );
572 }
573
574 /**
575 * @param string $module_key
576 * @param array $board
577 *
578 * @return bool
579 */
580 public function is_module_enabled( string $module_key, array $board = [] ): bool {
581 if( ! $board ) $board = $this->get_current();
582
583 return ! wpfkey( $board, 'modules', $module_key ) || wpfval( $board, 'modules', $module_key );
584 }
585
586 public function is_multi(): bool {
587 return 1 < $this->get_count( [ 'status' => true ] );
588 }
589
590 public function get_active_boardids(): array {
591 $boardids = [];
592 $boards = $this->get_boards( [ 'status' => true ] );
593 foreach( $boards as $board ) $boardids[] = $board['boardid'];
594
595 return $boardids;
596 }
597
598 public function dropdown( $selected = null ): string {
599 if( is_null( $selected ) ) $selected = $this->get_current( 'boardid' );
600 $selected = intval( $selected );
601
602 $html = '';
603 foreach( $this->get_boards( [ 'status' => true ] ) as $board ) {
604 $html .= sprintf(
605 '<option value="%1$d" %2$s>%3$s</option>',
606 $board['boardid'],
607 selected( $board['boardid'], $selected, false ),
608 $board['title'] . '(' . strtok( $board['locale'], '_' ) . ')'
609 );
610 }
611
612 return $html;
613 }
614
615 public function get_boards_pageids(): array {
616 $pageids = [];
617 foreach( $this->get_boards() as $board ) $pageids[] = $board['pageid'];
618
619 return array_unique( $pageids );
620 }
621 }
622