1
\$\begingroup\$

I'm pretty new to php coding, but i know wordpress for a long time. Also experimenting with bootstrap. I created a new Page Template and modified it a bit. What I'm looking for is to optimize this php code:

<div class="row">
<div class="col kb_landing_left">
    <?php
        global $post; 
        $post = get_post(56); 
        setup_postdata($post);
        get_template_part( 'template-parts/content', 'page', get_post_format() );
    ?>
</div>
<div class="col -sm-6">
    <div class="row">
        <div class="col kb_landing_right">
    <?php
        global $post; 
        $post = get_post(1); 
        setup_postdata($post);
        get_template_part( 'template-parts/content', 'page', get_post_format() );
    ?>
        </div>
    </div>

    <div class="row">
        <div class="col kb_landing_right">
    <?php
        global $post; 
        $post = get_post(3); 
        setup_postdata($post);
        get_template_part( 'template-parts/content', 'page', get_post_format() );
    ?>
        </div>
    </div>
    
    <div class="row">
        <div class="col kb_landing_right">
    <?php
        global $post; 
        $post = get_post(2); 
        setup_postdata($post);
        get_template_part( 'template-parts/content', 'page', get_post_format() );
    ?>
        </div>
    </div>
</div>

As you can see, it's calling for 4 specific post IDs, since i want them to appear on my homepage in a bootsrap grid. I guess this could be done better by using an array?

Any suggestion is very much appreciated! Stay healthy!

\$\endgroup\$
  • 2
    \$\begingroup\$ Please do not change the code in the question after you have received a review, read codereview.stackexchange.com/help/someone-answers. \$\endgroup\$ – pacmaninbw Jul 1 '20 at 21:54
  • 1
    \$\begingroup\$ The current question title of your question is too generic to be helpful. Please edit to the site standard, which is for the title to simply state the task accomplished by the code. Please see How do I ask a good question?. \$\endgroup\$ – BCdotWEB Jul 2 '20 at 7:22
0
\$\begingroup\$

Here is the anatomy of a shortcode, and how to add and then use them.

add_shortcode('my_custom_shortcode', function ($atts, $content = NULL, $tag = NULL) {
    $defaults = ['a' => 'default A', 'b' => 'default B', 'c' => 'default C'];
    $atts     = shortcode_atts($defaults, $atts, $tag);

    ob_start();
    ?>
    <h2>This is shortcode "<?= $tag ?>"</h2>

    <p><em>With the attributes of:</em></p>
    <ul>
        <?php foreach ($atts as $key => $value) : ?>
            <li><strong><?= $key ?>:</strong> <?= $value ?></li>
        <?php endforeach; ?>
    </ul>

    <p><em>With the content of:</em></p>
    <?= $content ?: '(Content was not passed to this shortcode)' ?>
    <?php
    return ob_get_clean();
});
  • In order to create a shortcode you need use the add_shortcode function
    • It takes two arguments: a $tag and a $callback (a callback can either be an anonymous function, as used in this example, a string that is the name of the callback function defined elsewhere, or an array of class and method).
    • $tag can be whatever you want, just as long as no other shortcode is already using that name. I chose my_custom_shortcode for this example
    • $callback accepts three arguments $atts, $content = NULL, $tag = NULL
      • $atts is an array of the arguments the user defined
      • $content is any text the user defined inside of a shortcode ([my_custom_shortcode]This text right here (if applicable)[/my_custom_shortcode])
      • $tag is the shortcode name, if you are using an anonymous function it will always be identical to the $tag name when adding the shortcode. It can be helpful because you can use the same (non-anonymous) callback function for different shortcodes and just change them slightly depending the the tag name.
  • inside the callback you can optionally use the shortcode_atts function. It allows you to restrict/expect certain values from the user, set defaults (if not passed by the user), and drop/ignore params that are invalid (as decided by you). I typically will do this, but it's not required.
  • you want to return a string in the callback. DON'T echo/display the contents directly to the buffer. That is a common mistake. You can use ob_start() to start capturing the output buffer and ob_get_clean() to get then clear the buffer when you're done.

Here is how a user (or you) can call a shortcode in code:

// This is the most primitive form, no params or content is passed
// NOTE: just like html, if there is no content, you don't need to close the shortcode tag
echo do_shortcode('[my_custom_shortcode]');

// This example has one param, in this case `b`, passed and content
// NOTE: since you do want to pass content here, you do need to have a closing shortcode tag
echo do_shortcode('[my_custom_shortcode b="some user defined value for B"]The user contents[/my_custom_shortcode]');

If you want to call a shortcode from some WYSIWYG/Gutenberg type UI tool in WordPress, you just need the string, like this...

[my_custom_shortcode]

-or-

[my_custom_shortcode b="some user defined value for B"]The user contents[/my_custom_shortcode]

...and WordPress with call do_shortcode behind the scenes.

So... How would you use it? Well I don't know what's inside your template file you're using for this question, but what's in there would go inside your shortcode callback. Here is your HTML, optimized from the original question

<div class="col kb_landing_left">
    <?= do_shortcode('[my_custom_shortcode post_id="56"]') ?>
</div>
<div class="col -sm-6">
    <?php foreach ([1, 3, 2] as $post_id) : ?>
        <div class="row">
            <div class="col kb_landing_right">
                <?= do_shortcode("[my_custom_shortcode post_id='{$post_id}']") ?>
            </div>
        </div>
    <?php endforeach; ?>
</div>

That's it, I would not mess with changing the global $post, it will cause you more problems than it's worth.

Here is how you write the shortcode:

add_shortcode('my_custom_shortcode', function ($atts, $content = NULL, $tag = NULL) {
    $atts = shortcode_atts(['post_id' => 0], $atts, $tag);

    if (empty($atts['post_id']) || empty($post = get_post($atts['post_id']))) {
        return ''; // return nothing, a proper post_id was not passed by the user
    }

    ob_start();
    ?>
    <h2>Title: <?= $post->post_title ?></h2>
    <p><?= $content ?: $post->post_excerpt ?></p>
    <p><a href="<?= get_permalink($post->ID) ?>">Read More</a></p>
    <?php
    return ob_get_clean();
});

In my example, I'm creating a custom shortcode called my_custom_shortcode. I'm only accepting a post_id param. If post_id is not passed, or is not a valid id for a post, I exit early with an empty string. If a valid post is found, then I display the Title, content (if passed by user or fallback to the post excerpt), then a Read More link that takes me to that post's url. Then catch the buffer and return it.

Let me know if you have questions!

\$\endgroup\$
  • \$\begingroup\$ Now that is truly great, i can't thank you enough! \$\endgroup\$ – Sniffles Jul 2 '20 at 15:40
  • \$\begingroup\$ I added the custom shortcode to my functions.php and my custom page template contains the HTML part with the embeded shortcodes. Everything seems to work properly, except for the excerpt. The content is not displaying, just the title and the Read More link. \$\endgroup\$ – Sniffles Jul 2 '20 at 16:11
  • \$\begingroup\$ @Sniffles quick sanity check, are you passing $content via the shortcode or does the $post have an excerpt? what does your shortcode call look like? \$\endgroup\$ – Phil F Jul 2 '20 at 19:35
  • \$\begingroup\$ I'm not sure what you mean by that. I've just copied and pasted the code above (the one where it's saying "Here is how you write the shortcode* into my functions.php Next i pasted the HTML part into my custom page template, called landingpage.php \$\endgroup\$ – Sniffles Jul 2 '20 at 19:52
  • \$\begingroup\$ The Title and the "Read More" link are displayed, but only that. Actually i wouldn't even need that, only the content of the posts is enough. Thanks! \$\endgroup\$ – Sniffles Jul 2 '20 at 19:58
4
\$\begingroup\$

Here is an improvement, but I would recommend a few additional changes as well.

<?php global $post; ?>

<div class="col kb_landing_left">
    <?php
    $post = get_post(56);
    setup_postdata($post);
    get_template_part('template-parts/content', 'page');
    ?>
</div>
<div class="col -sm-6">
    <?php foreach ([1, 3, 2] as $post_id) : ?>
        <div class="row">
            <div class="col kb_landing_right">
                <?php
                $post = get_post($post_id);
                setup_postdata($post);
                get_template_part('template-parts/content', 'page');
                ?>
            </div>
        </div>
    <?php endforeach; ?>
</div>

<?php
// Reset back to the original post
$post = get_queried_object();
setup_postdata($post);
?>

Since you're new to PHP here are some notes on PHP specifically

  • you only need to get the global variable once. Once a global variable is pulled in, it exists for the entire scope (whatever that scope happens to be).
  • if your column code is the same it should be in a foreach loop

Some WordPress stuff

  • get_template_part should only accept two parameters $slug and $name, maybe you meant get_template_part( 'template-parts/content', 'page' . get_post_format() ) possibly?
  • changing the global $post will typically cause a lot of problems down the line, so I would not do that unless you're certain it needs to be done. I would recommend something like a WordPress shortcode or PHP function that handles your template for non-current post data. Only use get_template_part for calling templates for the currently queried post.
  • if you do change the global $post, you'll (typically) need to reset it back to the original value because the rest of the (WordPress) code is dependent on it.

Please let me know if you're interested in using a WordPress shortcode for your columns.

Hope that helps!

Edit: As a side note, it looks like your html is malformed and a little bit different from the init question. Can you please check that as well. Also, please let me know if you're interested in using WordPress shortcodes. We can certainly optimize more, as we can write a little extra something today to will provide us a lot of value in the future. If WordPress is something you're never going to come back to again, then these micro-optimizes are not worth while. If this is something you plan to stick we, then it would be a good idea to take things a bit further. Thanks!

\$\endgroup\$
  • \$\begingroup\$ Again, thanks so much! Yes, i would be very intrested in using the shortcodes as well, because I'm indeed planning to use wordpress on a long term. \$\endgroup\$ – Sniffles Jul 1 '20 at 21:24
  • \$\begingroup\$ I edited the code, it was wrongly pasted. But your code works perfectly alreday! \$\endgroup\$ – Sniffles Jul 1 '20 at 21:27
  • \$\begingroup\$ Awesome, glad I can help! Could you please mark the question as 'Accepted'. And if you need anything else feel free to ask. Thanks! \$\endgroup\$ – Phil F Jul 1 '20 at 21:34
  • \$\begingroup\$ Of course, just did so.If you could give me some further advice about the shortcodes, that would be amazing! Thank you! \$\endgroup\$ – Sniffles Jul 1 '20 at 21:36
  • 1
    \$\begingroup\$ Of course, what is your current knowledge about WordPress shortcodes? codex.wordpress.org/Shortcode_API Are you familiar with what they are, or never heard of them until just now? \$\endgroup\$ – Phil F Jul 1 '20 at 21:39

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.