PrintJob allows you to create a custom header that will reflect the look and feel of your website, via the HTML area of the Appearance>Header section (either in the Storefront Settings or in the Settings for a particular account).

However, if you uncheck the option on the appearance page ‘Show dynamic menu’. you will need to make your header DYNAMIC. That means, you can have the header show dynamic content, such as ‘Login’ or ‘Logout’ or a count icon over the basket. Also, the PJ system is ‘role based’ which means that different users get different page links.

header_explain2


To utilize these dynamic properties you will need to use javascript in your header that will manipulate your header content according to the data that the PrintJob System provides. Right before your header starts, and within the .header-wrapper div, a javascript object is being injected – it contains all information necessary for dynamic links that depend on the user privileges, their status and contents of their interface.

Here is a complete example of a dynamic header.

<style type="text/css">
    .header-wrapper .contact-bar {
        background-color: #66A931;
        transition: background-color 0.4s ease 0s, transform 0.4s ease 0s, opacity 0.4s ease-in-out 0s;
        line-height: 1em;
        color: #fff;
        font-size: 12px;
        line-height: 13px;
        overflow: auto;
        padding: 10px 0;
    }
    .header-wrapper .logo_container {
        height: 80px;
        text-align: center;
        width: 100%;
        
    }
    .header-wrapper .logo_container img {
        height: 40px;
    }

    .header-wrapper .navbar li {
        display: none;  
    }
    .header-wrapper sup {
        font-size: 50%;
        line-height: 133%;
        position: relative;
        top: -10px;
    }
    .header-wrapper .navbar {
        background-color: navy;
    }
    .header-wrapper .navbar a {
        color: lightblue;
    }
    .header-wrapper .navbar a:hover {
        color: lightcyan;
    }

    .navbar .navbar-toggler div
    {
        display: block;
        width: 33px;
        height: 5px;
        margin-bottom: 5px;
        position: relative;
        background: lightblue;
        border-radius: 3px;
        z-index: 1;
        transform-origin: 4px 0px;
        transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0), background 0.5s cubic-bezier(0.77,0.2,0.05,1.0), opacity 0.55s ease;
    }
    .navbar .navbar-toggler:hover div {
        background: lightcyan;
    }
    .navbar .navbar-toggler div:first-of-type {
        margin-top: 5px;
    }
</style>

<div class="row contact-bar">
    <div class="container">
        <div class="row">
            <div class="col">
                <span><strong>T: </strong>+44 20 8144 2778</span> <span><strong>E: </strong>info@printjob.com</span>            
            </div>
            <div class="col text-right">
                <span id="header-wrapper-login-link">
                    <a class='badge badge-pill badge-secondary' id="login-link" href=""><span class="my-icon"></span> <span class='text'>Login</span></a>
                </span>
            </div>
        </div>
    </div>
</div>
<div class="row">
    <div class="logo_container">
        <span class="logo_helper"></span>
        <br>
        <img src="https://printjob.com/wp-content/uploads/2016/01/printjob-logo-dark.png">
    </div>
</div>
<div class="row" id="header-wrapper-menu">
    <div class="container">
        <nav class="navbar navbar-expand-md">
            <button class="navbar-toggler collapsed" type="button" data-toggle="collapse" data-target="#custom-navbar" aria-controls="custom-navbar" aria-expanded="false" aria-label="Toggle navigation">
                <div></div>
                <div></div>
                <div></div>
            </button>
            <div class="collapse navbar-collapse" id="custom-navbar">
                <ul class="navbar-nav">
                    <li  id="header-wrapper-products-link" class="nav-item">
                        <a  class="nav-link" href="/product/catalogue">Product Catalogue</a>           
                    </li>
                    <li id="header-wrapper-rfq-link" class="nav-item">
                        <a  class="nav-link" href="/Rfq/Manager/create">RFQ</a>                
                    </li>
                </ul>
                <ul class="navbar-nav ml-auto">
                    <li id="header-wrapper-orders-link" class="nav-item">
                        <a class="nav-link"><span class="my-icon"></span></a>                
                    </li>
                    <li id="header-wrapper-quotes-link" class="nav-item">
                        <a title="Quotes" class="nav-link" href="/Rfq/manager/user"><span class="my-icon"></span></a>                    
                    </li>
                    <li id="header-wrapper-users-link" class="nav-item">
                        <a title="Users" class="nav-link" href="/manager/users"><span class="icon-users"></span> Users</a>                    
                    </li>
                    <li id="header-wrapper-addresses-link" class="nav-item">
                        <a title="Addresses" class="nav-link" href="/user/addresses"><span class="icon-addresses"></span> Addresses</a>                    
                    </li>
                    <li id="header-wrapper-designs-link" class="nav-item">
                        <a class="nav-link"><span class="my-icon"></span></a>
                    </li>
                    <li id="header-wrapper-stock-link" class="nav-item">
                        <a class="nav-link"><span class="my-icon"></span></a>
                    </li>
                    <li id="header-wrapper-budget-info" class="nav-item">
                         <a class="nav-link disabled" disabled><span class="my-icon"></span></a>
                    </li>
                    <li id="header-wrapper-profile-link" class="nav-item">
                        <a class="nav-link"><span class="icon-user"></span> Profile</a>                
                    </li>
                    <li id="header-wrapper-basket-link" class="nav-item">
                        <a class="nav-link" title="Shopping Basket" href="/basket/basket"><span class="icon-shopping-cart"></span></a>            
                    </li>
                </ul>
            </div>
        </nav>
    </div>
</div>
<script type="text/javascript">
    //Links
    $('#header-wrapper-rfq-link a').prop('href', pj_header_data.rfq.link);
    $('#header-wrapper-orders-link a').prop('href', pj_header_data.orders.link);
    $('#header-wrapper-quotes-link a').prop('href', pj_header_data.quotes.link);
    $('#header-wrapper-designs-link a').prop('href', pj_header_data.saved_designs.link);
    $('#header-wrapper-profile-link a').prop('href', pj_header_data.profile.link);
    $('#header-wrapper-stock-link a').prop('href', pj_header_data.replenish_stock.link);
    $('#header-wrapper-basket-link a').prop('href', pj_header_data.basket.link);
    $('#header-wrapper-users-link a').prop('href', pj_header_data.users.link);
    $('#header-wrapper-addresses-link a').prop('href', pj_header_data.addresses.link);
    $('#header-wrapper-login-link a').prop('href', pj_header_data.login.link);

    //Logout button functionality
    if (pj_header_data.login.state == 1) {
        $("#header-wrapper-login-link a .text").text('Logout');
    }

    //Show links
    if (pj_header_data.products.show == 1) {
        $('#header-wrapper-products-link').css({'display': 'inline-block'});
    }
    if (pj_header_data.rfq.show == 1) {
        $('#header-wrapper-rfq-link').css({'display': 'inline-block'});
    }
    if (pj_header_data.basket.show == 1) {
        $('#header-wrapper-basket-link').css({'display': 'inline-block'});
    }
    if (pj_header_data.orders.show == 1) {
        $('#header-wrapper-orders-link').css({'display': 'inline-block'});
    }
    if (pj_header_data.quotes.show == 1) {
        $('#header-wrapper-quotes-link').css({'display': 'inline-block'});
    }
    if (pj_header_data.saved_designs.show == 1) {
        $('#header-wrapper-designs-link').css({'display': 'inline-block'});
    }
    if (pj_header_data.profile.show == 1) {
        $('#header-wrapper-profile-link').css({'display': 'inline-block'});
    }
    if (pj_header_data.replenish_stock.show == 1) {
        $('#header-wrapper-stock-link').css({'display': 'inline-block'});
    }
    if (pj_header_data.users.show == 1) {
        $('#header-wrapper-users-link').css({'display': 'inline-block'});
    }
    if (pj_header_data.addresses.show == 1) {
        $('#header-wrapper-addresses-link').css({'display': 'inline-block'});
    }

    //Budget functionality
    if (pj_header_data.budgets.show == 1) {

        function objToString(obj) {
            var str = '';
            for (var p in obj) {
                if (obj.hasOwnProperty(p)) {
                    str += p + ': ' + obj[p] + '\n';
                }
            }
            return str;
        }

        $('#header-wrapper-budget-info').css({'display': 'inline-block'});
        $('#header-wrapper-budget-info a').append(pj_header_data.budgets.total_value);
        $('#header-wrapper-budget-info').attr('title', objToString(pj_header_data.budgets.budgets));
    }

    //Activate links
    if (pj_header_data.products.active == 1) {
        $('#header-wrapper-products-link').addClass('active');
    }
    if (pj_header_data.rfq.active == 1) {
        $('#header-wrapper-rfq-link').addClass('active');
    }
    if (pj_header_data.orders.active == 1) {
        $('#header-wrapper-orders-link').addClass('active');
    }
    if (pj_header_data.quotes.active == 1) {
        $('#header-wrapper-quotes-link').addClass('active');
    }
    if (pj_header_data.saved_designs.active == 1) {
        $('#header-wrapper-designs-link').addClass('active');
    }
    if (pj_header_data.basket.active == 1) {
        $('#header-wrapper-basket-link').addClass('active');
    }
    if (pj_header_data.profile.active == 1) {
        $('#header-wrapper-profile-link').addClass('active');
    }
    if (pj_header_data.replenish_stock.active == 1) {
        $('#header-wrapper-stock-link').addClass('active');
    }
    if (pj_header_data.users.active == 1) {
        $('#header-wrapper-users-link').addClass('active');
    }
    if (pj_header_data.addresses.active == 1) {
        $('#header-wrapper-addresses-link').addClass('active');
    }

    //Counters
    $('#header-wrapper-basket-link a').append('<sup class="badge badge-info badge-pill">' + pj_header_data.basket.count + '</sup>');
    if (pj_header_data.orders.count > 0) {
        $('#header-wrapper-orders-link a').append('<sup class="badge badge-info badge-pill">' + pj_header_data.orders.count + '</sup>');
    }
    if (pj_header_data.quotes.count > 0) {
        $('#header-wrapper-quotes-link a').append('<sup class="badge badge-info badge-pill">' + pj_header_data.quotes.count + '</sup>');
    }
    if (pj_header_data.saved_designs.count > 0) {
        $('#header-wrapper-designs-link a').append('<sup class="badge badge-info badge-pill">' + pj_header_data.saved_designs.count + '</sup>');
    }

    //Icons 
    $('#header-wrapper-orders-link a').prepend('<span class="' + pj_header_data.orders.icon + '"></span>');
    $('#header-wrapper-quotes-link .my-icon').addClass(pj_header_data.quotes.icon);
    $('#header-wrapper-designs-link .my-icon').addClass(pj_header_data.saved_designs.icon);
    $('#header-wrapper-stock-info .my-icon').addClass(pj_header_data.replenish_stock.icon);
    $('#header-wrapper-budget-info .my-icon').addClass(pj_header_data.budgets.icon);
    $('#header-wrapper-profile-link .my-icon').addClass(pj_header_data.profile.icon);
    $('#header-wrapper-basket-link .my-icon').addClass(pj_header_data.basket.icon);
    $('#login-link .my-icon').addClass(pj_header_data.login.icon);
</script>

 

Learning from this example

The following section explains some of how this code is put together.

 

Its at this point that your IT expert should step in.

 

PrintJob Header Data Object

It’s important you are aware of these objects – they can be found by looking at the “source” of a storefront page when the default <system> header is enabled. You can refer to these objects in your custom header code.

Here is an example of such an object:

var pj_header_data = {
  products: {
    "show":1,
    "active":1,
    "link":"/product/catalogue",
    "icon":"icon-products"
  },
  rfq: {
    "show":0,
    "active":0,
    "link":"/Rfq/manager/create",
    "icon":"icon-quotes"
  },
  basket: {
    "show":1,
    "active":0,
    "count":2,
    "link":"/basket/basket",
    "icon":"icon-shopping-cart"
  },
  orders: {
    "show":1,
    "active":0,
    "count":0,
    "link":"/Order/manager/user",
    "icon":"icon-orders"
  },
  quotes: {
    "show":1,
    "active":0,
    "count":0,
    "link":"/Rfq/manager/user",
    "icon":"icon-quotes"
  },
  saved_designs: {
    "show":1,
    "active":0,
    "count":1,
    "link":"/user/savedForLater",
    "icon":"fas fa-save"
  },
  users: {
    "show":1,
    "active":0,
    "link":"/manager/users",
    "icon":"icon-users"
  },
  addresses: {
    "show":1,
    "active":0,
    "link":"/user/addresses",
    "icon":"icon-addresses"
  },
  replenish_stock: {
    "show":0,
    "active":0,
    "link":"/product/replenishment",
    "icon":"icon-"
  },
  profile: {
    "show":1,
    "active":0,
    "link":"/user/myProfile",
    "icon":"icon-user"
  },
  budgets: {
    "show":0,
    "active":0,
    "total_value":"£552.50",
    "icon":"icon-budget",
    "budgets": {
      "Purchase Budget":"£432.50",
      "Special":"120.00"
    }
  },
  login: {
    "link":"/site/logout",
    "state":1,
    "icon":"icon-logout"
  },
  language: {
    "language_code":"en_gb",
  }
}

WARNING: The above is only an example for you to study. Do NOT include the above in your header as it is automatically generated, based on who is logged in and what privileges they have. If you include the above you will override real values with static ones!

Description of the attributes:

link – appears in every object and describes a URI component (Uniform Resource Identifier) that should be used to reach a required page within the system.
show – available on every object, except for login and basket (those appear always). If its value is 0 it means that link should not be visible i.e. that user will not be able to use it due to their privileges or not being logged in etc.
active – appears on every object except for login. If the value is 1 it means that user is on a page that corresponds to the link. This value may be used to highlight a current page in your item.
count – present on several objects, namely basket, quotes, orders and saved_designs. If its present it will show how many items a corresponding entity contains i.e. 4 items in the basket or 2 unseen quotes.
login – this object is special, it has a unique property `state` which translates to 1 – the user is logged in, 0 – the user is not logged in.

We also have a special object called ‘language‘. It has only one value – ‘language_code’ which shows which language your user is using in the system. This will be helpful in providing localized content if your system runs multiple languages.

Now… about the example code:

Styles

The first section is responsible for all the styles that manage the aesthetic look of the header.

<style type="text/css">
  .header-wrapper #top-header #et-secondary-menu {
    float: right;
  } 
  .header-wrapper #top-header #et-info-phone::before {
    content: "T:";
    margin-right: 4px;
  }
  [...]
</style>

Please note, that every style starts with

.header-wrapper

class, which ensures that whatever names of classes or selectors you are going to use you are not going interfere with the rest of the site. A notable recurring example is using `p` selector to change the text colour in the header. E.g.:

p {color: white; } // BAD: this will make text white in the whole of the page, not only the header, and some text inside PrintJob will become white on white, while
.header-wrapper p { color: white} // GOOD: will not affect anything outside of the header

HTML

<div id="top-header">
  [...]
</div>

Its up to you what you are going to put in here. All naming conventions are allowed. The entirety of the HTML you going to enter here will be wrapped by a div with `header-wrapper` class and as long as your styles are correctly named, you should be able to achieve your desired aesthetic result.

One thing to bear in mind is that if you want to use dynamic header functionalities (i.e. your own menu) then you have to be giving specific elements (like links) unique ids or classes so you can call them from the javascript section and enable automation.

In our examples we chose to use list elements as menu defining elements and gave them all unique IDs, like in the example below:

<li id="header-wrapper-products-link"><a href='/product/catalogue'>Product Catalogue</a></li>
[...]
<li id="header-wrapper-orders-link"><a href='/Order/manager/user' title="Orders"><span class="my-icon icon-orders"></span></a></li>
<li id="header-wrapper-quotes-link"><a><span class="my-icon icon-quotes"></span></a></li>
[...]
<li id="header-wrapper-budget-info"><span class="my-icon"></span></li>
<li id="header-wrapper-basket-link"><a><span class="my-icon"></span> Basket</a></li>

The above code shows several different approaches to building your links.

As you might have noticed, some link selectors `a` do not have the `href` property (which is normally required), and some do. This is to illustrate two possible approaches. One is to simply enter values manually (hardcode) and another is to allow adding of this property dynamically with javascript. Hardcoding is easier and less resource intensive. Dynamic attribution is more complex but more resilient i.e. if links were ever to change (that will not happen often if at all) then your header would still work without intervention.

You can include PrintJob supplied icons by hardcoding them into a ‘span’ element or use javascript (as described in a separate section below) to apply icons in relevant places.

Another thing to notice is that we opted to use a text inside the ‘basket’ link and a title in ‘orders’ link.

It is up to you how you build your header – our example aims to show you some of the different options you have.

Javascript

<script type="text/javascript">
[...]
</script>

This section is optional – if you are using the system supplied dynamic header you wont need it.

This section is responsible for six functionalities:

  1. Setting link locations on your buttons
  2. Modifying text on the login/logout button, depending on whether the user is logged in or not
  3. Showing or hiding buttons depending on users privileges
  4. Budget functionality
  5. Adding active class to links that are active (user is on a page that link is pointing to) (optional)
  6. Displaying counters on relevant links (optional)
  7. Setting icons for links (optional)

All the information required to perform those tasks is available as a javascript object called ‘pj_header_data’ on every PrintJob page as described in a section above.

Here is an explanation of specific parts of the javascript.

1. Links association:
  $('#header-wrapper-rfq-link a').prop('href', pj_header_data.rfq.link);

This and similar lines are populating `href` attributes of link elements with values taken from the PrintJob system. You could hardcode those into your header but using dynamic allocation ensures that menu in your header will stay operational even if links will change for some reason, however unlikely that may be. If you prefer to hard-code the links then this whole section is optional.

2. Login button functionality

if (pj_header_data.login.state == 1) {
$(“#header-wrapper-login-link a .text”).text(‘Logout’);
}

If user is logged in (login.stat == 1) we change text to Logout.

3. Hiding and showing specific links:
  if (pj_header_data.orders.show == 1) {
    $('#header-wrapper-orders-link').css({'display':'inline-block'});   
  }

Each link has a property ‘show’ which determines if it should be shown so in our example we are using an ‘if’ conditional to determine if we want to make it visible (in our example all links that are transitional are hidden by default).

Two notable exceptions are Basket and Products link – although it has a ‘show’ flag, that flag is always 1, because both guests and users can see basket and product catalogue.

4. Budget functionality
  if (pj_header_data.budgets.show == 1) {
  
    function objToString (obj) {
      var str = '';
      for (var p in obj) {
          if (obj.hasOwnProperty(p)) {
              str += p + ': ' + obj[p] + '\n';
          }
      }
      return str;
    }
  
    $('#header-wrapper-budget-info').css({'display':'inline-block'});
    $('#header-wrapper-budget-info').append(pj_header_data.budgets.total_value);
    $('#header-wrapper-budget-info').attr('title', objToString(pj_header_data.budgets.budgets));
  }

This section of javascript is responsible for displaying and formatting the budgets information icon.

This icon is not a link, there is no page where detailed budget information is displayed for a user. Instead, all information is packed into this icon and its title attribute. Firstly, we only do all the formatting if the icon is supposed to be showing (i.e. if admin has activate the budgets feature for this user). If so, we make it visible and then we add the value of ‘total_value’ parameter after the icon (append line). Then we create a ‘title’ attribute for our budget icon with the stringified content of ‘budgets’ model (title line and objToString function).

Of course, you can choose to show it differently, we are illustrating how to achieve the same look as on the original PrintJob menu.

5. Activating links:
  if (pj_header_data.products.active == 1) {
    $('#header-wrapper-products-link').addClass('active');
  }

Each link has a property ‘active’ which take on value 1 when a user is on the page associated with the link. We use the same style ‘if’ conditional to determine if we should add ‘active’ class to the link. You can name the class however you wish and style it in ‘styles’ section of your header.

6. Displaying counters:
  $('#header-wrapper-basket-link a').append(' <span class="header-wrapper-counts">' + pj_header_data.basket.count + '</span>');
  if (pj_header_data.orders.count > 0) {
    $('#header-wrapper-orders-link a').append(' <span class="header-wrapper-counts">' + pj_header_data.orders.count + '</span>');
  }

Because in our example we always show the basket link, we also chose to show basket counter all the time, that is why there is no conditional in our example. In our code, we are appending a ‘span’ to basket link that is styled by ‘header-wrapper-counts’ class. The result is a coloured circle with a white number inside.

In case of the Orders counter, we only show it when there is at least one unseen order (just like in default PrintJob menu). That is why there is a conditional encapsulating append code.

7. Adding icons:
  $('#header-wrapper-basket-link .my-icon').addClass(pj_header_data.basket.icon);
  $('#login-link .my-icon').addClass(pj_header_data.login.icon);

You can add your own icons in HTML without using any of the PrintJob icons. In such case feel free to ignore this section. Otherwise, if you wish to use PrintJob supplied icons, every link has an ‘icon’ property which specifies a name of the class that needs to be added to a span element to render an icon corresponding with the link. You can either hard code it or use the javascript similar to the above to accomplish the same goal.

Comments are closed.