PluginProbe
wpForo Forum / 2.2.9
wpForo Forum v2.2.9
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.2.9, at classes/Boards.php

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