Badging (for PDPs)
Badging (for PDPs)
Set up your triggers
Start by finding a way to target exactly the element that you want to replace.
In this case, you can use its Id #shopify-featured-image
:
Since badging is currently only available in PDP pages, your Simple triggers page will already include a product
page type.
Make sure you add that element on the Simple triggers page, in the Polling for section. If you have any questions about triggers, there’s a section on them here.
Define your sample payload
The Placement schema already includes the message
and an imageUrl
fields, one of which will need to be defined for a campaign to run.
Note
You can add custom fields to your schema to give merchandisers additional control over the Placement’s design. For more details, see Schemas. |
You can set your sample payload by filling out the fields on the Placement Content page:
The sample payload will look like this:
{
"message": "HOT RIGHT NOW!",
"imageUrl": "https://image.flaticon.com/icons/png/512/91/91381.png"
}
Note
If you’re using Qubit CLI to develop locally, you’ll need to save the Placement in the UI and pull its new structure to your local project at this point. |
Write some code!
This is what your placement.js file will look like at first:
module.exports = function renderPlacement ({ content, onImpression, onClickthrough }) {
if (content) {
} else {
}
}
To start with, you have to import preact and @qubit/utils, a library that offers some helpful tools for manipulating the DOM.
Next, you should use onRemove
and elements
(two other arguments available for us in the renderPlacement
function) which you can read more about in placement.js arguments.
const React = require('preact')
const {
style,
insertBefore,
onEvent,
onEnterViewport,
restoreAll
} = require('@qubit/utils/dom')()
module.exports = function renderPlacement ({
content,
onImpression,
onClickthrough,
onRemove,
elements
}) {
// ...
}
As you can see in the boilerplate code, you will divide our code into two parts, content and no-content. However, there are a couple of things you need to do before getting into that split to avoid creating bias in our test:
// The functions provided by @qubit/utils are all linked to the `restoreAll` function,
// which means that when you remove the Placement on the page with `onRemove` (particularly useful for single-page applications),
// it will clean it up after itself and avoid leaking side effects.
onRemove(restoreAll)
// Appending this element to the same spot on the dom for both control and variant will ensure the test is fair.
// Check out the Impressions and clickthroughs guide in the docs to learn more about this.
const element = document.createElement('div')
insertBefore(target, element)
// Emitting onImpression before branching into control/variant prevents bad splits
onEnterViewport(element, onImpression)
Apart from that, you can destructure the array of elements provided to you for accessing to the element you polled for in the beginning (the banner with Id #shopify-featured-image
).
Note
If you had polled for more elements or global objects, they would also appear in this destructured array in the order they’re being polled for. |
const [target] = elements
So far, our placement.js code looks like this:
const React = require('preact')
const {
style,
insertBefore,
onEvent,
onEnterViewport,
restoreAll
} = require('@qubit/utils/dom')()
module.exports = function renderPlacement ({
content,
onImpression,
onClickthrough,
onRemove,
elements
}) {
onRemove(restoreAll)
const [target] = elements
const element = document.createElement('div')
insertBefore(target, element)
onEnterViewport(element, onImpression)
if (content) {
} else {
}
}
Content
After setting up the Placement code and ensuring that only consistent impression events are being collected, you can have a look at rendering the badge.
// Here you use destructuring to get our content from the `content` object
const { message, imageUrl } = content
// Note that you will use these classNames to style our banner in placement.css
React.render(
<div className='Badge'>
{image && <img className='Badge-image'src={image}>}
{message && <p className='Badge-message'>{message}</p>}
</div>,
// You are rendering this badge inside the target, which is the product container
target
)
Now, all you need to do is give it some styles in placement.css. Don’t worry about importing it, it’s all bundled together when you are serving the Placement.
#shopify-featured-image {
position: relative;
}
.Badge {
position: absolute;
display: grid;
grid-template-columns: 30px 1fr;
top: 80%;
left: 50%;
transform: translateX(-50%);
padding: 10px;
background-color: white;
}
.Badge-image {
margin-right: 13px;
}
.Badge-message {
color: black;
margin: auto;
margin-left: 13px;
}
No content (control)
Due to the fact that you are only tracking onImpression
before checking for content, and are also not tracking clicks, there is no need to do anything for the control.
This makes the else
statement redundant which is why it should be removed.
So this is what the whole placement.js will look like:
const React = require('preact')
const {
style,
insertBefore,
onEvent,
onEnterViewport,
restoreAll
} = require('@qubit/utils/dom')()
module.exports = function renderPlacement ({
content,
onImpression,
onClickthrough,
onRemove,
elements
}) {
onRemove(restoreAll)
const element = document.createElement('div')
insertBefore(target, element)
onEnterViewport(element, onImpression)
const [target] = elements
if (content) {
const { message, imageUrl } = content
React.render(
<div className='Badge'>
{image && <img className='Badge-image'src={image}>}
{message && <p className='Badge-message'>{message}</p>}
</div>,
target
)
}
}
And now your product has a badge!
After you are done, you can publish your Placement and your merchandiser will be able to target it with some campaigns!