0

I want to centralise the prices on our website, so that I can simply update one place, and once updated it propagates to all pages.

I don't want to use a plugin.

The idea I have is to create an array of prices, then print the prices using a function, then register shortcodes with that function.

$prices = array(
    'price1' => '100',
    'price2' => '150'
)

This function doesn't work, but the idea is:

function printPrice($price) { 
    return $prices->$price
}

Then I would register the shortcodes as follows:

add_shortcode('first_price', 'printPrice(price1)');
add_shortcode('second_price', 'printPrice(price2)');

Then I would use the shortcodes as follows in a page or post:

The first price is: [first_price]
The second price is: [second_price]

Which would render on the frontend as:

The first price is: 100
The second price is: 150

If there is a better and clearer, more WordPress specific way of doing this, that doesn't involve any of the above steps, but solves the same problem, please advise. The solution doesn't need to look like what I have suggested above.

If this solution is viable, please assist me in fixing the above function.

Edit:

I found the following function which works exactly as I want, but is very cumbersome, as I have to create a function for each price:

function function_price1($atts, $content = null) {
    return '100';
}
add_shortcode('price1', 'function_price1');

function function_price2($atts, $content = null) {
    return '150';
}
add_shortcode('price2', 'function_price2');

After reading https://developer.wordpress.org/apis/handbook/shortcode/ I then tried:

// [price price1="100"]
function price_func( $atts ) {
    $a = shortcode_atts( array(
        'price1' => '100',
        'price2' => '150',
    ), $atts );
 
    return "{$a['price1']}";
}
add_shortcode( 'price1', 'price1_func' );

but this allows the user to change the price with [price price1='200'], which is not what I want.

I want the prices to be fixed, and have the user choose from a predefined list of options. Example, like this, which is shown on the shortcode API page:

[ gallery id="123" size="medium" ]

Nowhere on the shortcode API page, does it show you how to setup that shortcode, where the user can only choose from, presumably, small, medium and large.

On the page, if I use the following, the page doesn't load:

[price key="price1"]

SallyCJ suggested: But actually, a simple callback could start with function my_shortcode_callback( $atts ) where $atts will contain the shortcode attributes like key if it's specified when adding the shortcode - e.g. [print-price key="price1"] has that attribute, but [print-price] does not have it. So your callback would only need to return the price based on the value of $atts['key'], if it's set.

I do not understand this response unfortunately. I don't know how to take this, and turn it into working code.

12
  • Please see this for the correct way to create and work with shortcodes. And you don't need multiple shortcodes; you can just create one and use an attribute like key as in [print-price key="price1"] to get the specific price only. But once again, please read the linked documentation and try to come up with your own code first - if you got stuck, then you can come back here to edit your post accordingly or just post a new question, but be as detailed as possible with your code included.
    – Sally CJ
    Jul 19, 2022 at 14:49
  • And keep in mind that generic PHP questions like "how to get an array value" are better suited at Stack Overflow.
    – Sally CJ
    Jul 19, 2022 at 14:50
  • @SallyCJ I followed the link, but that didn't help, as all the examples have a shortcode where attributes are passed into the shortcode. I don't want the attributes to change. The prices are fixed. I just want to return a value for an attribute that exists. I tried using key as an attribute, but the page completely doesn't load when I do that.
    – wickyd
    Jul 19, 2022 at 18:30
  • 1
    @SallyCJ Thank you very much for the detailed response. That worked perfectly.
    – wickyd
    Jul 21, 2022 at 18:39
  • 1
    @SallyCJ Noted, noted and noted :) The link to learn how to create a block is broken. Was it perhaps this: Create a basic block
    – wickyd
    Jul 22, 2022 at 10:48

1 Answer 1

1

I do not understand this response unfortunately. I don't know how to take this, and turn it into working code.

What I meant by that response, is that you would be using a shortcode that looks like these in your posts:

  • [print-price key="price1"]
  • [print-price key="price2"]
  • [print-price key="foo-bar"]

Where key is an attribute for the shortcode named print-price, and that the attribute value corresponds to a key in the prices array which is $prices in the question. So with your sample array or prices, the first shortcode above would return 100, whereas the second one would return 150, because 100 is the value of $prices['price1'] and 150 is the value of $prices['price2'].

And that is how we access an item in that array, i.e. array[key] and not array->key (which is actually used with objects). So for example, use $prices['price1'] and not $prices->price1.

So here's a full working example you can try:

Note that I defined the prices array in the shortcode callback, but if you've got hundreds or more prices, then you might instead want to store the prices in the database, e.g. as an option in the WordPress options table (wp_options).

function print_price_shortcode( $atts ) {
    $atts = shortcode_atts(
        // default attributes and their value
        array(
            'key' => '',
        ),
        // attributes defined in the shortcode
        $atts
    );

    // Define the price list.
    $prices = array(
        'price1' => 100,
        'price2' => 150,
        // more prices here..
    );

    // Return the price for the specific key if one was set and it exists in the
    // price list, i.e. the above $prices array.
    if ( isset( $prices[ $atts['key'] ] ) ) {
        return $prices[ $atts['key'] ];
    }

    // If the key isn't in the list, then let's return an empty string. Or just
    // return something else if you want to.
    return '';
}

// Registers a shortcode named or with the tag print-price and the above function
// being the callback which RETURNS whatever text/number/etc. which will replace
// the shortcode, e.g. [print-price] or [print-price key="price1"], in the post.
add_shortcode( 'print-price', 'print_price_shortcode' );

PS: If you're using PHP 7 or later, you can, if you want to, replace the entire lines starting from the if to return ''; with this, which uses the null coalescing operator, i.e. ??:

return $prices[ $atts['key'] ] ?? '';

Update: A better/user-friendly solution

So as I commented, shortcode is easy, but if you're familiar with the block editor, then you would want to create a block which can give you a nice user interface (UI) like so where you would simply select a price from a dropdown instead of having to type in a key value. However, the block editor uses JavaScript (and React), so you will need to have some decent JavaScript programming skills in order to develop blocks. =)

Preview image (WordPress v6.0.1)

Here's the edit() function code for the above, but see my GitHub repo for the save() function and other code:

// Static prices array, but if you want to, you can make it dynamic (inside of
// the edit() function).
const PRICES = [ 100, 150, 199.99 ];

const Edit = ( { attributes, setAttributes } ) => {
    const blockProps = useBlockProps( { style: blockStyle } );

    const currency = '$'; // or maybe, use a `currency` attribute

    // Build an options object for the SelectControl element below.
    const prices = PRICES.map( price => ( {
        label: currency + price,
        value: price,
    } ) );

    // Callback which updates the `price` attribute when a new price is selected
    // from the dropdown.
    const setNewPrice = ( value ) => setAttributes( { price: Number( value ) } );

    return (
        <>
            <InspectorControls>
                <PanelBody title={ __( 'Price', 'wpse-407885' ) }>
                    <SelectControl
                        label={ __( 'Price', 'wpse-407885' ) }
                        options={ [ { // add a "Select a price" option to the price list
                            label: __( 'Select a price', 'wpse-407885' ),
                            value: '',
                        }, ...prices ] }
                        onChange={ setNewPrice }
                        value={ attributes.price }
                        hideLabelFromVision
                        __nextHasNoMarginBottom
                    />
                </PanelBody>
            </InspectorControls>

            <div { ...blockProps }>
                <p>
                    { ( !! attributes.price ) ? sprintf(
                        /* translators: %s: Price with currency, e.g. $100.00 */
                        __( 'Selected price: %s', 'wpse-407885' ),
                        currency + attributes.price.toFixed( 2 )
                    ) : <em>{ __( 'No price selected', 'wpse-407885' ) }</em> }
                </p>
            </div>
        </>
    );
};

You can also download any of these plugins that you can simply install & activate: A price dropdown right in the block editor content area, A price dropdown in the settings sidebar, or both blocks in a single plugin.

Some specific resources and tools I used:

  1. The official Gutenberg examples
  2. https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar/
  3. https://raw.githubusercontent.com/WordPress/gutenberg/trunk/schemas/json/block.json
  4. Node.js v16.16.0 (with NPM v8.13.2), Git v2.37.1 and the @wordpress/scripts package v23.0.0
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.