Skip to content

Price filters

simpbire_calculated_booking_price Filter

Starting with version 2.0.2, Simple Bike Rental PRO introduces the 'simpbire_calculated_booking_price' filter, which allows developers to change the final price of a booking without having to modify the plugin files.

The filter is applied after the plugin completes all its internal calculations — including hourly and daily rates, quantities, accessories, and multi-day discounts — and before the total is saved in the booking and used for Stripe payment.

If no code uses this filter, the plugin continues to function exactly as it did in previous versions.

Syntax

add_filter(
    'simpbire_calculated_booking_price',
    function ( $total, $context ) {

        // Use $context to check dates, rental type, 
        // bicycle rates, quantities, and accessories.

        // Apply your custom pricing logic here.

        return $total;
    },
    10,
    2
);

The $total parameter contains the original total calculated internally by the plugin. The $context parameter provides access to booking information and configured bicycle rates, such as daily_rate and hourly_rate.

Informational messages in the price summary

When the filter changes the final total, the price shown in the summary might not match the sum of the individual items.

For example:

60.00 € — Bicycle price
Total: 45.00 € 

To explain to the user why the total has changed, you can use the simpbire_calculated_booking_price_notice filter.

The message appears in the price summary, right before the final total.

add_filter(
    'simpbire_calculated_booking_price_notice',
    function ( $notice, $filtered_total, $original_total, $context ) {
        return 'Promotional rate applied.';
    },
    10,
    4
);

The callback receives four parameters:

Parameters Description
$notice Current message. By default, it's an empty string.
$filtered_total Final total after applying the price filter.
$original_total Total calculated internally by the plugin before filtering.
$context The same array of information used by the price filter.

The message:

  • is only displayed in the dynamic price summary on the frontend;
  • is not saved in the booking;
  • is not sent to Stripe;
  • is not added to emails or administrative details;
  • is not displayed when the filter returns an empty string.

It's advisable to display the message only when the price has actually been changed:

add_filter(
    'simpbire_calculated_booking_price_notice',
    function ( $notice, $filtered_total, $original_total, $context ) {

        if ( abs( $filtered_total - $original_total ) < 0.01 ) {
            return '';
        }

        return 'A custom fee has been applied.';

    },
    10,
    4
);

The $context parameter

The $context parameter contains the main booking details. Among the most useful are:

Key Description
reservation_id Booking ID. During the price preview, the booking has not yet been saved, and the value is 0.
calculation_source Indicates which plugin operation requested the price calculation. Especially useful for advanced integrations and debugging. (ajax_preview, frontend_save, admin_save, admin_accessories_update).
is_preview Indicates whether the calculation is a dynamic price preview (true) or a recalculation for a booking (false). Especially useful for advanced integrations and debugging.
rental_type Rental type.
daily_rate Standard daily rate configured for the selected bicycle.
hourly_rate Standard hourly rate configured for the selected bicycle.
bike_id Bicycle ID.
start_date Start date (Y-m-d).
end_date End date (Y-m-d).
start_time Start time.
end_time End time
quantity Number of bicycles reserved.
original_total Original total calculated by the plugin before filtering.
bike_total_single Final total for the single bicycle.
bike_total_with_quantity Total calculated for the bicycles, based on the quantity booked. Accessories are not included.
accessories_total Final total for accessories.
currency Currency configured in the plugin.

Note: Generally, you don't need to use calculation_source or is_preview in pricing rules. The filter should yield consistent results when previewing and saving the booking.

rental_type values

The plugin currently uses these identifiers:

Value Meaning
orario Hourly rental
giornaliero Daily rental
multiday Multi-day rental

These values can be used to apply different rules based on the type of booking.

Examples

1. Always set a fixed price

add_filter( 
    'simpbire_calculated_booking_price', 
    function ( $total, $context ) { 
        return 10.00; 
    }, 
    10, 
    2 
);

// Fixed-price message
add_filter(
    'simpbire_calculated_booking_price_notice',
    function ( $notice, $filtered_total, $original_total, $context ) {
        if ( abs( $filtered_total - $original_total ) < 0.01 ) {
            return '';
        }
        return 'Custom fixed price applied.';
    },
    10,
    4
);

2. Apply a change only to daily rentals

add_filter(
    'simpbire_calculated_booking_price',
    function ( $total, $context ) {
        if ( 'giornaliero' !== ( $context['rental_type'] ?? '' ) ) {
            return $total;
        }
        return $total * 0.90;
    },
    10,
    2
);

// Message regarding the discount on daily rentals
add_filter(
    'simpbire_calculated_booking_price_notice',
    function ( $notice, $filtered_total, $original_total, $context ) {
        if (
            'giornaliero' === ( $context['rental_type'] ?? '' )
            && $filtered_total < $original_total
        ) {
            return '10% discount applied to the daily rental.';
        }
        return $notice;
    },
    10,
    4
);

In this example, a 10% discount is applied only to daily rentals.

3. Special price for a specific date

add_filter(
    'simpbire_calculated_booking_price',
    function ( $total, $context ) {
        if (
            'giornaliero' === ( $context['rental_type'] ?? '' )
            && '2026-08-15' === ( $context['start_date'] ?? '' )
        ) {
            // Special fixed price.
            return 45.00;
        }
        return $total;
    },
    10,
    2
);

// Message regarding the special price for a specific date
add_filter(
    'simpbire_calculated_booking_price_notice',
    function ( $notice, $filtered_total, $original_total, $context ) {
        if (
            'giornaliero' === ( $context['rental_type'] ?? '' )
            && '2026-08-15' === ( $context['start_date'] ?? '' )
        ) {
            return 'Special rate applied for August 15th.';
        }
        return $notice;
    },
    10,
    4
);

In this example, a special daily rental price is set for a specific date

To apply a percentage discount, such as 20%, instead of a fixed price, replacereturn 45.00; with return $total * 0.80;

4. Apply a discount to multiple dates

add_filter(
    'simpbire_calculated_booking_price',
    function ( $total, $context ) {
        if ( 'giornaliero' !== ( $context['rental_type'] ?? '' ) ) {
            return $total;
        }
        $discount_dates = array(
            '2026-08-15',
            '2026-09-10',
            '2026-10-05',
        );
        if ( in_array( $context['start_date'] ?? '', $discount_dates, true ) ) {
            return $total * 0.80;
        }
        return $total;
    },
    10,
    2
);

// Message for the discount applied to multiple dates
add_filter(
    'simpbire_calculated_booking_price_notice',
    function ( $notice, $filtered_total, $original_total, $context ) {
        $discount_dates = array(
            '2026-08-15',
            '2026-09-10',
            '2026-10-05',
        );
        if (
            'giornaliero' === ( $context['rental_type'] ?? '' )
            && in_array( $context['start_date'] ?? '', $discount_dates, true )
            && $filtered_total < $original_total
        ) {
            return '20% promotional discount applied.';
        }
        return $notice;
    },
    10,
    4
);

In this example, a discount is applied to multiple dates for the daily rental type

5. Different rates on weekdays and weekends

add_filter(
    'simpbire_calculated_booking_price',
    function ( $total, $context ) {
        if ( 'giornaliero' !== ( $context['rental_type'] ?? '' ) ) {
            return $total;
        }

        $daily_rate = (float) ( $context['daily_rate'] ?? 0 );

        if ( $daily_rate <= 0 ) {
            return $total;
        }

        $date = DateTimeImmutable::createFromFormat(
            'Y-m-d',
            $context['start_date'] ?? ''
        );

        if ( ! $date ) {
            return $total;
        }

        $quantity = max(
            1,
            (int) ( $context['quantity'] ?? 1 )
        );

        $accessories_total = max(
            0.0,
            (float) ( $context['accessories_total'] ?? 0 )
        );

        $bike_total = $daily_rate * $quantity;
        $is_weekend = (int) $date->format( 'N' ) >= 6;

        return $is_weekend
            ? round( ( $bike_total * 1.10 ) + $accessories_total, 2 )
            : round( $bike_total + $accessories_total, 2 );
    },
    10,
    2
);

add_filter(
    'simpbire_calculated_booking_price_notice',
    function ( $notice, $filtered_total, $original_total, $context ) {
        if ( 'giornaliero' !== ( $context['rental_type'] ?? '' ) ) {
            return $notice;
        }

        $date = DateTimeImmutable::createFromFormat(
            'Y-m-d',
            $context['start_date'] ?? ''
        );

        if ( ! $date || (int) $date->format( 'N' ) < 6 ) {
            return $notice;
        }

        return 'A 10% weekend surcharge has been applied.';
    },
    10,
    4
);

This example uses the daily rate configured for the bicycle and applies a 10% surcharge only on Saturdays and Sundays. On weekdays, the normal daily rate is maintained, and no message is displayed.

On weekends, the message "10% weekend surcharge applied" is displayed.

6. Different rates for each day of a multi-day booking

This is a more advanced example.

The code reconstructs the booking price day by day, applying a different rate on weekends.

/**
 * Multi-day pricing:
 * - standard daily rate from Monday to Friday;
 * - 10% surcharge on Saturdays and Sundays.
 */
add_filter(
    'simpbire_calculated_booking_price',
    function ( $original_total, $context ) {

        if ( 'multiday' !== ( $context['rental_type'] ?? '' ) ) {
            return $original_total;
        }

        $daily_rate = isset( $context['daily_rate'] )
            ? (float) $context['daily_rate']
            : 0.0;

        if ( $daily_rate <= 0 ) {
            return $original_total;
        }

        $start_date = $context['start_date'] ?? '';
        $end_date   = $context['end_date'] ?? '';

        if ( ! $start_date || ! $end_date ) {
            return $original_total;
        }

        try {
            $current = new DateTimeImmutable( $start_date );
            $end     = new DateTimeImmutable( $end_date );
        } catch ( Exception $e ) {
            return $original_total;
        }

        if ( $end < $current ) {
            return $original_total;
        }

        $bike_total_single = 0.0;

        while ( $current <= $end ) {
            $day_of_week = (int) $current->format( 'N' );
            $day_rate    = $daily_rate;

            // 6 = Saturday, 7 = Sunday.
            if ( $day_of_week >= 6 ) {
                $day_rate *= 1.10;
            }

            $bike_total_single += $day_rate;
            $current = $current->modify( '+1 day' );
        }

        $quantity = max(
            1,
            (int) ( $context['quantity'] ?? 1 )
        );

        $accessories_total = max(
            0.0,
            (float) ( $context['accessories_total'] ?? 0.0 )
        );

        return round(
            ( $bike_total_single * $quantity ) + $accessories_total,
            2
        );

    },
    10,
    2
);

/**
 * Message displayed in the price summary on the frontend.
 */
add_filter(
    'simpbire_calculated_booking_price_notice',
    function ( $notice, $filtered_total, $original_total, $context ) {

        if ( 'multiday' !== ( $context['rental_type'] ?? '' ) ) {
            return $notice;
        }

        $start_date = $context['start_date'] ?? '';
        $end_date   = $context['end_date'] ?? '';

        if ( ! $start_date || ! $end_date ) {
            return $notice;
        }

        try {
            $current = new DateTimeImmutable( $start_date );
            $end     = new DateTimeImmutable( $end_date );
        } catch ( Exception $e ) {
            return $notice;
        }

        if ( $end < $current ) {
            return $notice;
        }

        while ( $current <= $end ) {
            if ( (int) $current->format( 'N' ) >= 6 ) {
                return 'A 10% surcharge applies to Saturdays and Sundays included in the booking.';
            }

            $current = $current->modify( '+1 day' );
        }

        return $notice;

    },
    10,
    4
);

This approach allows you to implement advanced pricing logic, such as different prices for weekends (Saturdays and Sundays) on multi-day bookings.

This snippet fully reconstructs the price of the bicycle section, day by day. As a result, it replaces the plugin’s standard multi-day calculation and does not automatically apply any multi-day discount configured in the settings. Instead, the accessories are retained using the total already calculated by the plugin.

We recommend not using this filter if you've enabled the multi-day discount in the plugin's general settings.

Best practices

Price filter

  • Always return a numeric, non-negative value.
  • Return the original total when the custom rule doesn't apply.
  • Do not modify the database, send emails, or record coupon usage within the filter.
  • The plugin automatically discards non-numeric, negative, NAN, or infinite values and uses the original total.
  • Remember that the filter changes the final total, but it doesn't automatically redistribute the difference between the prices of the bike, accessories, and discounts shown in the summary.

Message filter

  • Use short, easy-to-understand messages.
  • Do not enter HTML: the filter accepts plain text.
  • Keep the same conditions as those used in the corresponding price filter.
  • The filter can be applied multiple times as the user changes dates, quantities, or accessories.
  • Do not perform any permanent operations within the filter.
  • Use $filtered_total and $original_total to check if the price has actually changed.