1 Create QR Codes of Web Pages Shared by Randy Aufrecht, ONE&ALL Church 2 years ago 12.0 Web Intermediate QR Codes have been around for quite a long time, but since the pandemic, they have become common place. They are used at restaurants for contactless menus and even the Superbowl ads. QR codes give your users an easy way to get to your website using their phones without having to type the url into their mobile browser. Wouldn't it be nice to have a way to create those QR codes on the fly and even let your staff to create them and then be able to see how the interactions on those perform. The Details This system uses a workflow to create a shortlink and attach tracking information to the shortlink and has changes to the short link page and a special shortlink page used by your staff to view their content and interactions. Page Short Link Entity For tracking purposes we will add 2 attributes to the Page Short Link Entity. A Ministry Attribute, a defined value holding the names of your ministries who can request short links/qr codes and Requester Attribute, a Person Entity holding who made the request. Note: We use the Ministry Defined Type throughout our website so we can be consistent with all aspects of our website in regards to content. Visit System Settings...Entity Attributes Change the Entity Type Filter to: Page Short Link Click the + to add an attribute to the Page Short Link Entity Add Ministry Attribute: Name: Ministry Active: checked Field Type: Defined Value Defined Type: Ministries Add Requester Attribute: Name: Requester Active: checked Field Type: Person Workflow The workflow is used to create short links and/or connet ministries and requesters to existing short links. Import the Workflow attached into your Rock Instance. Visit Power Tools...Workflow Import/Export On the right, select the downloaded file, choose the category and select Test. This will verify that everything will import. After running the test and you determine it is safe, uncheck the test and import the workflow. Edit the imported Workflow Change the Attribute Ministry with your Defined Type On the action: Create Short Link in Activity: Create Short Link, change the Site to your Public Site We only allow short link creation to our public website. On the action: Get created Entity in Activity: Create Short Link, change the SiteId == 9 to your public SiteId On the action: Set URL in Activity: Redirect-Close, change the last line to be the Page "Page Short Link Detail" you create below /page/1905?ShortLinkId={{- slid -}} Pages to View Short Links and Details Create 2 pages to help manage your Shortlinks that have the new attributes attached to them. The first page uses a table formatting plugin named "Datatables". Find more information at datatables.net on usage. Add Page: Short Link Creation: Page Basic Settings: Layout: Left Sidebar Page Advanced Settings: Header Content: <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.24/css/jquery.dataTables.css"> <script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.js"></script> add Block to Main: Page Parameter Filter Block Title Text: Ministry Show Block Title: checked Add Filters : Name: Ministry Field Type: Defined Value Defined Type: Ministries or whatever Defined Type you use add Block to Main: Dynamic Data Block Properties...Basic Settings: WebRequest checked Query:select psl.Id , psl.Token , psl.Url , p.NickName + ' ' + p.LastName as Requester , p.Id as RequesterId , dv.[Value] as Ministry from PageShortLink psl left join AttributeValue req on req.EntityId = psl.Id and req.AttributeId = 25576 -- Attribute Id of Requester Attribute on Page Short Link Attribute LEFT JOIN PersonAlias pa ON pa.Guid = TRY_CAST(req.[Value] AS uniqueidentifier) LEFT JOIN Person p ON p.Id = pa.PersonId JOIN AttributeValue min ON min.EntityId = psl.Id and min.AttributeId = 25575 -- Attribute Id of Ministry Attribute on Page Short Link Attribute JOIN DefinedValue dv ON min.Value = cast(dv.Guid as varchar(50)) WHERE (@Ministry = '' or min.Value = @Ministry) ORDER BY psl.Token Parameters: Ministry=; Customize Results with Lava: checked Formatted Output: <table id="ShortLink" class="display"> <thead> <tr> <th>Token</th><th>Ministry</th><th>Requester</th><th>Url</th><th>Details</th><th>Download QR</th> </tr> </thead> <tbody> {% for row in rows %} <tr> <td>{{ row.Token }}</td> <td>{{ row.Ministry }}</td> <td><a href="/Person/{{ row.RequesterId}}">{{ row.Requester }}</a></td> <td>{{ row.Url }}</td> <td class="text-center"><a href="/page/1905?ShortLinkId={{ row.Id }}"><i class="fa fa-file-alt"></i></a></td> {% capture qrUrl %}https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=www.oneandall.church/{{ row.Token | EscapeDataString }}{% endcapture %} <td class="text-center"><a href="{{ qrUrl }}" download="{{ row.Token}}"><i class="fa fa-download"></i></a></td> </tr> {% endfor %} </tbody> </table> <script> $(document).ready( function () { $('#ShortLink').DataTable({"paging": false}); } ); </script> Add Block to Sidebar: HTML Content Code: <a href="/WorkflowEntry/398" class="btn btn-primary">Create Short Link</a> Change the Workflow Id to the Workflow ID created above Add Page: Page Short Link Detail Page Basic Settings: Layout: Left Sidebar Add Block to Main: Dynamic Chart Chart Height: 200 Query Params: ShortLinkId= SQL: SELECT asd.DATE AS DATETIME , count(i.Id) AS YValue , 'Interactions' AS SeriesName FROM Interaction i INNER JOIN InteractionComponent ic ON ic.Id = i.InteractionComponentId INNER JOIN AnalyticsSourceDate asd ON asd.DateKey = i.InteractionDateKey INNER JOIN InteractionSession sess ON sess.id = i.InteractionSessionId INNER JOIN InteractionDeviceType idt ON idt.Id = sess.DeviceTypeId WHERE ic.EntityId = @ShortLinkId AND ic.InteractionChannelId = 10 AND NOT (idt.Name LIKE '%bot%') GROUP BY asd.DATE Column Width: 12 Chart Style: Rock Show Legend: No Chart Type: Line Add Block to Main: Short Link Click List Add Block to Sidebar: HTML Content HTML: {% pageshortlink id:'{{ PageParameter.ShortlinkId }}' iterator:'items' securityenabled:'false' %} {% for item in items %} <div class="text-center"> {% capture qrUrl %}https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=https://www.oneandall.church/{{ item.Token | EscapeDataString }}{% endcapture %} <img src="qrUrl"> <a class="btn btn-primary mt-3" href="{{ qrUrl }}" download="{{ item.Token}}" target="_blank"><i class="fa fa-download"></i> Download QR Code</a> <h3>www.oneandall.church/{{ item.Token }}</h3> <p>Redirects to: {{ item.Url }}</p> </div> {% endfor %} {% endpageshortlink %} Pulling it all together To give our staff the ability to create their own short links and qr codes, we have created a custom footer on our website. This is only available to a select group of people who are given access to the Block itself. Add Block to footer of site: HTML Content Change view permissions of block to allow any security group you would like to see the block and deny "All Users" Edit HTML, NOTE: You will need to edit the code to fit the style of your website: {% assign PageId = 'Global' | Page:'Id' %} {% assign EditAccess = PageId | HasRightsTo:'Edit','Rock.Model.Page' %} <div class="container"> {% assign url = 'Global' | Page:'Url' | EscapeDataString %} <a class="oa-btn oa-btn-primary" style="border-color:#000;" href="{{ 'Global' | Attribute:'InternalApplicationRoot' }}WorkflowEntry/###?Url={{ url }}" target="_blank">Short Link</a> {% if EditAccess == true %} <a accesskey="e" class="oa-btn oa-btn-primary" style="border-color:#000;" href="{{ 'Global' | Attribute:'InternalApplicationRoot' }}pages?Page={{ PageId }}" target="_blank">Edit Page</a> {% endif %} </div> NOTE: There are 2 buttons in this block. Button to Create the Short Link/QR Codes (starts Workflow created in this recipe Replace ### with the Workflow Type Id) Button for those who have edit rights to the page so they can easily get to the page if they need to update it with the Page editing layout Update the Link Detail page found in CMS Configuration...Short Links and can be found at (/admin/cms/short-links/1) Add to Header Content of Page: <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js" integrity="sha512-TW5s0IT/IppJtu76UbysrBH9Hy/5X41OTAbQuffZFU6lQ1rdcLHzpU5BzVvr/YFykoiMYZVWlr/PX1mDcfM9Qg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment"></script> <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-trendline"></script> <script> Chart.defaults.elements.line.tension = 0.4; Chart.defaults.plugins.legend.position = 'right'; Chart.defaults.plugins.legend.align = 'start'; Chart.defaults.interaction.mode = 'index'; </script> Add 3 Blocks to the Main Zone between Short Link Detail and Short Link Click List: Entity Attribute Values Dynamic Data, Rock v13.4 has a fix and allows for a Dynamic Chart block instead and you can ignore step 1 above. HTML Content Configure Entity Attribute Values Block: Name: Attributes Entity Type: Page Short Link Configure Dynamic Data Block: Query: select asd.Date as DateTime , count(i.Id) as YValue , 'Interactions' as SeriesName from Interaction i inner join InteractionComponent ic on ic.Id = i.InteractionComponentId inner join AnalyticsSourceDate asd on asd.DateKey = i.InteractionDateKey inner join InteractionSession sess ON sess.id = i.InteractionSessionId inner join InteractionDeviceType idt ON idt.Id = sess.DeviceTypeId where ic.EntityId = @ShortLinkId and ic.InteractionChannelId = 10 and not (idt.Name like '%bot%') group by asd.Date order by asd.[Date] Parameters: ShortLinkId= Formatted Output: <div class="col-md-8"> <div class="chart-container" style="position:relative; width:100%; height:300px; margin-bottom:50px;"> <h3>Interactions</h3> <canvas id="newGiverChart"></canvas> </div> </div> <script> var ctx = document.getElementById("newGiverChart").getContext('2d'); var config = { type: 'line', data: { labels: [{%-for row in rows -%}"{{row.DateTime | Date:'MM/dd/yy' }}"{%- if forloop.last-%}{%-else-%},{%-endif-%}{%-endfor-%}], datasets: [ {%- for row in rows -%} {%- if forloop.first -%} { label: 'Interactions', {%- capture color -%}{%- cycle 'bgc':'#FFC905','#4054D9','#8DC63F','#652D90','#00ADEE','#F15A29','#FF6675','#FFB1BB' -%}{%- endcapture -%} borderColor: "{{color | UnescapeDataString}}", backgroundColor: "{{color | UnescapeDataString}}", borderWidth: 1, data: [ {%- endif -%} {x:'{{row.DateTime | Date:'MM/dd/yy'}}', y:{{row.YValue}} }, {%- if forloop.last -%} ] }, {%- endif -%} {%- endfor-%} ] }, options: { responsive: true, maintainAspectRatio: false, animation: { duration: 2500, }, plugins: { tooltip: { mode: 'index' }, legend: { display: false } }, scales: { x: { type: 'time', time: { unit:'day', displayFormats: { month: 'MM/YY', week: 'MM/DD/YY' }, tooltipFormat: 'MM/DD/YY' } }, y: { beginAtZero: true } } } } var newgiverLine = new Chart(ctx, config); </script> Configure HTML Content: {% pageshortlink id:'{{ PageParameter.ShortlinkId }}' iterator:'items' securityenabled:'false' %} {% for item in items %} {% capture qrUrl %}https://api.qrserver.com/v1/create-qr-code/?size=300x300&data={{'Global' | Attribute:'PublicApplicationRoot'}}{{ item.Token | EscapeDataString }}{% endcapture %} <div class="text-center"> <h3>{{ item.Token }}</h3> <p>{{ item.Url }}</p> <img src="{{ qrUrl }}"><br> <a class="btn btn-primary mt-3" href="{{ qrUrl }}" download="{{ item.Token}}" target="_blank"><i class="fa fa-download"></i> Download QR Code</a> </div> {% endfor %} {% endpageshortlink %} If you are on version 13.4, you can replace the Dynamic Data block with a Dynamic Chart block similar to the one created on the Page Short Link Detail Page earlier. A bug prevents the Dynamic Chart from using a pageparameter in the page route. Download File