| @@ -239,9 +239,9 @@ | ||
| 239 | 239 | $new_cats = json_decode( $website->categories, true ); |
| 240 | 240 | if ( is_array( $new_cats ) && ! empty( $new_cats ) ) { |
| 241 | 241 | $current = current( $new_cats ); |
| 242 | 242 | if ( is_array( $current ) && ! empty( $current ) ) { // new site's category format data. |
| 243 | - static::arrange_categories_list( $new_cats, $allCategories_new_tree ); | |
| 243 | + static::arrange_categories_list( $new_cats, $allCategories_new_tree, $website ); | |
| 244 | 244 | } elseif ( is_string( $current ) ) { // old format. |
| 245 | 245 | $allCategories = array_unique( array_merge( $allCategories, $new_cats ) ); |
| 246 | 246 | } |
| 247 | 247 | } |
| @@ -247,9 +247,9 @@ | ||
| 247 | 247 | } |
| 248 | 248 | } else { |
| 249 | 249 | $custom_categories = apply_filters( 'mainwp_edit_post_get_categories', false, $website, $_REQUEST ); |
| 250 | 250 | if ( is_array( $custom_categories ) && ! empty( $custom_categories ) ) { |
| 251 | - static::arrange_categories_list( $custom_categories, $allCategories_new_tree ); | |
| 251 | + static::arrange_categories_list( $custom_categories, $allCategories_new_tree, $website ); | |
| 252 | 252 | } |
| 253 | 253 | } |
| 254 | 254 | } |
| 255 | 255 | } |
| @@ -292,10 +292,34 @@ | ||
| 292 | 292 | * @param array $print_cats categories to print. |
| 293 | 293 | * @param array $check_printed_cats_names check printed cats slugs. |
| 294 | 294 | */ |
| 295 | 295 | public static function print_catergories_tree( $print_cats, &$check_printed_cats_names = array() ) { // phpcs:ignore Squiz.Functions.MultiLineFunctionDeclaration.ContentAfterBrace -- NOSONAR - complexity. |
| 296 | + | |
| 297 | + // Build the list of sites for each category to show in tooltip. | |
| 298 | + $cats_sites = array(); | |
| 296 | 299 | foreach ( $print_cats as $item ) { |
| 297 | 300 | |
| 301 | + $term_pt = isset( $item['term_post_type'] ) && ! empty( $item['term_post_type'] ) ? sanitize_text_field( wp_unslash( $item['term_post_type'] ) ) : ''; | |
| 302 | + | |
| 303 | + $print_slug = $item['slug']; | |
| 304 | + | |
| 305 | + if ( ! empty( $term_pt ) ) { | |
| 306 | + $print_slug .= '_' . $term_pt; | |
| 307 | + } | |
| 308 | + | |
| 309 | + if ( isset( $item['site_id'] ) && isset( $item['site_name'] ) ) { | |
| 310 | + if ( ! isset( $cats_sites[ $print_slug ] ) ) { | |
| 311 | + $cats_sites[ $print_slug ] = array(); | |
| 312 | + } | |
| 313 | + | |
| 314 | + if ( ! in_array( $item['site_name'], $cats_sites[ $print_slug ], true ) ) { | |
| 315 | + $cats_sites[ $print_slug ][] = $item['site_name']; | |
| 316 | + } | |
| 317 | + } | |
| 318 | + } | |
| 319 | + | |
| 320 | + foreach ( $print_cats as $item ) { | |
| 321 | + | |
| 298 | 322 | $level = isset( $item['level'] ) ? $item['level'] : 0; |
| 299 | 323 | $term_pt = isset( $item['term_post_type'] ) && ! empty( $item['term_post_type'] ) ? sanitize_text_field( wp_unslash( $item['term_post_type'] ) ) : ''; |
| 300 | 324 | |
| 301 | 325 | $print_slug = $item['slug']; |
| @@ -323,10 +347,14 @@ | ||
| 323 | 347 | } else { |
| 324 | 348 | $cat_val = esc_attr( $item['name'] ); |
| 325 | 349 | } |
| 326 | 350 | |
| 351 | + if ( ! empty( $cats_sites[ $print_slug ] ) ) { | |
| 352 | + $cls .= ' mainwp-html-popup '; | |
| 353 | + } | |
| 354 | + | |
| 327 | 355 | $title = ! empty( $term_pt ) ? '<strong>' . esc_html( $item['name'] ) . '</strong>' : esc_html( $item['name'] ); |
| 328 | - echo '<div class="item ' . esc_attr( $cls ) . '" data-value="' . $cat_val . '" data-slug="' . esc_attr( $item['slug'] ) . '" post-type="' . esc_attr( $term_pt ) . '"class="sitecategory-list">' . $title . '</div>'; //phpcs:ignore -- ok. | |
| 356 | + echo '<div class="item ' . esc_attr( $cls ) . '" data-value="' . $cat_val . '" data-slug="' . esc_attr( $item['slug'] ) . '" post-type="' . esc_attr( $term_pt ) . '" ' . ( ! empty( $cats_sites[ $print_slug ] ) ? ' data-position="left center" html-popup-content="' . esc_attr( implode( ', ', $cats_sites[ $print_slug ] ) ) . '" data-inverted=""' : '') . '>' . $title . '</div>'; //phpcs:ignore -- $title ok. | |
| 329 | 357 | } |
| 330 | 358 | |
| 331 | 359 | if ( ! empty( $item['children'] ) ) { |
| 332 | 360 | static::print_catergories_tree( $item['children'], $check_printed_cats_names ); |
| @@ -338,12 +366,15 @@ | ||
| 338 | 366 | * Method arrange_categories_list() |
| 339 | 367 | * |
| 340 | 368 | * Tweaked John#105641 at StackOver#4284616. |
| 341 | 369 | * |
| 342 | - * @param array $categories categories. | |
| 343 | - * @param array $save_all_cats_tree all categories tree. | |
| 370 | + * Builds a hierarchical category tree from a flat category list. | |
| 371 | + * | |
| 372 | + * @param array $categories categories. | |
| 373 | + * @param array $save_all_cats_tree all categories tree. | |
| 374 | + * @param object $website website object. | |
| 344 | 375 | */ |
| 345 | - public static function arrange_categories_list( $categories, &$save_all_cats_tree ) { //phpcs:ignore -- NOSONAR - complex. | |
| 376 | + public static function arrange_categories_list( $categories, &$save_all_cats_tree, $website = null ) { //phpcs:ignore -- NOSONAR - complex. | |
| 346 | 377 | |
| 347 | 378 | if ( ! is_array( $save_all_cats_tree ) ) { |
| 348 | 379 | $save_all_cats_tree = array(); |
| 349 | 380 | } |
| @@ -352,10 +383,10 @@ | ||
| 352 | 383 | return; |
| 353 | 384 | } |
| 354 | 385 | |
| 355 | 386 | $tree_cats = $save_all_cats_tree; |
| 356 | - $all_cats = array(); | |
| 357 | - $child_cats = array(); | |
| 387 | + $all_cats = array(); // Category lookup indexed by term_id. | |
| 388 | + $child_cats = array(); // Categories waiting for their parent to be processed. | |
| 358 | 389 | |
| 359 | 390 | foreach ( $categories as $cat ) { |
| 360 | 391 | |
| 361 | 392 | if ( ! is_array( $cat ) || empty( $cat['name'] ) ) { |
| @@ -361,27 +392,34 @@ | ||
| 361 | 392 | if ( ! is_array( $cat ) || empty( $cat['name'] ) ) { |
| 362 | 393 | continue; |
| 363 | 394 | } |
| 364 | 395 | |
| 396 | + $cat['site_id'] = $website ? $website->id : null; | |
| 397 | + $cat['site_name'] = $website ? $website->name : null; | |
| 398 | + | |
| 365 | 399 | $cat['children'] = array(); |
| 366 | 400 | $term_id = $cat['term_id']; |
| 367 | 401 | |
| 368 | - // If this is a top-level. | |
| 402 | + // Top-level category. | |
| 369 | 403 | if ( empty( $cat['parent'] ) ) { |
| 370 | 404 | $cat['level'] = 0; |
| 371 | 405 | $all_cats[ $term_id ] = $cat; |
| 372 | - $tree_cats[] =& $all_cats[ $term_id ]; | |
| 373 | - // If this isn't a top-level. | |
| 406 | + // Store by reference so child relationships added later | |
| 407 | + // are reflected in the final tree structure. | |
| 408 | + $tree_cats[] =& $all_cats[ $term_id ]; | |
| 374 | 409 | } else { |
| 410 | + // Parent may not have been processed yet, so defer linking. | |
| 375 | 411 | $cat['level'] = isset( $all_cats[ $cat['parent'] ] ) && isset( $all_cats[ $cat['parent'] ]['level'] ) ? $all_cats[ $cat['parent'] ]['level'] + 1 : 1; |
| 376 | 412 | $child_cats[ $term_id ] = $cat; |
| 377 | 413 | } |
| 378 | 414 | } |
| 379 | 415 | |
| 416 | + // Multiple passes are needed when categories are not ordered by hierarchy. | |
| 417 | + // Limit iterations to prevent infinite loops caused by invalid parent IDs. | |
| 380 | 418 | $stop = count( $categories ); |
| 381 | 419 | $limit = 0; |
| 382 | 420 | $count = count( $child_cats ); |
| 383 | - // Process child cats. | |
| 421 | + | |
| 384 | 422 | while ( $count > 0 && $limit < $stop ) { |
| 385 | 423 | foreach ( $child_cats as $cat ) { |
| 386 | 424 | $term_id = $cat['term_id']; |
| 387 | 425 | $pid = isset( $cat['parent'] ) ? $cat['parent'] : -1; |
| @@ -386,17 +424,23 @@ | ||
| 386 | 424 | $term_id = $cat['term_id']; |
| 387 | 425 | $pid = isset( $cat['parent'] ) ? $cat['parent'] : -1; |
| 388 | 426 | |
| 389 | 427 | if ( isset( $all_cats[ $pid ] ) ) { |
| 390 | - $cat['level'] = isset( $all_cats[ $pid ] ) && isset( $all_cats[ $pid ]['level'] ) ? $all_cats[ $pid ]['level'] + 1 : 1; | |
| 391 | - $all_cats[ $term_id ] = $cat; | |
| 428 | + $cat['level'] = isset( $all_cats[ $pid ]['level'] ) ? $all_cats[ $pid ]['level'] + 1 : 1; | |
| 429 | + $all_cats[ $term_id ] = $cat; | |
| 430 | + | |
| 431 | + // Link child to parent by reference so nested descendants | |
| 432 | + // automatically become part of the tree. | |
| 392 | 433 | $all_cats[ $pid ]['children'][] =& $all_cats[ $term_id ]; |
| 393 | - unset( $child_cats[ $cat['term_id'] ] ); | |
| 434 | + | |
| 435 | + unset( $child_cats[ $term_id ] ); | |
| 394 | 436 | } |
| 395 | 437 | } |
| 396 | 438 | ++$limit; |
| 397 | 439 | } |
| 398 | - $save_all_cats_tree = $tree_cats; // to prevent it deleted by reference. | |
| 440 | + | |
| 441 | + // Return the completed category tree. | |
| 442 | + $save_all_cats_tree = $tree_cats; | |
| 399 | 443 | } |
| 400 | 444 | |
| 401 | 445 | /** |
| 402 | 446 | * Method posting_bulk() |
| @@ -519,9 +563,9 @@ | ||
| 519 | 563 | } else { |
| 520 | 564 | ?> |
| 521 | 565 | <div class="error"> |
| 522 | 566 | <p> |
| 523 | - <strong><?php esc_html_e( 'ERROR', 'mainwp' ); ?></strong>: <?php esc_html_e( 'An undefined error occured!', 'mainwp' ); ?> | |
| 567 | + <strong><?php esc_html_e( 'ERROR', 'mainwp' ); ?></strong>: <?php esc_html_e( 'An undefined error occurred!', 'mainwp' ); ?> | |
| 524 | 568 | </p> |
| 525 | 569 | </div> |
| 526 | 570 | <?php |
| 527 | 571 | } |