How do I build a page structure?


Hi, I'm very new to Beans AND Wordpress. Trying to understand the way both work at the moment having only built static html sites by hand previously. What I'm trying to understand is how to create the various structural elements I want on my pages and link those elements with content. For example I'd like my home page to feature a full width banner image with a headline and button that sit on top. Under that I'd like a grid of posts. Other pages may also feature a full width banner but just have a content are underneath with a single article. How do I create these different layouts in a way that I can edit the banner contents through Wordpress?


Hey Jason, welcome to WordPress and Beans πŸ™‚

First of all I would like to give you a bit of encouragement and let you know that there might be a bit of a learning curve just like when you learned how to write static sites. That said, it is totally worth it and you will meet plenty of helpful people in the WP and Beans community.

I am not sure how confortable you are with PHP, but I put some code together for you. Before I explain the code, here is the step you have do follow to get setup.

  1. Download and install Beans theme.
  2. Download and install Beans starter child theme.
  3. Activate the Beans starter child theme.
  4. In your starter child theme functions.php, replace the entire content with the snippet below.
  5. In your WordPress admin, create a page called blog.
  6. In your blog page, add and image, button text and button link in the Hero Content.
  7. Then go to Settings->Reading and set your Front page displays->Posts Page to Blog.
<?php

// Include Beans. Do not remove the line below.
require_once( get_template_directory() . '/lib/init.php' );

add_action( 'beans_uikit_enqueue_scripts', 'example_enqueue_uikit_assets' );

function example_enqueue_uikit_assets() {

 // Enqueue UIkit necessary extra components.
  beans_uikit_enqueue_components( array( 'flex', 'contrast' ) );

  // Enqueue child theme style.less
 beans_compiler_add_fragment( 'uikit', get_stylesheet_directory_uri() . '/style.less', 'less' );

}

add_action( 'admin_init', 'example_register_post_meta', 8 );

function example_register_post_meta() {

 $fields = array(
    array(
      'id' => 'beans_child_hero_image',
     'label' => __( 'Hero Image', 'beans-child' ),
     'type' => 'image'
   ),
    array(
      'id' => 'beans_child_hero_title',
     'label' => __( 'Hero Title', 'beans-child' ),
     'type' => 'text'
    ),
    array(
      'id' => 'beans_child_hero_button_text',
     'label' => __( 'Hero Button Text', 'beans-child' ),
     'type' => 'text'
    ),
    array(
      'id' => 'beans_child_hero_button_href',
     'label' => __( 'Hero Button Link', 'beans-child' ),
     'type' => 'text'
    )
 );

  beans_register_post_meta( $fields, array( 'post', 'page' ), 'beans-child-hero', array( 'title' => __( 'Hero Content', 'beans-child' ) ) );

}

add_action( 'wp', 'example_setup_document' );

function example_setup_document() {

 // Only apply to non-singular view.
 if ( !is_singular() ) {

   // Add grid.
    beans_wrap_inner_markup( 'beans_content', 'beans_child_posts_grid', 'div', array(
     'class' => 'uk-grid uk-grid-match',
     'data-uk-grid-margin' => ''
   ) );
    beans_wrap_markup( 'beans_post', 'beans_child_post_grid_column', 'div', array(
      'class' => 'uk-width-large-1-3 uk-width-medium-1-2'
   ) );

    // Move the posts pagination after the new grid markup.
   beans_modify_action_hook( 'beans_posts_pagination', 'beans_child_posts_grid_after_markup' );

  }

}

add_action( 'beans_header_after_markup', 'example_hero' );

function example_hero() {

 // Stop here if not image is set. We use get_queried_object to get the right id if a page is assigned to Blog Posts.
  if ( !$image_id = beans_get_post_meta( 'beans_child_hero_image', false, beans_get( 'ID', get_queried_object() ) ) )
   return;

 $image = wp_get_attachment_image_src( $image_id, 'full' );

  // Stop here if the image doesn't exist.
 if ( empty( $image[0] ) )
   return;

 ?>
  <div class="tm-hero uk-cover uk-position-relative">
   <img class="uk-width-1-1" src="<?php echo esc_url( $image[0] ); ?>" width="<?php echo esc_attr( $image[1] ); ?>" height="<?php echo esc_attr( $image[2] ); ?>">
   <div class="uk-position-cover uk-flex uk-flex-center uk-flex-middle">
     <div class="uk-text-center uk-contrast">
      <?php if ( $title = beans_get_post_meta( 'beans_child_hero_title' ) ) : ?>
        <h1><?php echo esc_html( $title ); ?></h1>
      <?php endif; ?>
     <?php if ( $button_text = beans_get_post_meta( 'beans_child_hero_button_text' ) ) : ?>
        <p><a class="uk-button uk-button-primary uk-button-large" href="<?php echo esc_url( beans_get_post_meta( 'beans_child_hero_button_href' ) ); ?>" title="<?php echo esc_attr( $button_text ); ?>"><?php echo esc_attr( $button_text ); ?></a></p>
      <?php endif; ?>
     </div>
    </div>
  </div>
  <?php

}

Here is what to code do:

  • Loads Beans framework which is always needed in your child theme functions.php
  • example_enqueue_uikit_assets() enqueues the necessary UIkit components for your layout, as well as your child theme style.less
  • example_register_post_meta() add the hero content fields in your admin blog and blog.
  • example_setup_document() adds the posts grid only for non-singular view.
  • example_hero() adds the hero section after the header if an image is set.

This is an example an example of what you should see. You could really do a lot more complex stuff like making it a slider or what ever you would like.

I realize this might be a lot to take and I am happy to help you further if something doesn't make sense to you πŸ™‚

Thanks,


Wow! Thanks heaps for that Thierry. I've been playing around with that for a while and it's really helped. So powerfull - I had no idea you could create custom fields like that. Out of interest - how would I use the image as a background image in the div with the headline and button? I'm keen to make that a full width, 60vh sized banner with a background image.

All getting very exciting!


Hey Jason, glad you like it.

While I usually don't link inline style, I think it is reasonable to add your background-image as and inline style since it is a dynamic url. Your example_hero() function would be as follow:

function example_hero() {

 // Stop here if not image is set. We use get_queried_object to get the right id if a page is assigned to Blog Posts.
  if ( !$image_id = beans_get_post_meta( 'beans_child_hero_image', false, beans_get( 'ID', get_queried_object() ) ) )
   return;

 $image = wp_get_attachment_image_src( $image_id, 'full' );

  // Stop here if the image doesn't exist.
 if ( empty( $image[0] ) )
   return;

 ?>
  <div class="tm-child-hero uk-flex uk-flex-center uk-flex-middle" style="background-image: url(<?php echo esc_url( $image[0] ); ?>);">
   <div class="uk-text-center uk-contrast">
      <?php if ( $title = beans_get_post_meta( 'beans_child_hero_title' ) ) : ?>
        <h1><?php echo esc_html( $title ); ?></h1>
      <?php endif; ?>
     <?php if ( $button_text = beans_get_post_meta( 'beans_child_hero_button_text' ) ) : ?>
        <p><a class="uk-button uk-button-primary uk-button-large" href="<?php echo esc_url( beans_get_post_meta( 'beans_child_hero_button_href' ) ); ?>" title="<?php echo esc_attr( $button_text ); ?>"><?php echo esc_attr( $button_text ); ?></a></p>
      <?php endif; ?>
   </div>
  </div>
  <?php

}

Then in your child theme style.less you would add the rest of the CSS needed as follow:

.tm-child-hero {
 background-position: 50% 50%;
 background-size: cover;
 background-repeat: no-repeat;
 height: 60vh;
}

Technically you could add it to the CSS compiler but it isn't a great idea as it would create a different file for each page. Alternatively if you really don't want inline style in the HTML, you could print it in the <head> tag, in which case your complete functions.php file would be as such.

Yes the Beans fields API is really cool, especially when using page templates. You can assign fields to a specific page template, then when you select the page template in your WP admin, it displays all the fields assigned accordingly. This way you can really keep the backend matching the front end and build clean custom solutions. It also means that you can keep your admin clean as you don't have unecesary fields bloating your admin when not needed. More about fields in the docs, let me know if you want more info about that.

Beans 1.4.0 will be focused on adding new field types and adding repeatable fields which will take it to a whole new level. An example would be if you are building a recipe page template, manually adding a field for each ingredient isn't great and the repeater will shine in this case.

Hope that helps,


Thanks Thierry, this is just getting better and better.

The background image information you gave me is working perfectly.

I was thinking about what you said here and in your previous reply about custom fields and wondered if it might be possible to use custom fields to dynamically attach classes to the h1 etc? this would be amazing if I could create the option in the admin area to align the input in the hero_title either left, right or centered etc or select from a dropdown of predefined colors and so on.

I just googled custom fields then found and installed the 'advanced custom fields' plugin for wp. Haven't had a play with this properly yet. Just wish my php knowledge was better.

Really appreciate all the help Thierry. Think I'm going to be addicted to Beans.

Cheers Jason


Hey Jason,

You can pretty much do anything you want with Beans Fields API (besides repeatable at this stage). You may add as many fields as you want and even create your own fields type if you want to. For that you do need to understand the way it works which you will find in Beans Fields API documentation. If anything isn't clear, I am happy to help indeed.

Despite that Beans Fields API is faster than ACF, it is definitely a great plugin and I recommend it if you want to add fields via the admin panel rather than in the code. Beans and AFC are very good friends and work like a charm together. Just like Beans fields, you will also be able to add any fields for specific post types, page templates etc. Then you can easily retrieve these fields values in your child themes and add it anywhere on your page. You can use the field data to build pretty cool stuff using UIkit components. If you need help with that, let me know want you are trying to achieve and where you get stuck, I will gladly help πŸ™‚

Happy coding,


Hi Thierry

Thanks for all your help to date. I've been playing with the code you gave me and am beginning to the site underway (to a degree). The fact that I'm a Wordpress and php novice is limiting πŸ™‚

I managed to add another custom field to the Hero area through adding to the code you gave me for the functions.php file.

I've also used the custom fileds plugin to create new custom fileds that I want to use for 'team member' pages. What I've pasted below is kind of getting me there but for some reason the custom field data is sitting under the hero area but above the main content area rather than within it. Thus pushing the page title underneath along with the sidebar.

Any thoughts on why this might be happening?

Here's the code that I have. (many, many thanks in advance):

<?php

add_action( 'beans_header_after_markup', 'example_hero' );

function example_hero() {

    // Stop here if not image is set. We use get_queried_object to get the right id if a page is assigned to Blog Posts.
    if ( !$image_id = beans_get_post_meta( 'beans_child_hero_image', false, beans_get( 'ID', get_queried_object() ) ) )
        return;

    $image = wp_get_attachment_image_src( $image_id, 'full' );

    // Stop here if the image doesn't exist.
    if ( empty( $image[0] ) )
        return;

    ?>
    <div class="tm-child-hero uk-flex uk-flex-center uk-flex-middle" style="background-image: url(<?php echo esc_url( $image[0] ); ?>); ">
        <div class="uk-container uk-flex uk-flex-middle uk-width-1-1 <?php echo get_field( 'heroposition'); ?> <?php echo get_field( 'heroalign'); ?> ">
            <div data-uk-parallax="{opacity: '0', viewport: 0.5, y:-100} " class="uk-width-1-2">
            <?php if ( $title = beans_get_post_meta( 'beans_child_hero_title' ) ) : ?>
                <h1 class="uk-contrast my-hero-headline"><?php echo esc_html( $title ); ?></h1>
            <?php endif; ?>
            <?php if ( $description = beans_get_post_meta( 'beans_child_hero_description' ) ) : ?>
                <h3 class="my-hero-description"><?php echo esc_html( $description ); ?></h3>
            <?php endif; ?>
            <?php if ( $button_text = beans_get_post_meta( 'beans_child_hero_button_text' ) ) : ?>
                <p><a class="uk-button  my-button-outline-white uk-button-large" href="<?php echo esc_url( beans_get_post_meta( 'beans_child_hero_button_href' ) ); ?>" title="<?php echo esc_attr( $button_text ); ?>"><?php echo esc_attr( $button_text ); ?></a></p>
            <?php endif; ?>
            </div>
        </div>
    </div>

    <div class="tm-main uk-container uk-container-center uk-flex uk-flex-middle uk-width-3-4 uk-flex-left uk-text-left ">
        <div class=" uk-width-2-6">
            <h1 data-markup-id="beans_post_title" itemprop="headline" class="uk-article-title"><?php echo ( $page_title); ?></h1>
            <?php if ( $role = beans_get_post_meta( 'role' ) ) : ?>
                <p class="uk-block"><?php echo esc_html( $role ); ?></p>
            <?php endif; ?>
        </div>
        <div class=" uk-width-2-6">
            <h1 data-markup-id="beans_post_title" itemprop="headline" class="uk-article-title"><?php echo ( $page_title); ?></h1>
            <?php if ( $role = beans_get_post_meta( 'role' ) ) : ?>
                <p class="uk-block"><?php echo esc_html( $role ); ?></p>
            <?php endif; ?>
        </div>
    </div>
    <?php

}

Hey Jason,

My first thought is that you should stick to ACF or Beans Fields API but I would personally not mixed the two. ACF might be a bit easier to manage if you are doing your debut in WP and Beans.

Regarding your roles, you are creating a new tm-main section with as a container flex and grid which isn't correct.

  • Could you give a bit more details about what you are trying to achieve (maybe a design)?
  • Do you want a page with a grid of all your team members?
  • How many team members do you have?

Thanks,


Hey Thierry

I'll put a design sketch together and provide a bit more detail about what I'd like to achieve.

Back to you shortly.

Many thanks Jason


Hi Thierry

Here's a pdf with some wireframes for the key pages.

https://cloudup.com/cssYQq4i1-n

Ideally what I'd love to achieve using Advanced Custom Fields is a set of modular page elements that can be added in any order with subfields used to control classes. I played around with that part for the code you gave me to create the hero banner section already - to control the text alignment etc and it works great.

It would be great to have the ability to add a background image to the row elements such as the one under the hero section on the home page. Or just leave it blank, or add a background colour.

Hope all this and my sketch makes sense.

Any help you could give that helps to understand how to put this together would be greatly appreciated.

Many thanks Jason


Hey Jason, thanks for putting the wireframe together.

This is turning to a full custom website and you know what, I am keen to help you achieve this πŸ™‚ I think in this case the best is to use ACF Pro. It is $25 AUD once off but I think it is worth it. If you prefer to use the free version, you might get away with it but I think repeatable fields will be useful. Down the line, you will be able to replace it with Beans Fields API but at this stage it is a bit premature. The approach I'd advise is the following:

  1. In ACF, add a field group for the hero with the same fields that we previously added with the Beans Fields to replace it. (you will do the assignment condition at the end)
  2. Still in ACF, you are going to add a fields group for each page template wich requires some (Home - About us - Programmes (if not CPT)). All the other layouts are dynamic content which doesn't need custom fields.
  3. Then for your team members, I suggest to create a post type for that so that it is re-usable and since there is a single view for each.
  4. Regarding your programmes, is it only a simple grid with a short description and the "Register" button or will it have single view with full description in which case a another custom post type would be appropriate.
  5. Once ACF and custom post types are set, then you will be able to create the template files in your child theme and in your admin assign the ACF field groups to each template.
  6. Then you will be able to write your PHP/HTML in each template.
  7. Finally add your styling (only cosmetic as all the structural and responsive is handle in UIkit) and voilΓ , a custom non-bloated professional website.

Alright, so if you are happy with the architecture, let me know what you feel confortable with and what you feel you would need help with (even if you have no idea where to start and need help with everything). Bare in mind that this seem to be a lot but it is in fact relatively easy and fun once you get your hands dirty πŸ™‚

Thanks,


Hi Thierry

Happy Easter.

I've been playing with this over the weekend and I solved the problem I was having creating the team member page and populating it with data from custom fields.

I think you're right though a custom post type would work better instead. I've been trying to figure out how to create a loop on an 'about-us' page template that will pull in posts from a custom post type 'coaches'. Ideally I'd like each of these posts to appear as an image of the coach and the coach's name on top of the image that links to the full single post page for the coach.

How would I go about doing that Thierry?

I've managed to make a good start on the programmes page with some custom fields and that's coming together well - quite simple.

I thought about upgrading to ACF Pro for the repeater but working through the pages so far don't think I'll need the repeater function - maybe in the future for other projects.

Agree, I'd like the hero section to be used pretty much on most pages so if I recreate those fields in ACF could you tell me what to do in the functions.php file to reassign?

Like I say, I've managed to create a couple of page templates to think I have that under control - not sure how I create the templates for the CPT.

Oh, one other thing I haven't quite figured out - some page elements I'd like to break out of the uk-container and become 90vw but it looks like the main content area is wrapped in the uk-container?

Many thanks for your help Thierry.


Hey Jason, happy easter to you!

Regarding your custom "coaches" loop, here is an example how you would add it in your main content fixed container:

add_action( 'beans_fixed_wrap[_main]_prepend_markup', 'example_coach_loop' );

function example_coach_loop() {

 $query = new WP_Query( array(
   'post_type' => 'coaches',
   'posts_per_page' => 3
 ) );

  ?>
  <div class="uk-grid" uk-data-grid-margin>
   <?php if ( $query->have_posts() ) : ?>
      <?php while ( $query->have_posts() ) : $query->the_post(); ?>
       <div class="uk-width-1-3">
          <a href="<?php the_permalink();?>" title="<?php esc_html( get_the_title() );?>">
            <h3><?php the_title(); ?></h3>
            <?php the_post_thumbnail(); ?>
          </a>
        </div>
      <?php endwhile; ?>
    <?php endif; ?>
 </div>
  <?php

 wp_reset_postdata();

}

In the example above, I set the number of posts to 3 but you may change it and add more query arguments such as ordering etc. You may also change the HTML according to your needs and use Beans Image API if you need to crop, resize etc the image.

Regarding replacing the Hero, you would just add the same fields in ACF as a fields group and then replace beans_get_post_meta() Beans functions with ACF get_field() function in your code (more about get_field() in this article).

For the CPT themplates, you would add archive-{post_type}.php for the "index" view and single-{post_type}.php for the single view. This discussion might help too πŸ™‚

Last but not least, you can remove any attribute using the Beans HTML API, for instance if you want to remove the main fixed container, you can add beans_remove_attribute( 'beans_fixed_wrap[_main]', 'class', 'uk-container' );. If you want to replace it with you own class to add the 90vw, you may use beans_replace_attribute( 'beans_fixed_wrap[_main]', 'class', 'uk-container', 'your-class-name' );. You could even completely remove the markup with beans_remove_markup( 'beans_fixed_wrap[_main]' );. Here is a list of all the Beans HTML API functions available.

Hope that helps,


Thanks Thierry

Great help - though I'm still a little stuck on parts of it.

I added the above code to my functions.php file - not sure if that's right? This is now displaying the coaches post on every page of the site. Ideally I'd like to call the 'coaches' posts only into a specific section on the about us page - halfway down the page under some intro text etc.

I'd like to do the same thing with another 2 custom post types - 'players-to-watch' and 'success-stories' both of which need to display the latest post on the home page, again under other content. I'd like to only show the latest, no more than 1 of each post type.

I created a archive-coaches.php page but I'm not really sure what to put in there. I had more success with the single-coaches.php page - that is now displaying all the data from my custom fields.

Also now have the hero section working across pages and posts.

Haven't tried the 90vw stuff yet - maybe tomorrow.

So definitely getting there.

Cheers Jason


Hey Jason, great to hear you are getting there.

> I added the above code to my functions.php file - not sure if that's right? This is now displaying the coaches post on every page of the site. Ideally I'd like to call the 'coaches' posts only into a specific section on the about us page - halfway down the page under some intro text etc.

The code I provided is just an example using the 'beans_fixed_wrap[_main]_prepend_markup' hook but you can add it anywhere on the page. Pretty much all markup have dynamic action hooks firing around it as follow:

  • {$markup_id}_before_markup, fires before the opening markup.
  • {$markup_id}_prepend_markup, fires after the opening markup (not available for selfclosed markup).
  • {$markup_id}_append_markup, fires before the closing markup (not available for selfclosed markup).
  • {$markup_id}_after_markup, fires after the closing markup.

We have made it simple to find Markup IDs, you’ll need to first enable Beans development mode in your WordPress Admin->Appearance->Settings. Once the development mode is enabled, the Markup ID’s are output in a data-markup-id tag in the front-end, so you just have to inspect the page using your browser inspect and all markup ids will be displayed.

Since you want to re-use it in multiple places, I think the best is to leave the function (aka example_coach_loop()) in your functions.php and add the add_action... part in your coaches and about us template files. If you don't want to attach it using an action but rather add it in your custom HTML, you may simply call your example_coach_loop() πŸ™‚

Regarding your Custom Post Type template file, this documentation my help you. All you need to know is that in any template file you always have beans_load_document() which essentially display the document. From there, you would add all your modification above.

Thanks,


Hi Thierry

I'm trying and failing to add the coaches_loop to my html. I've added the code you gave me to my functions.php file and removed the add so it begins with the function (I replaced example_coach_loop with 'coaches_loop' in all cases as that is the name I gave to my custom post type. On the 'about' page I used

<?php coaches_loop(); ?>

Here's the error I get:

Fatal error: Call to undefined function coaches_loop() in /nfs/c05/h01/mnt/74707/domains/jasonsaunders.co.nz/html/test/wp-test/wp-content/themes/tm-beans-child/about-template.php on line 13

Any obvious error I might have made?

Thanks again. Jason


This message says that your function is not available so you must have a typo mistake or unsuccessfully added your function in your function.php which should look like:

function coaches_loop() {
  // Your code...
}

Typo - quite right.

Hope you're week is going well.

All coming along nicely so far.

I did notice the custom hero section tweak that I did to get the hero section displaying for posts as well as pages has created a big blank space on my events page - is there a better way to do this?

What I'd done previously is remove the 'IF' section before the content.

Cheers Jason


Hi Thierry

The custom post single page that I created doesn't have a sidebar. How would I create a custom sidebar specific to the coaches section? ie links to the other coach posts.

Many thanks, Jason


Hey Jason,

In your example_hero() function (name given in the first code example), you can add and if ( statement ) return; which will prevent it from displaying the content on specific "pages". Here is an example:

add_action( 'beans_header_after_markup', 'example_hero' );

function example_hero() {

 // Example: if condition is met, stop here and don't run the rest of this function.
  if ( is_page( 'event-page' ) )
      return;

    // All the code displaying the here....

}

Regarding the custom sidebar, please refer to this discussion. Feel free to participate to that discussion if you have questions.

Thanks,

  • 1
  • 2

Write a reply

Login or register to write a reply, it's free!