I've been working on a WordPress pricing page template and would appreciate feedback on the code structure, organization, and any potential improvements. The template is used to display a pricing list with categories and items.
How can we reduce this whole amount of nestiness and code?
<?php
get_header();
$cennik_kat_order = get_field('cennik_kat', 'option');
if (!is_array($cennik_kat_order)) {
$cennik_kat_order = [];
}
$sorted_cennik_categories = get_sorted_pricelist_categories($cennik_kat_order);
$mediraty = get_field('mediraty', 'option');
?>
<section class="prl c d-grid l-d">
<div class="prl--s">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed at odio vel tortor rhoncus lacinia ac ac nulla. Vestibulum facilisis justo nec congue facilisis. Morbi venenatis, nisi at lacinia fermentum, neque justo fermentum nulla, a laoreet metus ex id velit. Vivamus auctor erat vel augue tincidunt, in vehicula ex laoreet. Cras ullamcorper metus at mi sodales, at commodo urna varius. Vestibulum ac iaculis velit. Duis eu turpis risus. Nulla facilisi. Donec posuere erat eu purus congue, non tempus lorem tristique. Nulla a volutpat arcu, non rhoncus odio. Nam bibendum pharetra turpis, nec vehicula ipsum fermentum at. Aliquam erat volutpat. Fusce nec efficitur ex. Sed congue metus ac ligula iaculis, ac cursus massa cursus. Quisque nec libero sed elit fringilla tempus nec at felis. Sed ut viverra risus.
<?php
$image = new MiLossy($mediraty);
$image->Draw();
?>
</div>
<h3 class="prl__heading h3 f-400 c-black-800 m-reset">Lorem Ipsum</h3>
<div class="prl__cats hm d-flex f-c">
<?php
foreach ($sorted_cennik_categories as $key => $category) :
$icon = get_field_from_oferta_parent_by_taxonomy('icon', $category->term_id, 'taxonomy_pricelist');
$color = get_field_from_oferta_parent_by_taxonomy('color', $category->term_id, 'taxonomy_pricelist');
?>
<div class="details prl__cat hm__item--wr br" id="<?= $category->slug; ?>">
<summary class="hm__title--main p d-flex f-c ais jcb cp w-100 zero-level-hierarchy">
<span class="c-black-800 h5 f-400 m-0">Lorem Ipsum
<?php if (DEBUG) : ?>
<a style="font-size: 1em;" tabindex="-1" href="<?= get_edit_term_link($category->term_id, 'cennik_kat'); ?>">(Edytuj)</a>
<?php endif; ?></span>
<div class="prl__cat-btn d-flex aic jce">
<span class="toggle-text level-zero">Rozwiń</span>
<div class="hm__icon-wr d-flex aic jcc br">
<svg class="hm__icon" width="16" height="16" viewBox="0 0 16 16">
<use xlink:href="#arrow-down"></use>
</svg>
</div>
</div>
</summary>
<div class="content-wrapper prl__hm--wrapper w-100">
<div class="content-inner prl__hm--inner">
<div class="real-content prl__gap d-flex f-c">
<?php
$term_posts_order_ids = get_field('cennik_order_' . $category->slug, 'option');
$query = new WP_Query(
[
'post_type' => 'cennik',
'posts_per_page' => -1,
'post_parent' => 0,
'tax_query' => [
[
'taxonomy' => 'cennik_kat',
'field' => 'term_id',
'terms' => $category->term_id,
'include_children' => true,
'operator' => 'IN',
],
],
'orderby' => 'title',
'order' => 'ASC',
]
);
if (is_array($term_posts_order_ids) && !empty($term_posts_order_ids)) {
$query->posts = sort_objects_by_id_order($query->posts, $term_posts_order_ids);
}
if ($query->have_posts()) :
while ($query->have_posts()) :
$query->the_post();
$is_pakiet = has_term(get_pakiet_term_id(), 'cennik_kat', $post->ID);
$maybe_children = get_pages(['child_of' => $post->ID, 'post_type' => 'cennik']);
$has_children = !empty($maybe_children);
$is_pakiet = $has_children && $is_pakiet;
$is_group = $has_children && !$is_pakiet;
$is_single = !$has_children && !$is_pakiet;
?>
<?php if ($is_group) : ?>
<div class="details prl__item prl__gap prl__item--gr d-flex f-c w-100">
<summary class="hm__title p d-flex f-c ais jcb cp w-100 first-level-hierarchy">
<span class="c-black-800 h5 f-400 m-0">Lorem Ipsum
<?php if (DEBUG) : ?>
<a style="font-size: 1em;" tabindex="-1" href="<?= get_edit_post_link($post->ID); ?>">(Edytuj)</a>
<?php endif; ?>
</span>
<div class="prl__cat-btn d-flex aic jce">
<span class="toggle-text level-one">Rozwiń</span>
<div class="hm__icon-wr d-flex aic jcc br">
<svg class="hm__icon" width="16" height="16" viewBox="0 0 16 16">
<use xlink:href="#arrow-down"></use>
</svg>
</div>
</div>
</summary>
<div class="content-wrapper prl__hm--wrapper">
<div class="content-inner prl__hm--inner">
<div class="real-content prl__items-gr prl__gap--small d-flex f-c">
<div class="prl__hr w-100"></div>
<?php
if ($has_children) {
$children = $maybe_children;
$children_order_ids = get_field('children_order', $post->ID);
$maybe_children = get_pages(['child_of' => $post->ID, 'post_type' => 'cennik']);
$has_children = !empty($maybe_children);
$grandchildrens = [];
if (is_array($children_order_ids) && !empty($children_order_ids)) {
$children = sort_objects_by_id_order($children, $children_order_ids);
}
foreach ($children as $key => $page) {
$is_group = has_term(get_pakiet_term_id(), 'cennik_kat', $page->ID);
$group_children = get_pages(['child_of' => $page->ID, 'post_type' => 'cennik']);
if ($is_group) {
?>
<div class="details details--last prl__item prl__gap prl__item--gr d-flex f-c w-100">
<summary class="hm__title p d-flex f-c ais jcb cp w-100">
<span class="c-black-800 h6 f-500 m-0 l-3">Lorem Ipsum
<?php if (DEBUG) : ?>
<a style="font-size: 1em;" tabindex="-1" href="<?= get_edit_post_link($page->ID); ?>">(Edytuj)</a>
<?php endif; ?>
</span>
<div class="prl__cat-btn d-flex aic jce">
<span class="toggle-text level-one">Rozwiń</span>
<div class="hm__icon-wr d-flex aic jcc br">
<svg class="hm__icon" width="16" height="16" viewBox="0 0 16 16">
<use xlink:href="#arrow-down"></use>
</svg>
</div>
</div>
</summary>
<div class="content-wrapper prl__hm--wrapper w-100">
<div class="content-inner prl__hm--inner">
<div class="real-content prl__gap d-flex f-c">
<div class="prl__hr w-100"></div>
<?php
foreach ($group_children as $grandchild) {
$displayed_grandchildren[] = $grandchild->ID;
print_pricelist_item($grandchild->ID, true);
}
?>
</div>
</div>
</div>
</div>
<?php
}
}
foreach ($children as $page) {
$is_group = has_term(get_pakiet_term_id(), 'cennik_kat', $page->ID);
if (!$is_group && !in_array($page->ID, $displayed_grandchildren)) {
print_pricelist_item($page->ID, false);
}
}
}
?>
</div>
</div>
</div>
</div>
<?php endif; ?>
<?php if ($is_single) : ?>
<div class="real-content prl__item prl__gap d-flex f-c w-100">
<?php print_pricelist_item($post->ID); ?>
</div>
<?php endif; ?>
<?php
endwhile;
wp_reset_postdata();
endif;
?>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
</section>
<?php try_attach_resource('js/priceListOpening.min.js'); ?>
<?php
get_footer();
?>
function get_sorted_pricelist_categories( array $ordered_terms_id, bool $hide_empty = true ): array {
$all_terms = get_terms(
[
'taxonomy' => 'cennik_kat',
'hide_empty' => $hide_empty,
]
);
if ( ! empty( $ordered_terms_id ) ) {
$sorted_terms = sort_objects_by_id_order( $all_terms, $ordered_terms_id, 'term_id' );
} else {
usort(
$all_terms,
function ( $a, $b ) {
return strcmp( $a->slug, $b->slug );
}
);
$sorted_terms = $all_terms;
}
foreach ( $sorted_terms as $key => $term ) {
if ( $term->term_id == get_pakiet_term_id() ) {
unset( $sorted_terms[ $key ] );
}
}
return array_values( $sorted_terms );
}
/**
* Recursively retrieves a custom field value from a post or its ancestors.
*
* @param WP_Post $post_object The post object to start searching from.
* @param string $field_name The custom field name to retrieve.
* @return int|null The field value or null if not found.
*/
function get_recursive_category_id( WP_Post $post_object, string $field_name ): ?int {
if ( $cat_id = get_field( $field_name, $post_object->ID ) ) {
return $cat_id;
}
if ( ! $post_object->post_parent ) {
return null;
}
$parent = get_post( $post_object->post_parent );
return get_recursive_category_id( $parent, $field_name );
}
/**
* Retrieves and formats the price for a specific post.
*
* @param int $post_id The ID of the post for which to retrieve the price.
* @return string Formatted price or a call-to-action text if the price is not set.
*/
function show_price( int $post_id ): string {
$maybe_price = get_field( 'price', $post_id );
$maybe_from = get_field( 'prefix_from', $post_id );
$maybe_to = get_field( 'prefix_to', $post_id );
$price_upper = get_field( 'price_upper', $post_id );
if ( ! $maybe_price ) {
return 'Zadzwoń';
}
$price = format_price( $maybe_price );
if ( $maybe_price && $maybe_from ) {
$price = 'od ' . $price;
}
if ( $maybe_price && $maybe_to ) {
$price .= ' do ' . $price_upper . ' zł';
}
return $price;
}
function show_pricelist_item_type( int $post_id ) {
$type = get_field( 'type', $post_id );
if ( $type ) {
return $type;
}
$parent_id = get_post( $post_id )->post_parent;
if ( $parent_id ) {
return show_pricelist_item_type( $parent_id );
}
return '';
}
/**
* Print a pricelist item.
*
* @param int $post_id The post ID of the pricelist item.
* @param bool $white_style Whether to use white style for the item (default: false).
*/
function print_pricelist_item( int $post_id, bool $second_level = false ) {
?>
<div class="prl__price-item<?= $second_level ? ' prl__test' : null; ?> d-flex aic jcb">
<div class="d-flex f-c" style="gap: 8px;">
<div class="prl__heading h6 m-0">
<?= get_the_title( $post_id ); ?>
<?php if ( DEBUG ) : ?>
<a style="font-size: 1em;" tabindex="-1" href="<?= get_edit_post_link( $post_id ); ?>">(Edytuj)</a>
<?php endif; ?>
</div>
<div class="prl__desc"><?= get_field( 'desc', $post_id ); ?></div>
</div>
<div class="d-flex f-c jcc aie" style="gap:8px">
<div class="prl__price h6 f-500 t-r"><?= show_price( $post_id ); ?></div>
<!-- show_pricelist_item_type -->
<div class="prl__type h6 f-400 t-r c-black-700">
<?= show_pricelist_item_type( $post_id ); ?>
<?php if ( DEBUG ) : ?>
<a style="font-size: 1em;" tabindex="-1" href="<?= get_edit_post_link( $post_id ); ?>">(Edytuj)</a>
<?php endif; ?>
</div>
</div>
</div>
<?php
}
Here's what I'd like feedback on:
Code Structure: Any suggestions for improving the organization and structure of the code to make it more modular and maintainable.
Performance: Any potential performance optimizations or areas where code can be optimized.
Readability: Suggestions for improving code comments, variable names, and overall code readability.
WordPress Best Practices: Any recommendations for following WordPress best practices and conventions.
Code Quality: Any potential bugs or issues in the code that I may have missed.
I appreciate your time and assistance in reviewing this code. Your feedback will help me improve my coding skills and the quality of my project.
$icon
and$color
, and that invalidated the answer you'd received. \$\endgroup\$