Scott Sawyer Consulting - We Build Websites That Work https://test.scottsawyerconsulting.com/ en Starting a Business https://test.scottsawyerconsulting.com/blog/Starting-Business <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--title--blog--rss.html.twig * field--node--title--blog.html.twig x field--node--title.html.twig * field--node--blog.html.twig * field--title.html.twig * field--string.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <span class="field-wrapper">Starting a Business</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--uid--blog--rss.html.twig * field--node--uid--blog.html.twig x field--node--uid.html.twig * field--node--blog.html.twig * field--uid.html.twig * field--entity-reference.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <span class="field-wrapper"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'username' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> <span lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="">admin</span> <!-- END OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> </span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--created--blog--rss.html.twig * field--node--created--blog.html.twig x field--node--created.html.twig * field--node--blog.html.twig * field--created.html.twig * field--created.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <span class="field-wrapper">Wed, 10/23/2019 - 23:33</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'links__node' --> <!-- FILE NAME SUGGESTIONS: * links--node.html.twig x links.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--body--blog--rss.html.twig * field--node--body--blog.html.twig * field--node--body.html.twig * field--node--blog.html.twig * field--body.html.twig * field--text-with-summary.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper body field field--name-body field--type-text-with-summary field--label-hidden field__items"> <div class="field__item"> <p>I started my current consulting business about 14 years ago.  Since then, I have enjoyed the privilege of working with businesses and non-profits of about every kind.  I been inspired by many of the passionate people who started those businesses.  In that time, I've had several ideas for different businesses, but due to the time committed to consulting, they have all died on the vine.  I just did not have the bandwidth to invest in these ideas in the way it takes to be successful.  Well, now I have a business idea that I think I can start with an absolute minimum of commitment, at least to get it launched.</p> <h2>So, what is the big idea?</h2> <p>At this time, I am not ready to share the idea. It stems from an idea that I had several years ago ( like 10 years ), but not really the same.  It's not so much a technology company, though technology will play a major role.  The previous idea never got off the ground, really.  There were too many pieces, and it became clear that I was going to need a lot more money than what I had planned.  This time around, I plan to simplify tremendously.</p> <p>I think it's enough to say that it's a consumer retail business.  It'll be mostly online, though I hope I can get some product into retailers.  For the most part, I plan to drop ship from the supplier.  I'll purchase a small inventory for trunk sales and promotion.  But the primary idea for this business is that it should be a side hustle, and mostly work without a lot of attention.  I don't plan to quit consulting, but if I can make some money, while participating in an activity I love, then I'll consider it a success.</p> <h2>Then why even bring it up now?</h2> <p>The purpose of this post ( and hopefully subsequent posts ), is to document the process of launching this business.  I was to expose some of the gory details of what it takes to launch this business.  Since I am so early in the process, I think this is an adequate time to start recording my thoughts.</p> <h2>Where things are right now?</h2> <p>Well, not too far.</p> <ul><li>I have a logo, thanks to my brother, Rick. </li> <li>I think I've found a supplier. </li> <li>I have a pretty good idea about how I want to market.  </li> <li>I purchased a domain name, though the one I want is on back order.</li> </ul><p>That last one I am a bit bummed about.  I actually owned the domain at one time, back when the original idea for this company was started.  But after sitting on it for a couple of years and realizing it was never going to happen, I let the domain expire.  I have relatively high hopes that I will be able to regain ownership of the domain.  It's currently redirecting to some Asian language site, it appears to be spam, so I don't think it's very valuable to the current owner.  Unfortunately, there is a chance they just purchased the domain in hopes of gouging whomever comes along that wants the domain.  I wouldn't imagine it would be very desirable on the open market, but the cost to the current owner for holding out is not very high.  I have a very limited amount I am willing to spend to get it, so if they aren't willing to negotiate, I may be out of luck.  </p> <p>For the record, I purchased a back order from GoDaddy, and I enlisted their brokerage service.  My budget is only $200 + commission ( 20% ). If that doesn't get the domain name, I did purchase a backup, but it's not as good.</p> <h2>What's next?</h2> <p>Normally, you should start a business by creating a business plan, marketing plan, spend a bunch of time with an attorney and an accountant.  I'm not going to do that.  </p> <p>I am starting by setting up an account with the supplier and building the ecommerce platform.  Partially because that is what I know best.  Partially because I don't want to spend a bunch of money on the front-end.</p> <p>Don't get me wrong, a retail business requires a fair amount of set up. I'll need to collect sales taxes, so there will certainly be plenty of work for legal and accounting.</p> <p>My initial goal is to get this business off the ground January 1, 2020.  And by "off the ground" I want to have the store online, and some inventory in hand.  All of the legal and accounting stuff set up. I want to sell my first product on Jan 1.</p> <p>I think that is enough for now.  I will do my best to keep this blog updated, though I tend to be terrible about that.  I want this blog to tell the story of the business, and maybe offer some assistance for other people who have an idea and want to start their business.</p> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> Thu, 24 Oct 2019 03:33:55 +0000 admin 130 at https://test.scottsawyerconsulting.com Creating links to ECK Entities in Twig https://test.scottsawyerconsulting.com/blog/Creating-links-ECK-Entities-Twig <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--title--blog--rss.html.twig * field--node--title--blog.html.twig x field--node--title.html.twig * field--node--blog.html.twig * field--title.html.twig * field--string.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <span class="field-wrapper">Creating links to ECK Entities in Twig</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--uid--blog--rss.html.twig * field--node--uid--blog.html.twig x field--node--uid.html.twig * field--node--blog.html.twig * field--uid.html.twig * field--entity-reference.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <span class="field-wrapper"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'username' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> <span lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="">admin</span> <!-- END OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> </span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--created--blog--rss.html.twig * field--node--created--blog.html.twig x field--node--created.html.twig * field--node--blog.html.twig * field--created.html.twig * field--created.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <span class="field-wrapper">Sun, 04/07/2019 - 02:16</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'links__node' --> <!-- FILE NAME SUGGESTIONS: * links--node.html.twig x links.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--body--blog--rss.html.twig * field--node--body--blog.html.twig * field--node--body.html.twig * field--node--blog.html.twig * field--body.html.twig * field--text-with-summary.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper body field field--name-body field--type-text-with-summary field--label-hidden field__items"> <div class="field__item"> <p>This post is mostly so I don't forget, as it took several hours to figure out.</p> <p>Recently, I needed to create some links in a twig templates to various ECK ( Entity Construction Kit ) entity types, mostly to Add, View, and Edit.  Now, it's not really a good idea to try building the paths manually, since the paths may change ( if I update the pathauto patterns or something ).  Routes are much more stable.</p> <p>In Twig, there are two main functions for generating links, link() and path().  Link creates an absolute URL, while path ( wait for it ) creates a path or relative URL.</p> <p>ECK is sort of a special case, because routes are dynamic, since they can't exist until entities and bundles are created.  And as far as I can tell, they aren't well documented.  I figured most of this out by digging through the repo.</p> <p>Let's say I have an entity type, Cool Entity ( machine name: cool_entity ) and a bundle, Awesome Stuff ( machine name: awesome_stuff ).</p> <p>Since in this case, I want relative URLs to View existing Awesome Stuff, edit an existing Awesome Stuff entry, and add new Awesome Stuff ( because I love Awesome Stuff ), I want to use the path() function.</p> <p>Path accepts a route_name and route_parameters as arguments. I can build my links as such:</p> <pre> <code class="language-haml">&lt;a href="{{ path( 'route_name', {'param_key': 'param_value'}) }}"&gt;View Awesome Stuff&lt;/a&gt;</code></pre> <p>All we need to do now if populate the route_name and parameters, right?  Well, I found it a bit confusing to determine the correct routes, so that's what we're going to do here.</p> <p>In ECK, the routes are dynamic, but the View ( canonical ) and Edit ( edit_form ) follow the typical format: "entity.{$entity_type}.canonical" for viewing an existing entity, and "entity.{$entity_type).edit_form" for editing.  The only real thing is to populate the route_parameter, which is "{$entity_type}": "{$entity_id}".  Our path function becomes:</p> <pre> <code class="language-haml">&lt;a href="{{ path('entity.cool_entity.canonical', {'cool_entity': awesome_stuff.id.value}) }}"&gt;View Awesome Stuff&lt;/a&gt;</code></pre> <p>You may have noticed I populated the "{$entity_id}" with "awesome_stuff.id.value".  This is just a Twig variable that has my entity id, probably populated from a controller or entity reference field ( because who doesn't want to reference Awesome Stuff? ).  However you can get the ID of the Awesome Stuff entity you want to view will work.</p> <p>For editing our Awesome Stuff:</p> <pre> <code class="language-haml">&lt;a href="{{ path('entity.cool_entity.edit_form', {'cool_entity': awesome_stuff.id.value}) }}"&gt;Edit Awesome Stuff&lt;/a&gt;</code></pre> <p>That was actually pretty straight forward.  Now for the fun stuff, linking to the entity form to create new Awesome Stuff.  </p> <p>Because of the way ECK works, all entity forms use the same route, 'eck.entity.add', and it's the route parameters that determine which form is displayed ( and subsequently, what entities are created ).</p> <p>The route 'eck.entity.add' takes two parameters, 'eck_entity_type' and 'eck_entity_bundle'.  Obviously, the bundle needs to be a bundle of the entity type. Now our Add link becomes:</p> <pre> <code class="language-haml">&lt;a href="{{ path('eck.entity.add', {'eck_entity_type': 'cool_entity', 'eck_entity_bundle': 'awesome_stuff'}) }}"&gt;Add Awesome Stuff&lt;/a&gt;</code></pre> <p>Sweet, now we have links to Add, View, and Edit Awesome Stuff. </p> <p>By the way, if you want to include a Delete link, it follows a similar pattern as Edit:</p> <pre> <code class="language-haml">&lt;a href="{{ path('entity.cool_entity.delete_form', {'cool_entity': awesome_stuff.id.value}) }}"&gt;Delete Awesome Stuff&lt;/a&gt;</code></pre> <p>We could stop there, but I just can't get enough Awesome Stuff.  What I want now is to help my dear users to find their way back to what ever page introduced them to such Awesome Stuff.  For those familiar, that would be done by appending the 'destination' parameter to my links.  </p> <p>Since, I just want the user to go back to the original page, I want to pass that path into the destination.  For that, I can use:</p> <pre> <code class="language-haml">{{ path('&lt;current&gt;') }}</code></pre> <p>Now my links are:</p> <pre> <code class="language-haml">&lt;!-- View --&gt; &lt;a href="{{ path('entity.cool_entity.canonical', {'cool_entity': awesome_stuff.id.value, 'destination': path('&lt;current&gt;')}) }}"&gt;View Awesome Stuff&lt;/a&gt; &lt;!-- Edit --&gt; &lt;a href="{{ path('entity.cool_entity.edit_form', {'cool_entity': awesome_stuff.id.value, 'destination': path('&lt;current&gt;')}) }}"&gt;Edit Awesome Stuff&lt;/a&gt; &lt;!-- Delete --&gt; &lt;a href="{{ path('entity.cool_entity.delete_form', {'cool_entity': awesome_stuff.id.value, 'destination': path('&lt;current&gt;')}) }}"&gt;Delete Awesome Stuff&lt;/a&gt; &lt;!-- Add --&gt; &lt;a href="{{ path('eck.entity.add', {'eck_entity_type': 'cool_entity', 'eck_entity_bundle': 'awesome_stuff', 'destination': path('&lt;current&gt;')}) }}"&gt;Add Awesome Stuff&lt;/a&gt;</code></pre> <p>And it looks so simple now.   Hopefully this will save somebody some time ( including myself when I completely forget it ).</p> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-tags--blog--rss.html.twig * field--node--field-tags--blog.html.twig * field--node--field-tags.html.twig * field--node--blog.html.twig * field--field-tags.html.twig * field--entity-reference.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper field field--name-field-tags field--type-entity-reference field--label-above field__items"> <div class="field-label field__label">Tags</div> <div class="field__item"> <a href="/taxonomy/term/16" hreflang="en">Drupal</a> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> Sun, 07 Apr 2019 06:16:53 +0000 admin 128 at https://test.scottsawyerconsulting.com Component Driven Drupal Theming https://test.scottsawyerconsulting.com/blog/Component-Driven-Drupal-Theming <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--title--blog--rss.html.twig * field--node--title--blog.html.twig x field--node--title.html.twig * field--node--blog.html.twig * field--title.html.twig * field--string.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <span class="field-wrapper">Component Driven Drupal Theming</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--uid--blog--rss.html.twig * field--node--uid--blog.html.twig x field--node--uid.html.twig * field--node--blog.html.twig * field--uid.html.twig * field--entity-reference.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <span class="field-wrapper"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'username' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> <span lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="">admin</span> <!-- END OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> </span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--created--blog--rss.html.twig * field--node--created--blog.html.twig x field--node--created.html.twig * field--node--blog.html.twig * field--created.html.twig * field--created.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <span class="field-wrapper">Thu, 03/14/2019 - 11:34</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'links__node' --> <!-- FILE NAME SUGGESTIONS: * links--node.html.twig x links.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--body--blog--rss.html.twig * field--node--body--blog.html.twig * field--node--body.html.twig * field--node--blog.html.twig * field--body.html.twig * field--text-with-summary.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper body field field--name-body field--type-text-with-summary field--label-hidden field__items"> <div class="field__item"> <p>When designing a Drupal based site, there is a killer tool with which most of us are familiar, <a href="https://www.drupal.org/project/paragraphs/">Paragraphs</a>.  Paragraphs allows us to create a component-based architecture, whereby authors can add components to a page in a structured way.  How can we use the flexibility of Paragraphs to create a component-driven author experience that empowers the author while ensuring a consistent design language?</p> <p>Stuff Used In This Post:</p> <ul><li><a href="https://www.drupal.org">Drupal core</a> ( required )</li> <li><a href="https://www.drupal.org/project/paragraphs/">Paragraphs</a> ( required )</li> <li><a href="https://foundation.zurb.com/">Foundation</a> ( optional, but really helpful )</li> <li><a href="https://www.drupal.org/project/field_group">Field Group</a> ( optional, but a good idea )</li> <li><a href="https://www.drupal.org/project/fences">Fences</a> ( optional, but a good idea )</li> <li><a href="https://www.drupal.org/project/markup">Markup</a> ( optional, but really encouraged ) </li> </ul><h2>A bit about Paragraphs</h2> <p>If you are not familiar with Paragraphs, I encourage you to take a look at the <a href="https://www.drupal.org/project/paragraphs/">project page</a>. The short version is, Paragraphs allows you to define a "bundle" of fields that an author can optionally include in a piece of content.  By defining and configuring different bundles, a site builder can give authors multiple options for the types of content available in a piece of content.</p> <p>By default, Drupal gives site builders the ability to add fields to a content type.  Let's say you have a Basic Page content type, out-of-the-box, a Title field and Body field are included.  You can also add many different field types, such as an image field, telephone number field, select lists, taxonomy fields, etc.  Drupal core ships with many types of fields, and even more are available as contributed modules. </p> <p>After you add fields to a content type, you can set the order in which those form fields appear to the author, and, independently, set the order in which the field values are displayed to readers.  Unfortunately, that doesn't give authors much control over the composition of a page.  The architect must anticipate every field the author might need, and once the display is configured, there is little flexibility left for the author. </p> <p>The new Layout Builder module ( hopefully soon to be included in Drupal core ) gives a bit more control as to how fields are laid out, but there are many things that Layout Builder can not do, such as configure padding, colors, or other attributes that an author may want to configure.  Additionally, all of the fields must still be added at the content type level.</p> <p>Let's say we know that an author will want to be able to add some images and text to a Basic Page.  We would need an image field and a text field.  But then, what if the author wants the page to have an image at the top, above the text, and another below the text?  We would then need to add two image fields, and a single text field.  As the author's requirements increase, so does the complexity of the Basic Page edit screen. The problem is, we can not possibly anticipate every type of layout / content that an author might want. </p> <p>Paragraphs can enhance the author experience by offering optional fields that can be added to a piece of content "on demand".  Paragraphs work by creating "bundles" of fields that are then added to the content type.  Then the author can select the "bundle" with a single button and new fields are added to the content type while editing a page.  This means that a content type is no longer limited by the site builder's initial understanding of every field that a piece of content will need, nor is the display of those fields predetermined.</p> <h2>How Paragraphs enable a Component Driven Site</h2> <p>Using Paragraphs, we can create two bundles, Text and Image.  Then, on our Basic Page content type, we can add a single field, Content ( using the required Entity Reference Revisions field type ) that reference our two bundles.  By setting the limit to "Unlimited" in the field storage configuration, the author can now add as many Text field and Image fields as necessary to their new page.  On the edit form, they are presented a button ( several different widgets are available ) to add which ever field they want, and as many as they like.  They can also reorder the fields as they see fit.  This opens up many possibilities.</p> <p>This ability to add different fields to a piece of content on demand gives the site builder the opportunity (responsibility?) to componentize the site.  It no longer makes sense to style a site based on the content type or individual page, because we no longer have control over exactly what content will be on the page.  Rather, we need to style the components that may be present on the page.  This way, regardless of how many components, or in what order, the components are added, the site design remains cohesive.</p> <h2>Giving Authors even more control</h2> <p>So far, we have given authors the ability to add as many images and blocks of text as they desire, and select the order in which they appear.  While that is a great first step, we want to give them even more control, and more field options.  Maybe under some blocks of text the author wants to add a link, and have it styled as a button.  We can add another Paragraph bundle that includes a Link field.  Since every Paragraph bundle has a name, let's call this "Button".  Now the author can add an image, text, and a link to the page.  But the link is just some underlined text, how do we ensure all of the link fields appear as a button, without requiring authors to add CSS classes to the link?</p> <p>Well, I tend to do this with a combination of Preprocess functions and CSS.</p> <p>This goes in the THEME.theme file.  THEME would be the machine name of your theme.  Keep in mind, you will want to use a custom theme ( or child theme ).  </p> <pre> <code class="language-php">// file: THEME.theme /** * Implements hook_preprocess_paragraph__type(). */ function THEME_preprocess_paragraph__button(array &amp;$variables) { // get the paragraph from the $variables array $paragraph = $variables['paragraph']; // add a class to the Paragraph container so we can target with CSS $variables['attributes']['class'][] = 'button--configuration'; }</code></pre> <p>Next, in the CSS, you could add something like:</p> <pre> <code class="language-css">// file: style.css .button--configuration a { // button styles }</code></pre> <p>There is a reason that I put the class on the container rather than the a element directly which I will get to, but you may choose to do this differently.</p> <p>Also, some of you may be saying, "Hey, we can do that with Twig rather than PHP!"  And you would be correct.  The reason I am not doing this is so that I don't need to create dozens of Twig files.  By adding the classes through preprocess functions, I can reuse the same Twig files and keep my styles better scoped.  There is also a case for using a combination of preprocess and Twig, which is how I usually do this.</p> <p><strong>NOTE: </strong>Going forward, I am going to use Sass instead of pure CSS.  For one thing, it helps componentize my styles in individual partials.  For another, I am going to be using <a href="https://foundation.zurb.com/">Foundation</a> for quickly building out components.  This should work for Bootstrap or any other front-end framework you choose ( even your own custom framework ).  There is a Drupal theme, Zurb Foundation, but it's currently a bit behind on the Foundation version.  I tend to use Foundation directly in a custom theme, but the concepts here mostly apply.  This is not a tutorial on Sass, so if you are not familiar, it's definitely worth looking into.</p> <p>So, to change the button to a component to Sass using Foundation, I would create a partial _paragraphs--button.scss in a directory like scss/components/.</p> <pre> <code class="language-scss">// file: _paragraphs--button.scss .button--configuration { a { @include button; // this is the Foundation mixin for creating a button. } }</code></pre> <p>Now whenever the author adds a link using our button field, it will get the button styles.</p> <p>In Foundation, and probably most frameworks, buttons have a default style, usually a standard background color, text color, and some other settings.  Let's say we want the author to be able to set the background color by themselves.  Foundation has some default classes for setting button backgrounds ( like <em>primary</em>, <em>secondary</em>, etc ).  Again, we don't want to burden authors with implementation details, like class names.  Also, <em>primary</em> and <em>secondary </em>don't really mean anything to an author, they just want to select a color.  And we want to limit those color options to those that work with our theme.</p> <p>Typically, when I design a site, one of the first things I do is establish a color palette.  The palette will have the customer's brand colors and a few variations of those colors.  I would include the colors as a Sass map:</p> <pre> <code class="language-scss">// file: _vars.scss $color-palette: ( blue: #0000ff, red: #ff0000, green: #00ff00 );</code></pre> <p>Now I an reuse those colors across my site to ensure consistency.</p> <p>So, how do I give those options to my authors?  I would add a field to my Button paragraph bundle call "Button Color" ( machine name: field_button_color ).  I typically use the field type List Text.  For the allowed values, I enter something like this:</p> <pre> <code>blue|Blue red|Red green|Green</code></pre> <p>This will create a select list for the author with the allowed colors ( It can also be radio buttons / checkboxes ).  In the field settings, I make it required, and set a default value.  For usability, I generally move these "Configuration" fields above the "Content" field in Manage Form Display, and move to the Hidden area in Manage Display on my Paragraph bundle.  This way, the field is available to my author, but never displayed to visitors.</p> <p>There is also a way to do this with a color picker field, but it adds some complexity.  Maybe one day I will write a post about it.</p> <p>Next, I add my field to my preprocess function:</p> <pre> <code class="language-php">&lt;?php // file: THEME.theme /** * Implements hook_preprocess_paragraph__type(). */ function THEME_preprocess_paragraph__button(array &amp;$variables) { // get the paragraph from the $variables array $paragraph = $variables['paragraph']; // add a class to the Paragraph container so we can target with CSS $variables['attributes']['class'][] = 'button--configuration'; // check for the field_button_color and set a class. if ($paragraph-&gt;hasField('field_button_color') &amp;&amp; !$paragraph-&gt;field_button_color-&gt;isEmpty()) { $variables['attributes']['class'][] = 'button-color--' . $paragraph-&gt;field_button_color-&gt;value; } }</code></pre> <p>Here, what I did was check to see if that field is added to my paragraph bundle, and has a value set.  This is just a good practice, because if you have added the field after some content was created, it will throw an error if you don't include this check.  Nobody likes errors.</p> <p>Now we have a class on our .button--configuration container, so let's see how we can use this in Sass. <a href="https://foundation.zurb.com/sites/docs/button.html#sass-mixins">Foundation has a mixin for button style</a>, but you could easily roll your own.</p> <pre> <code class="language-scss">// file: _paragraphs--button.scss .button--configuration { a { @include button; // this is the Foundation mixin for creating a button. } // loop over our colors to look for our button-color-- class @each $color-name, $color-value in $color-palette { &amp;.button-color--#{$color-name} { // @include button-style($background, $background-hover, $color); @include button-style($color-name, auto, auto); } } }</code></pre> <p>If you notice, the button-style mixin has two more parameters $background-hover, and $color.  For this post, I just set those to 'auto', but if we wanted to give authors control over those settings, we would simply add more "Configuration" fields to our Button bundle, preprocess them, and include in our Sass.</p> <p>Now, you can go crazy adding configuration fields to each paragraph bundle in an effort to give authors the maximum control over the site, but it gets time consuming and makes for a crazy and tedious author experience.  It's best to use some judgement, think about what the author actually needs, keep things organized, and set sensible defaults so the author doesn't have to touch every field ever time.  One way to help with the organization is to use the <a href="https://drupal.org/project/field_group">Field Group</a> module.  Usually, I create a Details group, name it something like "Button Configuration", and put all of my Configuration fields in there.  If there are a lot of configuration fields, I will group them in tabs.  </p> <p>This is an example of how a Button paragraph form display might look.  The configuration is all tucked away in a details group above the actual content field, with tabs for each of the settings.</p> <pre> <code>Button Configuration ( Details, collapsed ) - Configuration Tabs ( Tabs ) - Background Color ( Tab ) - Button Background Color ( field_button_background_color, select list ) - Text Color ( Tab ) - Button Text Color ( field_button_text_color, select list ) Button ( field_button, link field )</code></pre> <h2>A bit about Page Layout</h2> <p>Hopefully I have illustrated how you can use Paragraphs to give authors control over individual components.  This an awesome thing.  But now we want to give authors more control over the whole page.</p> <p>Bootstrap and older versions of Foundation had the concept of "Rows" and "Columns".  These basically defined a context for laying out content horizontally, also known as a "Grid Layout".  A "Row" is a container, and a "Column" defines how much horizontal space some chunk of content can use.  The current version of Foundation ( 6.5.3 at this time ) uses a concept they call <a href="https://foundation.zurb.com/sites/docs/xy-grid.html">XY Grids</a>, very similar to traditional grids, only leveraging CSS Flexbox, which is awesome.  Instead of "Rows" and "Columns", there are "Grid-X" ( horizontal layouts ) or "Grid-Y" ( vertical layouts ), and "Cells".  I wouldn't call Cells "Columns", because if used in a vertical layout context, they define vertical space, rather than horizontal.  However, it's easier to think about Cells in the horizontal context as Columns, and that is probably your primary concern, how to layout out the horizontal aspects of the page.</p> <p>To create a grid layout, there are a series of containers, the outer most establishes the context ( Grid X ), the inner defines the space for the content ( Cell ).  Here is an example of how the HTML must be structured to leverage the XY Grid.</p> <pre> <code class="language-haml">&lt;div class="grid-x"&gt; &lt;div class="cell"&gt; &lt;!-- The first column Content Here --&gt; &lt;/div&gt; &lt;div class="cell"&gt; &lt;!-- The second column Content Here --&gt; &lt;/div&gt; &lt;/div&gt;</code></pre> <p>This creates two Cells or columns.  We can set the sizes of those Cells by adding classes, prefixed by the size screen we want to target.  By default Foundation uses a 12 column grid, so we could do something like:</p> <pre> <code class="language-haml">&lt;div class="grid-x"&gt; &lt;div class="cell small-12 medium-6 large-4"&gt; &lt;!-- The first column Content Here --&gt; &lt;/div&gt; &lt;div class="cell small-12 medium-6 large-8"&gt; &lt;!-- The second column Content Here --&gt; &lt;/div&gt; &lt;/div&gt;</code></pre> <p>Again, this is not a tutorial on Foundation, so read up.</p> <p>The real question is, how do we implement something like this in a way that an author can control?  Remember, we want to minimize the amount of knowledge the author needs about how CSS works, they just want to select some options and the page look as they expect.</p> <h2>Paragraphs for Page Layout</h2> <p>One of the coolest aspect of Paragraphs is the ability to "nest" paragraph bundles.  That is, a Paragraph bundle that has another Paragraph bundle as it's content field.  We can leverage this nested approach to create the kind of complex structure an author probably expects of his shiny CMS.  To do this, we're going to build "inside out".  Hopefully you will see what I mean.</p> <p>The first step would be: remove all fields from our Basic Page content type.  There should only be a title ( it's a Drupal requirement anyway ).  We want the Basic Page to be a clean slate for our authors.</p> <p>We already have our Paragraph "component" bundles, Text, Image, Title, Button.  You can add as many as you want, but I encourage you to keep them relatively simple, only one content field per bundle, otherwise, the author may have difficulty understanding what they should choose.</p> <p>Now, let's create a new Paragraph bundle, you can call it Cell.  The Cell is the container for our components, so we need to add one field, and Entity Reference Revision -&gt; Paragraph, call it Components ( field_components ).  In the field storage settings, set to Unlimited.  In the field settings, choose each of the component bundles you want your author to be able to add to the page.</p> <p>Next, add some fields (of type Text List ) for the setting columns.  I would typically add a field for each of my screen sizes, field_small_size, field_medium_size, field_large_size.  </p> <pre> <code class="language-haml">field_small_size small-12|100% small-6|50% field_medium_size medium-12|100% medium-9|75% medium-8|66% medium-6|50% medium-4|33% medium-3|25% field_large_size large-12|100% large-9|75% large-8|66% large-6|50% large-4|33% large-3|25%</code></pre> <p>Notice, I didn't give the author every possible grid size, I can't think of a case where you would want small-1.  Also, I display a percentage in the select options rather than the cell size.  The cell sizes are implementation details authors don't understand.  They understand percents.  This is also a great time to add some assistance, in the form of some help text for the author.  I like the <a href="https://www.drupal.org/project/markup">Markup </a>module for adding instructions.  Drupal has Help text area for each field, but it's displayed below the field.  This can clutter the UI, and the one thing I learned in Technical Writing is ALWAYS INCLUDE THE WARNING ( and instruction ) BEFORE THE ACTION.  Thanks Dr. Wiseman! Just be sure to remove this from the Display or visitors will see your help text!</p> <p>As before, I am going to put these settings in field group tabs to minimize the clutter.</p> <p>Next, we need to add add a preprocess function in our theme.</p> <pre> <code class="language-php">&lt;?php // file: THEME.theme /** * Implements hook_preprocess_paragraph__type(). */ function THEME_preprocess_paragraph__cell(array &amp;$variables) { $paragraph = $variables['paragraph']; $variables['attributes']['class'][] = 'cell'; if ($paragraph-&gt;hasField('field_small_size') &amp;&amp; !$paragraph-&gt;field_small_size-&gt;isEmpty()) { $variables['attributes']['class'][] = $paragraph-&gt;field_small_size-&gt;value; } if ($paragraph-&gt;hasField('field_medium_size') &amp;&amp; !$paragraph-&gt;field_medium_size-&gt;isEmpty()) { $variables['attributes']['class'][] = $paragraph-&gt;field_medium_size-&gt;value; } if ($paragraph-&gt;hasField('field_large_size') &amp;&amp; !$paragraph-&gt;field_large_size-&gt;isEmpty()) { $variables['attributes']['class'][] = $paragraph-&gt;field_large_size-&gt;value; } }</code></pre> <p>Now we have our Cells, which contain our components, and the author can control the horizontal space at 3 different screen sizes.  That is some powerful stuff.</p> <p>We could just add our Cell field to our Basic Page content type and call it a day, but we'd be missing a few things.</p> <p>For one, Cells need to have a container with the class <em>.grid-x </em>.  We could easily use the <a href="https://www.drupal.org/project/fences">Fences</a> module on the Basic Page -&gt; Manage Display to add that class to the Cell field.  The result would be that our layout would always be the full-width of our screen.  My experience is, full-width content is difficult to make look good for all content.  It also means authors can't do things like add a background color to a row.  What I find is, for the majority of content, you want it contained to a center area ( or left or right ) of the page, with only some content able to be full width ( like Hero images ). </p> <h2>Creating Full-Width and Contained Sections</h2> <p>Let's say our page layout consists of a full-width Hero image, and below that 3 columns, centered, each with an image, a title and some text with a button.  How would we give authors that sort of capability?</p> <p>Here is what the markup would need to look like:</p> <pre> <code class="language-haml">&lt;div class="grid-x"&gt; &lt;div class="cell small-12 medium-12 large-12"&gt; &lt;img&gt; &lt;!-- our hero image --&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="grid-container"&gt; &lt;!-- need this wrapper --&gt; &lt;div class="grid-x"&gt; &lt;div class="cell small-12 medium-4 large-4"&gt; &lt;img&gt; &lt;h2&gt;Title 1&lt;/h2&gt; &lt;p&gt;A bit of text&lt;/p&gt; &lt;/div&gt; &lt;div class="cell small-12 medium-4 large-4"&gt; &lt;img&gt; &lt;h2&gt;Title 2&lt;/h2&gt; &lt;p&gt;A bit of text&lt;/p&gt; &lt;/div&gt; &lt;div class="cell small-12 medium-4 large-4"&gt; &lt;img&gt; &lt;h2&gt;Title 3&lt;/h2&gt; &lt;p&gt;A bit of text&lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt;</code></pre> <p>If you didn't notice, there is a wrapper element around our second <em>.grid-x</em>, <em>.grid-container .  </em>This is a Foundation feature that will contain the contents of the <em>.grid-x</em> to a predefined center region.  This is all configurable through SASS variables, but the defaults are fine for this discussion.  The point is, we need the author to be able to decide if the content will be the full-width of the screen or contained to the center region with minimum fuss.</p> <p>For starters, if you already added a Cell field to the Basic Page, delete it.</p> <p>Next, let's add a new Paragraph bundle.  call it Section.  Add an Entity Reference Revision field, Cell, Unlimited, and reference the Cell bundle.  </p> <p>Now you can add a boolean field, Contained.  I would have it checked by default.  </p> <p>Previously, we were using preprocess functions to add a class to our paragraph field.  Now we need to actually change our markup.  I start with the preprocess function in my THEME.theme file.</p> <pre> <code class="language-php">&lt;?php // file: THEME.theme /** * Implements HOOK_preprocess_paragraph__type(). */ function THEME_preprocess_paragraph__section(array &amp;$variables) { $paragraph = $variables['paragraph']; if ($paragraph-&gt;hasField('field_contained') &amp;&amp; !$paragraph-&gt;field_contained-&gt;isEmpty() &amp;&amp; $paragraph-&gt;field_contained-&gt;value == TRUE) { $variables['contained'] = 'TRUE'; } else { $variables['contained'] = 'FALSE'; }</code></pre> <p>You notice that this time, I didn't add a class, I created an entirely new variable, $variables['contained'], and I gave it a string, "TRUE" or "FALSE".  I've had some challenges with Twig and truthiness, so, string comparisons it is.</p> <p>If you've enabled Twig debug on your Drupal site, you will see the theme suggestion for our paragraph includes something like 'paragraph--section.html.twig'.  More on <a href="https://www.drupal.org/docs/8/theming/twig/debugging-twig-templates">Twig debug mode</a>.  The gist is, copy paragraph.html.twig from the Paragraphs module directory into your theme template directory.</p> <pre> <code>themes/custom/THEME/templates/paragraph--section.html.twig</code></pre> <p>Next edit the template so it looks something like this:</p> <pre> <code class="language-haml">{# file: paragraph--section.html.twig #} {% set classes = [ 'paragraph', 'paragraph--type--' ~ paragraph.bundle|clean_class, view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class, not paragraph.isPublished() ? 'paragraph--unpublished' ] %} {% block paragraph %} &lt;div{{ attributes.addClass(classes) }}&gt; {% if contained == 'TRUE' %} &lt;div class="grid-container"&gt; {% endif %} &lt;div class="grid-x"&gt; {% block content %} {{ content }} {% endblock %} &lt;/div&gt; {% if contained == 'TRUE' %} &lt;/div&gt; {% endif %} &lt;/div&gt;</code></pre> <p>There are a couple of things going on here.  </p> <ol><li>It checks that our variable 'contained' == 'TRUE'</li> <li>If yes, adds a <em>div.grid-container</em></li> <li>Add the container <em>div.grid-x</em></li> </ol><p>Be sure to clear cache after adding a new template.</p> <p>Now our author can control which sections are full-width and which are contained by checking a box.  Huzzah!</p> <p>Go ahead and add the Entity Reference Revisions paragraph field "Sections" ( referencing Sections bundle ) to your content type and you are almost done.</p> <p>Something you will likely notice is, the Cells don't automatically work.  This is because of the extra markup Drupal injects around fields.  </p> <p>There are many ways to deal with this, I find the simplest is to install the Fences module.  Go to Admin-&gt;Structure-&gt;Paragraphs-&gt;Sections-&gt;Manage Display.  Click the gear to the right of the field Cell, and set all the wrappers to None.  Now the Cells should use the grid as intended.</p> <h2>Finally, the Author Experience</h2> <p>Now that we're all set up, here is how the author would build a page:</p> <ol><li>Visit /node/add/page.</li> <li>Click Add Section -&gt; Configure the Section ( Contained, and whatever other settings you added ).</li> <li>Click Add Cell -&gt; Configure the Cell width for each screen size.</li> <li>Click Add Image / Add Title / Add Text / Add Button from the Components drop button and configure to taste.</li> </ol><p>There are a lot of other options I like to give authors, like background colors on sections, background images ( checkout <a href="https://www.drupal.org/project/field_group_background_image">Field Group Background Image</a> ), padding options.  Just try to keep the UI sensible, and use language a human being would understand.  </p> <p>If authors like Legos ( and who doesn't? ), they should quickly take to building pages with Paragraphs.  As always, they may need some help getting their heads around the basic concepts, so provide excellent help.  It could be a video, images, etc, using the Markup field is great for this.  Just keep in mind, images added directly through the Markup field editor get wiped out.  It's a weird Drupal thing, that is easy to work around by uploading your images to the theme or somewhere else.</p> <p> </p> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-tags--blog--rss.html.twig * field--node--field-tags--blog.html.twig * field--node--field-tags.html.twig * field--node--blog.html.twig * field--field-tags.html.twig * field--entity-reference.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper field field--name-field-tags field--type-entity-reference field--label-above field__items"> <div class="field-label field__label">Tags</div> <div class="field__item"> <a href="/taxonomy/term/16" hreflang="en">Drupal</a> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> Thu, 14 Mar 2019 15:34:23 +0000 admin 126 at https://test.scottsawyerconsulting.com Seeds Thrift Store https://test.scottsawyerconsulting.com/node/125 <!-- THEME DEBUG --> <!-- THEME HOOK: 'ds_entity_view' --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'foundation_2col_bricks' --> <!-- FILE NAME SUGGESTIONS: * foundation-2col-bricks--node--125.html.twig * foundation-2col-bricks--node-client-review-rss.html.twig * foundation-2col-bricks--node-client-review.html.twig * foundation-2col-bricks--node-rss.html.twig * foundation-2col-bricks--node.html.twig x foundation-2col-bricks.html.twig x foundation-2col-bricks.html.twig --> <!-- BEGIN OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_bricks/foundation-2col-bricks.html.twig' --> <div class="row"> <div class="medium-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--body--client-review--rss.html.twig * field--expert--node--body--client-review.html.twig * field--expert--node--client-review.html.twig * field--expert--node--body.html.twig * field--expert--body--client-review.html.twig * field--expert--client-review.html.twig * field--expert--body.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--node--body--client-review.html.twig * field--node--body.html.twig * field--node--client-review.html.twig * field--body.html.twig * field--text-with-summary.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper body field field--name-body field--type-text-with-summary field--label-hidden field__items"> <div class="field__item"> <p>My goal was to give Seeds Thrift Store the look of a high-end fashion retailer.  After looking at several sites, a few common patterns emerged, small headers with just the essential navigation, a large hero or mast head with greeting or special offer, a few teasers, and an Instagram gallery is common.  Most followed a common grid layout with large images of the merchandise dominating the experience.</p> <p>In my rendition, I included a few key messages to indicate Seeds has more to offer than just a typical thrift store, it's a fashion-forward place for trendy people.  </p> <p>The "More Than You Might Expect" section opens the door to some of the ideas we discussed, introducing Seeds to the DYI decorating folks.  Furnishings in particular seem to carry a higher price than many other items, so I think it's important to promote.  Other categories, Decor, Accessories, Footwear, can open visitors minds to visit Seeds to discover other items they may not have otherwise considered.</p> <p>The "Share Your Style" section introduces a social media campaign and the hashtag #seedslook as a way to engage customers.  Additionally, it's a way to highlight and generate demand for items.  We decided to add prices to demonstrate the great value of shopping at Seeds.  These items should be swapped out regularly and reflect seasonal trends.</p> <p>Directly above the footer is an email sign up form, promising access to New Arrivals.  </p> <p>The footer is simple, containing links to the main sections of the site, providing critical info such as phone number and address, and social media links.</p> <p>Of course the design is mobile-friendly, featuring responsive typography a single column layout, and offscreen navigation.   </p> <p>The first image scrolls so you can get an idea of the experience on a computer.  The two images below that open a modal when clicked so you can see more detail.  The first image is for desktop, the second is for mobile.</p> <p>Please provide feedback using the comment form below.  You can also show your approval by clicking on the stars under "Vote".</p> <p> </p> <p> </p> <p> </p> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> </div> </div> <div class="row"> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-feedback--client-review--rss.html.twig * field--expert--node--field-feedback--client-review.html.twig * field--expert--node--client-review.html.twig * field--expert--node--field-feedback.html.twig * field--expert--field-feedback--client-review.html.twig * field--expert--client-review.html.twig * field--expert--field-feedback.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--node--field-feedback--client-review.html.twig * field--node--field-feedback.html.twig * field--node--client-review.html.twig * field--field-feedback.html.twig x field--comment.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--comment.html.twig' --> <section class="field-wrapper"> <h2 class="field-items">Add new comment</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=125&amp;2=field_feedback&amp;3=client_feedback" token="6a27CMywOC4PxNJ2QRL_nqbPMhwiFa0RDUaASJ4buDI"></drupal-render-placeholder> </section> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--comment.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'links__node' --> <!-- FILE NAME SUGGESTIONS: * links--node.html.twig x links.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> </div> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-design--client-review--rss.html.twig * field--expert--node--field-design--client-review.html.twig * field--expert--node--client-review.html.twig * field--expert--node--field-design.html.twig * field--expert--field-design--client-review.html.twig * field--expert--client-review.html.twig * field--expert--field-design.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--node--field-design--client-review.html.twig * field--node--field-design.html.twig * field--node--client-review.html.twig * field--field-design.html.twig * field--entity-reference-revisions.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper field field--name-field-design field--type-entity-reference-revisions field--label-hidden field__items"> <div class="client-review--item field__item"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'ds_entity_view' --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'foundation_2col_stacked' --> <!-- FILE NAME SUGGESTIONS: * foundation-2col-stacked--paragraph--414.html.twig * foundation-2col-stacked--paragraph-review-item-default.html.twig * foundation-2col-stacked--paragraph-review-item.html.twig * foundation-2col-stacked--paragraph-default.html.twig * foundation-2col-stacked--paragraph.html.twig x foundation-2col-stacked.html.twig x foundation-2col-stacked.html.twig --> <!-- BEGIN OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_stacked/foundation-2col-stacked.html.twig' --> <div class="row"> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-content-title--review-item--default.html.twig * field--expert--paragraph--field-content-title--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-content-title.html.twig * field--expert--field-content-title--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-content-title.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-content-title--review-item.html.twig * field--paragraph--field-content-title.html.twig * field--paragraph--review-item.html.twig * field--field-content-title.html.twig * field--string.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <h2 class="field-wrapper field field--name-field-content-title field--type-string field--label-inline field__items"> <strong class="field-label field__label">Title</strong> Home Page - Desktop </h2> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-version--review-item--default.html.twig * field--expert--paragraph--field-version--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-version.html.twig * field--expert--field-version--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-version.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-version--review-item.html.twig * field--paragraph--field-version.html.twig * field--paragraph--review-item.html.twig * field--field-version.html.twig * field--decimal.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <h3 class="field-wrapper field field--name-field-version field--type-decimal field--label-inline field__items"> <strong class="field-label field__label">Version</strong> 1.00 </h3> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> </div> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-vote--review-item--default.html.twig * field--expert--paragraph--field-vote--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-vote.html.twig * field--expert--field-vote--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-vote.html.twig * field--expert.html.twig * field--ds-field-expert.html.twig * field--paragraph--field-vote--review-item.html.twig * field--paragraph--field-vote.html.twig * field--paragraph--review-item.html.twig * field--field-vote.html.twig * field--voting-api-field.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> <div class="field-label-inline">Vote</div> <drupal-render-placeholder callback="voting_api.lazy_loader:buildForm" arguments="0=fivestar&amp;1=paragraph&amp;2=review_item&amp;3=414&amp;4=vote&amp;5=field_vote&amp;6=a%3A5%3A%7Bs%3A5%3A%22style%22%3Bs%3A7%3A%22default%22%3Bs%3A12%3A%22show_results%22%3Bs%3A1%3A%221%22%3Bs%3A13%3A%22show_own_vote%22%3Bs%3A1%3A%221%22%3Bs%3A8%3A%22readonly%22%3Bi%3A0%3Bs%3A6%3A%22values%22%3Ba%3A0%3A%7B%7D%7D" token="_hUPwqsLF8ui7d8l2nlM5SpjvO3lbZADRt1nfM1ljZQ"></drupal-render-placeholder> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> </div> </div> <div class="row"> <div class="medium-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-preview--review-item--default.html.twig * field--expert--paragraph--field-preview--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-preview.html.twig * field--expert--field-preview--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-preview.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-preview--review-item.html.twig x field--paragraph--field-preview.html.twig * field--paragraph--review-item.html.twig * field--field-preview.html.twig * field--image.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'themes/custom/ssc1/templates/paragraphs/field--paragraph--field-preview.html.twig' --> <div class="field-wrapper paragraph paragraph--type--"> <div class="preview--container"> <div class="preview--content"> <div class="preview--content--inner"> <div class="field-item"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/2018-06/desktop-full.png" width="1920" height="4240" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> </div> </div> </div> </div> </div> <!-- END OUTPUT from 'themes/custom/ssc1/templates/paragraphs/field--paragraph--field-preview.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-additional-images--review-item--default.html.twig * field--expert--paragraph--field-additional-images--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-additional-images.html.twig * field--expert--field-additional-images--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-additional-images.html.twig * field--expert.html.twig * field--ds-field-expert.html.twig * field--paragraph--field-additional-images--review-item.html.twig * field--paragraph--field-additional-images.html.twig * field--paragraph--review-item.html.twig * field--field-additional-images.html.twig * field--image.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> <div class="field-label-above">Additional Images</div> <div class="client-review--additional-images"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2018-06/desktop-full_0.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2018-06/desktop-full_0.png?itok=PCZo59WM" width="217" height="480" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2018-06/mobile-full.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2018-06/mobile-full.png?itok=w1CCTxCS" width="34" height="480" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> </div> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> </div> </div> <!-- END OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_stacked/foundation-2col-stacked.html.twig' --> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> </div> </div> <div class="row"> <div class="medium-12 columns"></div> </div> <div class="row"> <div class="medium-6 small-12 columns"> </div> <div class="medium-6 small-12 columns"> </div> </div> <div class="row"> <div class="medium-12 columns"></div> </div> <!-- END OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_bricks/foundation-2col-bricks.html.twig' --> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> Fri, 08 Jun 2018 15:06:01 +0000 admin 125 at https://test.scottsawyerconsulting.com https://test.scottsawyerconsulting.com/node/125#comments Bowen, Hanes & Company https://test.scottsawyerconsulting.com/node/124 <!-- THEME DEBUG --> <!-- THEME HOOK: 'ds_entity_view' --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'foundation_2col_bricks' --> <!-- FILE NAME SUGGESTIONS: * foundation-2col-bricks--node--124.html.twig * foundation-2col-bricks--node-client-review-rss.html.twig * foundation-2col-bricks--node-client-review.html.twig * foundation-2col-bricks--node-rss.html.twig * foundation-2col-bricks--node.html.twig x foundation-2col-bricks.html.twig x foundation-2col-bricks.html.twig --> <!-- BEGIN OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_bricks/foundation-2col-bricks.html.twig' --> <div class="row"> <div class="medium-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--body--client-review--rss.html.twig * field--expert--node--body--client-review.html.twig * field--expert--node--client-review.html.twig * field--expert--node--body.html.twig * field--expert--body--client-review.html.twig * field--expert--client-review.html.twig * field--expert--body.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--node--body--client-review.html.twig * field--node--body.html.twig * field--node--client-review.html.twig * field--body.html.twig * field--text-with-summary.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper body field field--name-body field--type-text-with-summary field--label-hidden field__items"> <div class="field__item"> <p>To view each proof in more detail, click the image.  The first image scrolls in it's browser window.  </p> <p>The desktop versions have a width of 1920 pixels, which is a common width of modern, high-definition desktop screens.  The width of the content area ( where most of the text and images are found ) have a width of 1200 pixels.  Most common laptops have a screen width of 1366 pixels, so there are about 83px right and left "gutters", which grow for larger screens.  At 1200 pixels, most of the pages will display a maximum number of characters of 50-75  per line, which is considered optimal for reading.   The "hero" image stretches the full width of the screen.</p> <p>For the mobile pages we used 414 pixels, the width of an iPhone+, just for proofing purposes, as it will work on any phone size.  For the mobile views, the content "blocks" stack vertically, which is why the mobile views are taller.  When the site is viewed on larger screens, such as an iPad, more horizontal space is available, and the blocks shift to a more horizontal layout to take advantage of the additional space.</p> <p> </p> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> </div> </div> <div class="row"> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-feedback--client-review--rss.html.twig * field--expert--node--field-feedback--client-review.html.twig * field--expert--node--client-review.html.twig * field--expert--node--field-feedback.html.twig * field--expert--field-feedback--client-review.html.twig * field--expert--client-review.html.twig * field--expert--field-feedback.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--node--field-feedback--client-review.html.twig * field--node--field-feedback.html.twig * field--node--client-review.html.twig * field--field-feedback.html.twig x field--comment.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--comment.html.twig' --> <section class="field-wrapper"> <h2 class="field-items">Add new comment</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=124&amp;2=field_feedback&amp;3=client_feedback" token="XdOxDhZdilomUYP3yAad505qSz45A2muiBGNyvKjTAM"></drupal-render-placeholder> </section> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--comment.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'links__node' --> <!-- FILE NAME SUGGESTIONS: * links--node.html.twig x links.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> </div> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-design--client-review--rss.html.twig * field--expert--node--field-design--client-review.html.twig * field--expert--node--client-review.html.twig * field--expert--node--field-design.html.twig * field--expert--field-design--client-review.html.twig * field--expert--client-review.html.twig * field--expert--field-design.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--node--field-design--client-review.html.twig * field--node--field-design.html.twig * field--node--client-review.html.twig * field--field-design.html.twig * field--entity-reference-revisions.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper field field--name-field-design field--type-entity-reference-revisions field--label-hidden field__items"> <div class="client-review--item field__item"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'ds_entity_view' --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'foundation_2col_stacked' --> <!-- FILE NAME SUGGESTIONS: * foundation-2col-stacked--paragraph--413.html.twig * foundation-2col-stacked--paragraph-review-item-default.html.twig * foundation-2col-stacked--paragraph-review-item.html.twig * foundation-2col-stacked--paragraph-default.html.twig * foundation-2col-stacked--paragraph.html.twig x foundation-2col-stacked.html.twig x foundation-2col-stacked.html.twig --> <!-- BEGIN OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_stacked/foundation-2col-stacked.html.twig' --> <div class="row"> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-content-title--review-item--default.html.twig * field--expert--paragraph--field-content-title--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-content-title.html.twig * field--expert--field-content-title--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-content-title.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-content-title--review-item.html.twig * field--paragraph--field-content-title.html.twig * field--paragraph--review-item.html.twig * field--field-content-title.html.twig * field--string.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <h2 class="field-wrapper field field--name-field-content-title field--type-string field--label-inline field__items"> <strong class="field-label field__label">Title</strong> Design Proofs </h2> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-version--review-item--default.html.twig * field--expert--paragraph--field-version--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-version.html.twig * field--expert--field-version--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-version.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-version--review-item.html.twig * field--paragraph--field-version.html.twig * field--paragraph--review-item.html.twig * field--field-version.html.twig * field--decimal.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <h3 class="field-wrapper field field--name-field-version field--type-decimal field--label-inline field__items"> <strong class="field-label field__label">Version</strong> 2.00 </h3> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> </div> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-vote--review-item--default.html.twig * field--expert--paragraph--field-vote--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-vote.html.twig * field--expert--field-vote--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-vote.html.twig * field--expert.html.twig * field--ds-field-expert.html.twig * field--paragraph--field-vote--review-item.html.twig * field--paragraph--field-vote.html.twig * field--paragraph--review-item.html.twig * field--field-vote.html.twig * field--voting-api-field.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> <div class="field-label-inline">Vote</div> <drupal-render-placeholder callback="voting_api.lazy_loader:buildForm" arguments="0=fivestar&amp;1=paragraph&amp;2=review_item&amp;3=413&amp;4=vote&amp;5=field_vote&amp;6=a%3A5%3A%7Bs%3A5%3A%22style%22%3Bs%3A7%3A%22default%22%3Bs%3A12%3A%22show_results%22%3Bs%3A1%3A%221%22%3Bs%3A13%3A%22show_own_vote%22%3Bs%3A1%3A%221%22%3Bs%3A8%3A%22readonly%22%3Bi%3A0%3Bs%3A6%3A%22values%22%3Ba%3A0%3A%7B%7D%7D" token="ZzO9cWmZYx3Do6SRewk3jfDZ_7Z53FQvhWct2GW6h2E"></drupal-render-placeholder> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> </div> </div> <div class="row"> <div class="medium-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-preview--review-item--default.html.twig * field--expert--paragraph--field-preview--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-preview.html.twig * field--expert--field-preview--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-preview.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-preview--review-item.html.twig x field--paragraph--field-preview.html.twig * field--paragraph--review-item.html.twig * field--field-preview.html.twig * field--image.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'themes/custom/ssc1/templates/paragraphs/field--paragraph--field-preview.html.twig' --> <div class="field-wrapper paragraph paragraph--type--"> <div class="preview--container"> <div class="preview--content"> <div class="preview--content--inner"> <div class="field-item"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/2018-04/v2-desktop-b_1.png" width="1920" height="2960" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> </div> </div> </div> </div> </div> <!-- END OUTPUT from 'themes/custom/ssc1/templates/paragraphs/field--paragraph--field-preview.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-additional-images--review-item--default.html.twig * field--expert--paragraph--field-additional-images--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-additional-images.html.twig * field--expert--field-additional-images--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-additional-images.html.twig * field--expert.html.twig * field--ds-field-expert.html.twig * field--paragraph--field-additional-images--review-item.html.twig * field--paragraph--field-additional-images.html.twig * field--paragraph--review-item.html.twig * field--field-additional-images.html.twig * field--image.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> <div class="field-label-above">Additional Images</div> <div class="client-review--additional-images"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2018-04/v2-desktop-b.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2018-04/v2-desktop-b.png?itok=EIzzMLYn" width="480" height="320" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2018-04/v2-desktop-b_0.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2018-04/v2-desktop-b_0.png?itok=_4_TT0ok" width="311" height="480" alt="Front Page - Desktop" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2018-04/v2-mobile-c.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2018-04/v2-mobile-c.png?itok=-KQCzmKU" width="50" height="480" alt="Front Page - Mobile" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2018-04/v2-team-desk-a_0.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2018-04/v2-team-desk-a_0.png?itok=KJYdJEpo" width="311" height="480" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2018-04/v2-team-profile-desk-_0.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2018-04/v2-team-profile-desk-_0.png?itok=KR_AoHDK" width="393" height="480" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2018-04/v2-team-profile-mobile-.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2018-04/v2-team-profile-mobile-.png?itok=ByMpuuYV" width="64" height="480" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2018-04/v2-desk-media-video_0.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2018-04/v2-desk-media-video_0.png?itok=3c1omG4J" width="311" height="480" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2018-04/v2-mobile-media-video.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2018-04/v2-mobile-media-video.png?itok=e-bA7dn5" width="57" height="480" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> </div> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> </div> </div> <!-- END OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_stacked/foundation-2col-stacked.html.twig' --> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> </div> </div> <div class="row"> <div class="medium-12 columns"></div> </div> <div class="row"> <div class="medium-6 small-12 columns"> </div> <div class="medium-6 small-12 columns"> </div> </div> <div class="row"> <div class="medium-12 columns"></div> </div> <!-- END OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_bricks/foundation-2col-bricks.html.twig' --> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> Fri, 27 Apr 2018 06:18:59 +0000 admin 124 at https://test.scottsawyerconsulting.com https://test.scottsawyerconsulting.com/node/124#comments Creating a Recurring Monthly Newsletter With MailChimp https://test.scottsawyerconsulting.com/blog/Creating-Recurring-Monthly-Newsletter-MailChimp <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--title--blog--rss.html.twig * field--node--title--blog.html.twig x field--node--title.html.twig * field--node--blog.html.twig * field--title.html.twig * field--string.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <span class="field-wrapper">Creating a Recurring Monthly Newsletter With MailChimp</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--uid--blog--rss.html.twig * field--node--uid--blog.html.twig x field--node--uid.html.twig * field--node--blog.html.twig * field--uid.html.twig * field--entity-reference.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <span class="field-wrapper"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'username' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> <span lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="">admin</span> <!-- END OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> </span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--created--blog--rss.html.twig * field--node--created--blog.html.twig x field--node--created.html.twig * field--node--blog.html.twig * field--created.html.twig * field--created.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <span class="field-wrapper">Mon, 02/19/2018 - 13:05</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'links__node' --> <!-- FILE NAME SUGGESTIONS: * links--node.html.twig x links.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--body--blog--rss.html.twig * field--node--body--blog.html.twig * field--node--body.html.twig * field--node--blog.html.twig * field--body.html.twig * field--text-with-summary.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper body field field--name-body field--type-text-with-summary field--label-hidden field__items"> <div class="field__item"> <p>I love MailChimp.  It does so many things really well, the price is great ( especially if you don't have a lot of contacts, since it's free for less than 2,000 ).  It would seem like the perfect solution for a small business to send a monthly newsletter to it's customers.</p> <p>One challenge I recently discovered, however, is that MailChimp really wants you to log in and create each newsletter.  While it's certainly a good idea to create a unique newsletter each time, this is not always something a small business will have the resources to manage.</p> <p>In steps MailChimp's automation tools.  With the automation tools, you can set up various triggers that will send a newsletter automatically.  Think about an ecommerce application.  When a person makes a purchase, maybe you want to email them a nice message thanking them for their recent purchase, maybe some tips on how to best use their recent purchase, the possibilities are endless. </p> <p>When a customer recently inquired about how their new Website could be used to email their customers a monthly newsletter that contained a link to their content service, I immediately thought MailChimp would be an excellent solution.  However, I was initially stymied about how to make MailChimp work for them.</p> <p>For starters, the way their content service works is a bit different than what I am accustomed to.  It seems in some industries, rather than creating unique content in the form of a blog or something similar, they will subscribe to a monthly service that creates content for them, and makes the same content available to many of their customers.</p> <p>Before you start jumping up and down about SEO and the value of original content, which was my initial reaction, this can make sense in certain circumstances.  </p> <ol><li>For this particular client, the goal was not SEO, but rather offering useful tips to their customers.</li> <li>The content is not hosted on their site, it's hosted on the content service's site, and my client just links to it.</li> <li>My client wouldn't create this content on their own, nor pay for unique content ( which would be expensive due to the expertise needed ), so without the service, my client's customers would be deprived of these tips.</li> </ol><p>So, the content service is in place and performs it's responsibility well enough.  My job was to get this content to my client's customers every month.</p> <h2>The Constraints</h2> <p>What my client needs is a automated way to send the EXACT same email newsletter, with a link to their content service.  The URL to the content never changes, so there would be no need ( or willingness on my client's part ) to log into MailChimp and update the campaign. They just want to set it and forget it.</p> <p>MailChimp has the ability to use feed ( like RSS ) to trigger these email newsletters.  It can actually parse the feed to use as the content for the newsletter.  While I can see this being a useful feature, it would not work for my client, because their content service does not provide any sort of feed.  I'll keep this one tucked in memory for future projects.</p> <p>The only trigger that makes sense is a time duration ( once every 30 days ).  My client wants the newsletter to be sent once per month, on the same day for all subscribers.  </p> <p>However, MailChimp doesn't really have a great way to configure this.  It seems this isn't a use-case they considered when designing their automation tools.</p> <h2>Date Based Automation</h2> <p>The one automation that MailChimp offers that seemed to fit my client's needs is the <a href="https://kb.mailchimp.com/automation/automation-types#Date-Based">Date Based</a> automation.  </p> <blockquote> <p>Date-based automations can help you engage with your subscribers throughout the year.</p> </blockquote> <p>There are four Date Based automations that MailChimp supports:</p> <ul><li>List added date</li> <li>Birthdays</li> <li>Specific date</li> <li>Recurring date</li> </ul><p>List added date is great if you want to have a funnel-type of workflow.  Set up one or more emails when a person subscribes with messaging designed to move them towards your goal.</p> <p>Birthday emails are just to make your organization seem more personal.</p> <p>You can use specific date campaigns to touch subscribers on holidays, important shopping days, etc.</p> <p>Recurring date is based on a field you create on the subscriber profile.  This can be an anniversary of any type.  The day you adopted a pet, the day you bought a car, whatever.</p> <p>Missing from these otherwise useful Date Based automation triggers is the one thing I need, a trigger that I can use to send a MONTHLY email to all subscribers on the same day.</p> <h2>The Work Around</h2> <p>Since these are the only tools I had to work with, I had to think a bit differently about my problem.  Really, I wanted to send a monthly email, but what if I could send an annual email, once per month?  </p> <p>Instead of sending 1 monthly email, I could send 12 annual emails, just on separated by 30 days?  That seems to meet my needs.</p> <h2>The Solution</h2> <p>I would need to put a couple of pieces in place to make this work, since it doesn't seem that MailChimp wants to support this use-case out of the box. </p> <h3>The Template</h3> <p>The first step is to create a template that is actually less of a template and really a copy of the actual email that I want to send.  I used MailChimp's <a href="https://kb.mailchimp.com/templates/layouts-and-themes/create-a-template-with-the-template-builder">Template Builder</a> to create what would be sent each month, complete with logo, text, and links that the subscribers would receive.  </p> <h3>The Date Field</h3> <p>The next step is to add a new date field to the subscriber profile.  <a href="https://kb.mailchimp.com/lists/manage-contacts/manage-list-and-signup-form-fields">Read more about how to add fields</a>. There are a few things I needed to consider:</p> <ul><li>I need the field to have the same value for each subscriber ( more on this in a bit ), as this will be part of my trigger.</li> <li>I do not want the subscriber to access this field directly, it wouldn't make sense to them, and if they altered the field, it would mess up my plan.</li> <li>This field will determine what day of the month my emails send, so I need to set it for a day when I can be fairly certain the content will be updated.</li> </ul><p>I created a date field, Newsletter Date, and set it for an arbitrary month and year.  The day is the important piece.  I want my email to go out in the middle of each month because ( according to my client ) the new content is sure to be updated.  For this post, let's say, 11/15/2017.</p> <p>You'll want to pay attention to, and probably notate the name or merge name you give this field.</p> <h3>Populating the date field.</h3> <p>Unfortunately, MailChimp does not allow you to set a single default value for a field.  Instead it uses a "merge" value, so that when this field is merged into your template, it will be populated, unless it is otherwise set. </p> <p>This is annoying, because it would require someone editing each record by hand, as you'll see.</p> <p>When I first set this up, I imported their existing customers, so it was easy enough to add a column to the CSV that had the date field populated.  But what about new subscribers on their website?</p> <p>What I had to was hard code a value for that field, so when a person signed up, it would insert the correct date into the field we created.</p> <p>How you do this will depend on how your subscription form works.  If you are using the form MailChimp provides, you will probably want to use the Embedded Forms, choose Advanced, and add this field as a Hidden Field.</p> <p>For my purposes, I am using a module that let's me map values to the MailChimp fields.  If you are using Drupal, you will want to check out <a href="https://www.drupal.org/project/webform_mailchimp">Webform MailChimp</a>.</p> <h3>Recurring Campaign</h3> <p>Now that we have a reliable date field on our subscribers, we need to set up a Recurring Campaign.  </p> <p>In MailChimp:</p> <!-- THEME DEBUG --> <!-- THEME HOOK: 'filter_caption' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --> <figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="c49175c0-024e-460c-ac19-5bce914fe9c4" src="/sites/default/files/inline-images/Step-1.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 1 - Click Campaigns</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><!-- THEME DEBUG --><!-- THEME HOOK: 'filter_caption' --><!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="1daaa574-987b-4c59-93fa-7839cbe716ad" src="/sites/default/files/inline-images/Step-2.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 2 - Click Create Campaign</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><!-- THEME DEBUG --><!-- THEME HOOK: 'filter_caption' --><!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="94fe4829-d12c-43ea-82f9-530ebf6f0c36" src="/sites/default/files/inline-images/Step-3.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 3 - Click Create Campaign</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><!-- THEME DEBUG --><!-- THEME HOOK: 'filter_caption' --><!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="67930760-a622-445e-87b7-8a7ccbaca1af" src="/sites/default/files/inline-images/Step-4.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 4 - Click Automated</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><!-- THEME DEBUG --><!-- THEME HOOK: 'filter_caption' --><!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="970480cf-064b-491a-8083-bfbc5353d185" src="/sites/default/files/inline-images/Step-5.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 5 - Click Date Based</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><!-- THEME DEBUG --><!-- THEME HOOK: 'filter_caption' --><!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="68c7a0ac-cac8-400c-843f-a3cf6db8f72a" src="/sites/default/files/inline-images/Step-6.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 6 - Click Specific Date</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><!-- THEME DEBUG --><!-- THEME HOOK: 'filter_caption' --><!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="c663b9ce-c274-40bf-94b4-f8c304f8b048" src="/sites/default/files/inline-images/Step-7.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 7 - Give it a name and select the list with your date field.</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><!-- THEME DEBUG --><!-- THEME HOOK: 'filter_caption' --><!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="00b4835d-fc17-4e39-a8b3-67f904d79776" src="/sites/default/files/inline-images/Step-8.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 8 - Create your triggers, one per month, in 30 day intervals.</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><!-- THEME DEBUG --><!-- THEME HOOK: 'filter_caption' --><!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="9da1cef3-afeb-4364-a1ba-edf56630e24a" src="/sites/default/files/inline-images/Step-9.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 9 - Create 12 iterations</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><!-- THEME DEBUG --><!-- THEME HOOK: 'filter_caption' --><!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="921e2994-5168-4f2a-b150-5210a0aed5ed" src="/sites/default/files/inline-images/Step-10.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 10 - Click Design Email for each trigger</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><!-- THEME DEBUG --><!-- THEME HOOK: 'filter_caption' --><!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="c7bc7ada-b8bc-43b9-a99a-be046728ebd8" src="/sites/default/files/inline-images/Step-11.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 11 - Be sure to give each trigger a name so you can tell them apart.</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><!-- THEME DEBUG --><!-- THEME HOOK: 'filter_caption' --><!-- BEGIN OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><figure role="group"><img alt="Image removed." data-entity-type="file" data-entity-uuid="6be9cb07-a8ae-428b-878e-c50229b12054" src="/sites/default/files/inline-images/Step-12.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /><figcaption>Step 12 - Choose Saved Templates and customize if desired.</figcaption></figure><!-- END OUTPUT from 'core/themes/stable/templates/content-edit/filter-caption.html.twig' --><p>Congratulations!  Now you have an email that will send to all subscribers on the same day each month, every year, with no interaction required.  Just make sure your new subscribers are getting the correct date added when they subscribe.</p> <p> </p> <p> </p> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-tags--blog--rss.html.twig * field--node--field-tags--blog.html.twig * field--node--field-tags.html.twig * field--node--blog.html.twig * field--field-tags.html.twig * field--entity-reference.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper field field--name-field-tags field--type-entity-reference field--label-above field__items"> <div class="field-label field__label">Tags</div> <div class="field__item"> <a href="/taxonomy/term/46" hreflang="en"> Marketing</a> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> Mon, 19 Feb 2018 18:05:01 +0000 admin 123 at https://test.scottsawyerconsulting.com Rogoff & Company https://test.scottsawyerconsulting.com/node/122 <!-- THEME DEBUG --> <!-- THEME HOOK: 'ds_entity_view' --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'foundation_2col_bricks' --> <!-- FILE NAME SUGGESTIONS: * foundation-2col-bricks--node--122.html.twig * foundation-2col-bricks--node-client-review-rss.html.twig * foundation-2col-bricks--node-client-review.html.twig * foundation-2col-bricks--node-rss.html.twig * foundation-2col-bricks--node.html.twig x foundation-2col-bricks.html.twig x foundation-2col-bricks.html.twig --> <!-- BEGIN OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_bricks/foundation-2col-bricks.html.twig' --> <div class="row"> <div class="medium-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--body--client-review--rss.html.twig * field--expert--node--body--client-review.html.twig * field--expert--node--client-review.html.twig * field--expert--node--body.html.twig * field--expert--body--client-review.html.twig * field--expert--client-review.html.twig * field--expert--body.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--node--body--client-review.html.twig * field--node--body.html.twig * field--node--client-review.html.twig * field--body.html.twig * field--text-with-summary.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper body field field--name-body field--type-text-with-summary field--label-hidden field__items"> <div class="field__item"> <p>For your project, we started by expanding your color pallet to include colors in the same family as your predominant color, which is a unique shade of red.</p> <p>We experimented with layout and color variations, that range from very traditional to very modern that pushes some design boundaries of what one might consider for a CPA firm website.  Additionally, for some layouts, we provided some alternatives that are closely related in style, but have a few differences.</p> <p>Each layout has a preview of what it might look like in a browser to give a sense of scale.  You can scroll the browser window to see how it might flow.  Below each design are one or more images, first is the full layout of the preview, followed by some alternatives.  You can click on the images to see a larger version.</p> <p>Each design has comments where you can leave any feedback.  The comments will only be seen by me.</p> <p> </p> <p> </p> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> </div> </div> <div class="row"> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-feedback--client-review--rss.html.twig * field--expert--node--field-feedback--client-review.html.twig * field--expert--node--client-review.html.twig * field--expert--node--field-feedback.html.twig * field--expert--field-feedback--client-review.html.twig * field--expert--client-review.html.twig * field--expert--field-feedback.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--node--field-feedback--client-review.html.twig * field--node--field-feedback.html.twig * field--node--client-review.html.twig * field--field-feedback.html.twig x field--comment.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--comment.html.twig' --> <section class="field-wrapper"> <h2 class="field-items">Add new comment</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=122&amp;2=field_feedback&amp;3=client_feedback" token="2HbTGUk-6UG7cpR9duaygM30xeyMULWTdH3A8M1XNRk"></drupal-render-placeholder> </section> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--comment.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'links__node' --> <!-- FILE NAME SUGGESTIONS: * links--node.html.twig x links.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> </div> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-design--client-review--rss.html.twig * field--expert--node--field-design--client-review.html.twig * field--expert--node--client-review.html.twig * field--expert--node--field-design.html.twig * field--expert--field-design--client-review.html.twig * field--expert--client-review.html.twig * field--expert--field-design.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--node--field-design--client-review.html.twig * field--node--field-design.html.twig * field--node--client-review.html.twig * field--field-design.html.twig * field--entity-reference-revisions.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper field field--name-field-design field--type-entity-reference-revisions field--label-hidden field__items"> <div class="client-review--item field__item"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'ds_entity_view' --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'foundation_2col_stacked' --> <!-- FILE NAME SUGGESTIONS: * foundation-2col-stacked--paragraph--410.html.twig * foundation-2col-stacked--paragraph-review-item-default.html.twig * foundation-2col-stacked--paragraph-review-item.html.twig * foundation-2col-stacked--paragraph-default.html.twig * foundation-2col-stacked--paragraph.html.twig x foundation-2col-stacked.html.twig x foundation-2col-stacked.html.twig --> <!-- BEGIN OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_stacked/foundation-2col-stacked.html.twig' --> <div class="row"> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-content-title--review-item--default.html.twig * field--expert--paragraph--field-content-title--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-content-title.html.twig * field--expert--field-content-title--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-content-title.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-content-title--review-item.html.twig * field--paragraph--field-content-title.html.twig * field--paragraph--review-item.html.twig * field--field-content-title.html.twig * field--string.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <h2 class="field-wrapper field field--name-field-content-title field--type-string field--label-inline field__items"> <strong class="field-label field__label">Title</strong> Design 1 </h2> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-version--review-item--default.html.twig * field--expert--paragraph--field-version--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-version.html.twig * field--expert--field-version--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-version.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-version--review-item.html.twig * field--paragraph--field-version.html.twig * field--paragraph--review-item.html.twig * field--field-version.html.twig * field--decimal.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <h3 class="field-wrapper field field--name-field-version field--type-decimal field--label-inline field__items"> <strong class="field-label field__label">Version</strong> 1.00 </h3> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> </div> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-vote--review-item--default.html.twig * field--expert--paragraph--field-vote--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-vote.html.twig * field--expert--field-vote--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-vote.html.twig * field--expert.html.twig * field--ds-field-expert.html.twig * field--paragraph--field-vote--review-item.html.twig * field--paragraph--field-vote.html.twig * field--paragraph--review-item.html.twig * field--field-vote.html.twig * field--voting-api-field.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> <div class="field-label-inline">Vote</div> <drupal-render-placeholder callback="voting_api.lazy_loader:buildForm" arguments="0=fivestar&amp;1=paragraph&amp;2=review_item&amp;3=410&amp;4=vote&amp;5=field_vote&amp;6=a%3A5%3A%7Bs%3A5%3A%22style%22%3Bs%3A7%3A%22default%22%3Bs%3A12%3A%22show_results%22%3Bs%3A1%3A%221%22%3Bs%3A13%3A%22show_own_vote%22%3Bs%3A1%3A%221%22%3Bs%3A8%3A%22readonly%22%3Bi%3A0%3Bs%3A6%3A%22values%22%3Ba%3A0%3A%7B%7D%7D" token="gMSWLHCeTx8vA73oWnfJUaXTAughAdgmEDyj4X8rnvc"></drupal-render-placeholder> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> </div> </div> <div class="row"> <div class="medium-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-preview--review-item--default.html.twig * field--expert--paragraph--field-preview--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-preview.html.twig * field--expert--field-preview--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-preview.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-preview--review-item.html.twig x field--paragraph--field-preview.html.twig * field--paragraph--review-item.html.twig * field--field-preview.html.twig * field--image.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'themes/custom/ssc1/templates/paragraphs/field--paragraph--field-preview.html.twig' --> <div class="field-wrapper paragraph paragraph--type--"> <div class="preview--container"> <div class="preview--content"> <div class="preview--content--inner"> <div class="field-item"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/2017-12/v2-Desktop-a.png" width="1920" height="5000" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> </div> </div> </div> </div> </div> <!-- END OUTPUT from 'themes/custom/ssc1/templates/paragraphs/field--paragraph--field-preview.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-additional-images--review-item--default.html.twig * field--expert--paragraph--field-additional-images--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-additional-images.html.twig * field--expert--field-additional-images--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-additional-images.html.twig * field--expert.html.twig * field--ds-field-expert.html.twig * field--paragraph--field-additional-images--review-item.html.twig * field--paragraph--field-additional-images.html.twig * field--paragraph--review-item.html.twig * field--field-additional-images.html.twig * field--image.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> <div class="field-label-above">Additional Images</div> <div class="client-review--additional-images"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2017-12/v2-Desktop-a_0.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2017-12/v2-Desktop-a_0.png?itok=H9zRPgvM" width="184" height="480" alt="Full Design" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2017-12/v2-Desktop-b-red.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2017-12/v2-Desktop-b-red.png?itok=FApfTFKL" width="304" height="480" alt="Red Alternate" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2017-12/v2-Desktop-b-blue-2.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2017-12/v2-Desktop-b-blue-2.png?itok=sG9AjmOE" width="304" height="480" alt="Blue alternate" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> </div> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> </div> </div> <!-- END OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_stacked/foundation-2col-stacked.html.twig' --> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> </div> <div class="client-review--item field__item"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'ds_entity_view' --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'foundation_2col_stacked' --> <!-- FILE NAME SUGGESTIONS: * foundation-2col-stacked--paragraph--411.html.twig * foundation-2col-stacked--paragraph-review-item-default.html.twig * foundation-2col-stacked--paragraph-review-item.html.twig * foundation-2col-stacked--paragraph-default.html.twig * foundation-2col-stacked--paragraph.html.twig x foundation-2col-stacked.html.twig x foundation-2col-stacked.html.twig --> <!-- BEGIN OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_stacked/foundation-2col-stacked.html.twig' --> <div class="row"> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-content-title--review-item--default.html.twig * field--expert--paragraph--field-content-title--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-content-title.html.twig * field--expert--field-content-title--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-content-title.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-content-title--review-item.html.twig * field--paragraph--field-content-title.html.twig * field--paragraph--review-item.html.twig * field--field-content-title.html.twig * field--string.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <h2 class="field-wrapper field field--name-field-content-title field--type-string field--label-inline field__items"> <strong class="field-label field__label">Title</strong> Design 2 </h2> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-version--review-item--default.html.twig * field--expert--paragraph--field-version--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-version.html.twig * field--expert--field-version--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-version.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-version--review-item.html.twig * field--paragraph--field-version.html.twig * field--paragraph--review-item.html.twig * field--field-version.html.twig * field--decimal.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <h3 class="field-wrapper field field--name-field-version field--type-decimal field--label-inline field__items"> <strong class="field-label field__label">Version</strong> 1.00 </h3> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> </div> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-vote--review-item--default.html.twig * field--expert--paragraph--field-vote--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-vote.html.twig * field--expert--field-vote--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-vote.html.twig * field--expert.html.twig * field--ds-field-expert.html.twig * field--paragraph--field-vote--review-item.html.twig * field--paragraph--field-vote.html.twig * field--paragraph--review-item.html.twig * field--field-vote.html.twig * field--voting-api-field.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> <div class="field-label-inline">Vote</div> <drupal-render-placeholder callback="voting_api.lazy_loader:buildForm" arguments="0=fivestar&amp;1=paragraph&amp;2=review_item&amp;3=411&amp;4=vote&amp;5=field_vote&amp;6=a%3A5%3A%7Bs%3A5%3A%22style%22%3Bs%3A7%3A%22default%22%3Bs%3A12%3A%22show_results%22%3Bs%3A1%3A%221%22%3Bs%3A13%3A%22show_own_vote%22%3Bs%3A1%3A%221%22%3Bs%3A8%3A%22readonly%22%3Bi%3A0%3Bs%3A6%3A%22values%22%3Ba%3A0%3A%7B%7D%7D" token="pO6EV7WxXs1_Xe9mL7oAKvc48Ewrgb0In_0wFMI7U3c"></drupal-render-placeholder> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> </div> </div> <div class="row"> <div class="medium-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-preview--review-item--default.html.twig * field--expert--paragraph--field-preview--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-preview.html.twig * field--expert--field-preview--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-preview.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-preview--review-item.html.twig x field--paragraph--field-preview.html.twig * field--paragraph--review-item.html.twig * field--field-preview.html.twig * field--image.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'themes/custom/ssc1/templates/paragraphs/field--paragraph--field-preview.html.twig' --> <div class="field-wrapper paragraph paragraph--type--"> <div class="preview--container"> <div class="preview--content"> <div class="preview--content--inner"> <div class="field-item"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/2017-12/v3-Desktop-a-dark-footer.png" width="1920" height="2696" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> </div> </div> </div> </div> </div> <!-- END OUTPUT from 'themes/custom/ssc1/templates/paragraphs/field--paragraph--field-preview.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-additional-images--review-item--default.html.twig * field--expert--paragraph--field-additional-images--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-additional-images.html.twig * field--expert--field-additional-images--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-additional-images.html.twig * field--expert.html.twig * field--ds-field-expert.html.twig * field--paragraph--field-additional-images--review-item.html.twig * field--paragraph--field-additional-images.html.twig * field--paragraph--review-item.html.twig * field--field-additional-images.html.twig * field--image.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> <div class="field-label-above">Additional Images</div> <div class="client-review--additional-images"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2017-12/v3-Desktop-a-dark-footer_0.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2017-12/v3-Desktop-a-dark-footer_0.png?itok=67ITWBhd" width="342" height="480" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2017-12/v3-Desktop-a-light-footer.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2017-12/v3-Desktop-a-light-footer.png?itok=XptU_kOZ" width="342" height="480" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2017-12/v3-Desktop-b.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2017-12/v3-Desktop-b.png?itok=YNb0h--6" width="342" height="480" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> </div> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> </div> </div> <!-- END OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_stacked/foundation-2col-stacked.html.twig' --> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> </div> <div class="client-review--item field__item"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'ds_entity_view' --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'foundation_2col_stacked' --> <!-- FILE NAME SUGGESTIONS: * foundation-2col-stacked--paragraph--412.html.twig * foundation-2col-stacked--paragraph-review-item-default.html.twig * foundation-2col-stacked--paragraph-review-item.html.twig * foundation-2col-stacked--paragraph-default.html.twig * foundation-2col-stacked--paragraph.html.twig x foundation-2col-stacked.html.twig x foundation-2col-stacked.html.twig --> <!-- BEGIN OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_stacked/foundation-2col-stacked.html.twig' --> <div class="row"> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-content-title--review-item--default.html.twig * field--expert--paragraph--field-content-title--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-content-title.html.twig * field--expert--field-content-title--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-content-title.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-content-title--review-item.html.twig * field--paragraph--field-content-title.html.twig * field--paragraph--review-item.html.twig * field--field-content-title.html.twig * field--string.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <h2 class="field-wrapper field field--name-field-content-title field--type-string field--label-inline field__items"> <strong class="field-label field__label">Title</strong> Design 3 </h2> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-version--review-item--default.html.twig * field--expert--paragraph--field-version--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-version.html.twig * field--expert--field-version--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-version.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-version--review-item.html.twig * field--paragraph--field-version.html.twig * field--paragraph--review-item.html.twig * field--field-version.html.twig * field--decimal.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <h3 class="field-wrapper field field--name-field-version field--type-decimal field--label-inline field__items"> <strong class="field-label field__label">Version</strong> 1.00 </h3> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> </div> <div class="medium-6 small-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-vote--review-item--default.html.twig * field--expert--paragraph--field-vote--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-vote.html.twig * field--expert--field-vote--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-vote.html.twig * field--expert.html.twig * field--ds-field-expert.html.twig * field--paragraph--field-vote--review-item.html.twig * field--paragraph--field-vote.html.twig * field--paragraph--review-item.html.twig * field--field-vote.html.twig * field--voting-api-field.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> <div class="field-label-inline">Vote</div> <drupal-render-placeholder callback="voting_api.lazy_loader:buildForm" arguments="0=fivestar&amp;1=paragraph&amp;2=review_item&amp;3=412&amp;4=vote&amp;5=field_vote&amp;6=a%3A5%3A%7Bs%3A5%3A%22style%22%3Bs%3A7%3A%22default%22%3Bs%3A12%3A%22show_results%22%3Bs%3A1%3A%221%22%3Bs%3A13%3A%22show_own_vote%22%3Bs%3A1%3A%221%22%3Bs%3A8%3A%22readonly%22%3Bi%3A0%3Bs%3A6%3A%22values%22%3Ba%3A0%3A%7B%7D%7D" token="9b1IQne-Utna1d0gUij5urK3tK5uEBG7g1vi0uSFTNE"></drupal-render-placeholder> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> </div> </div> <div class="row"> <div class="medium-12 columns"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-preview--review-item--default.html.twig * field--expert--paragraph--field-preview--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-preview.html.twig * field--expert--field-preview--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-preview.html.twig * field--expert.html.twig * field--theme-ds-field-expert.html.twig * field--paragraph--field-preview--review-item.html.twig x field--paragraph--field-preview.html.twig * field--paragraph--review-item.html.twig * field--field-preview.html.twig * field--image.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'themes/custom/ssc1/templates/paragraphs/field--paragraph--field-preview.html.twig' --> <div class="field-wrapper paragraph paragraph--type--"> <div class="preview--container"> <div class="preview--content"> <div class="preview--content--inner"> <div class="field-item"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/2017-12/v1-Desktop-a.png" width="1920" height="4000" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> </div> </div> </div> </div> </div> <!-- END OUTPUT from 'themes/custom/ssc1/templates/paragraphs/field--paragraph--field-preview.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-additional-images--review-item--default.html.twig * field--expert--paragraph--field-additional-images--review-item.html.twig * field--expert--paragraph--review-item.html.twig * field--expert--paragraph--field-additional-images.html.twig * field--expert--field-additional-images--review-item.html.twig * field--expert--review-item.html.twig * field--expert--field-additional-images.html.twig * field--expert.html.twig * field--ds-field-expert.html.twig * field--paragraph--field-additional-images--review-item.html.twig * field--paragraph--field-additional-images.html.twig * field--paragraph--review-item.html.twig * field--field-additional-images.html.twig * field--image.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> <div class="field-label-above">Additional Images</div> <div class="client-review--additional-images"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_formatter' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> <a href="https://test.scottsawyerconsulting.com/sites/default/files/2017-12/v1-Desktop-a_0.png"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image_style' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'image' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <img src="/sites/default/files/styles/large/public/2017-12/v1-Desktop-a_0.png?itok=WkwDU-KD" width="230" height="480" alt="" typeof="foaf:Image" /> <!-- END OUTPUT from 'core/themes/stable/templates/field/image.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-style.html.twig' --> </a> <!-- END OUTPUT from 'core/themes/stable/templates/field/image-formatter.html.twig' --> </div> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-field-expert.html.twig' --> </div> </div> <!-- END OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_stacked/foundation-2col-stacked.html.twig' --> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> </div> </div> <div class="row"> <div class="medium-12 columns"></div> </div> <div class="row"> <div class="medium-6 small-12 columns"> </div> <div class="medium-6 small-12 columns"> </div> </div> <div class="row"> <div class="medium-12 columns"></div> </div> <!-- END OUTPUT from 'themes/contrib/zurb_foundation/layouts/foundation_2col_bricks/foundation-2col-bricks.html.twig' --> <!-- END OUTPUT from 'modules/contrib/ds/templates/ds-entity-view.html.twig' --> Fri, 22 Dec 2017 23:28:43 +0000 admin 122 at https://test.scottsawyerconsulting.com https://test.scottsawyerconsulting.com/node/122#comments WordPress as a Social Media manager https://test.scottsawyerconsulting.com/blog/WordPress-Social-Media-manager <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--title--blog--rss.html.twig * field--node--title--blog.html.twig x field--node--title.html.twig * field--node--blog.html.twig * field--title.html.twig * field--string.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <span class="field-wrapper">WordPress as a Social Media manager</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--uid--blog--rss.html.twig * field--node--uid--blog.html.twig x field--node--uid.html.twig * field--node--blog.html.twig * field--uid.html.twig * field--entity-reference.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <span class="field-wrapper"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'username' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> <span lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="">admin</span> <!-- END OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> </span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--created--blog--rss.html.twig * field--node--created--blog.html.twig x field--node--created.html.twig * field--node--blog.html.twig * field--created.html.twig * field--created.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <span class="field-wrapper">Mon, 05/29/2017 - 23:03</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'links__node' --> <!-- FILE NAME SUGGESTIONS: * links--node.html.twig x links.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--body--blog--rss.html.twig * field--node--body--blog.html.twig * field--node--body.html.twig * field--node--blog.html.twig * field--body.html.twig * field--text-with-summary.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper body field field--name-body field--type-text-with-summary field--label-hidden field__items"> <div class="field__item"> <p>WordPress can be a powerful, flexible platform, and there are many little tricks that can be used to extend it's capabilities well beyond what you might expect.  In this post, I am going to share how we use WordPress to manage social media content.</p> <p>When a customer wants us to manage their social media content, posting updates on their behalf, the process of creating the posts, submitting the posts for approval, receiving edits, and loading them into a platform such as Hootsuite can be tedious, often involving a lot of forwarding of emails with attachments.  Sometimes it's challenging to determine which attachment is the most current, if it's been approved by all of the respective parties, etc.</p> <p>Obviously, this is error-prone, inefficient, and just plain ugly.  </p> <p>Now, before you bite my head off and start trying to tell me about all of the great tools out there that might make this easier, there are a few advantages to the process I am about to describe.</p> <ol><li>The customer already has the Website. ( btw, this process can work with just about any CMS )</li> <li>The customer already has a login.  ( never underestimate the value of limiting the number of logins a customer needs to manage )</li> <li>The customer is already familiar with WordPress ( or whatever they are currently using ).</li> <li>WordPress has a decent editorial workflow. ( Drafts, Pending Review, Revisions, etc )</li> </ol><p>So, for us, it makes a lot of sense to leverage the tools our customers already have, use, and are comfortable with.</p> <h2>The Basic Idea</h2> <p>The ideas here are applicable to most CMS platforms, it just so happens for a majority of our marketing customers, WordPress is already in place.  What we want to do is generate an RSS feed that will be picked up by Hootsuite ( or whatever platform you like, provided it supports pulling RSS feeds ).  </p> <ol><li>We create a custom post type that we load up with the social media content, setting each post as a draft.  Optionally, we can set a post date to some optimal time for the post to be picked up.</li> <li>The customer logs in, edits the post, and when satisfied, publishes the post.</li> <li>We connect the RSS feed to Hootsuite, and assign it to a social media network.</li> <li>Magic happens!</li> </ol><p>As you can see, overall, this is a very basic workflow, but it can take a lot of the pain out of managing a customer's social media content.</p> <h2>Custom Post Type</h2> <p>For our setup, we make a really simple custom post type.  If you are not familiar with custom post types, I encourage you to read up on it in the<a href="https://codex.wordpress.org/Post_Types"> WordPress Codex</a>. If you are not using custom post types, you are likely missing a lot of opportunities to make much better WordPress sites.  </p> <p>There are many ways to create a custom post type in WordPress, a simple code snippet in your theme's function.php file is the most straightforward way and will likely be sufficient for our purposes, though it is<a href="https://codex.wordpress.org/Post_Types#A_word_about_custom_post_types_as_a_plugin"> recommended to create your post types as a plugin</a>.  You could use something like this:</p> <pre> <code class="language-php">&lt;?php add_action( 'init', 'create_post_type' ); function create_post_type() { register_post_type( 'social_media', array( 'labels' =&gt; array( 'name' =&gt; __( 'Social Media' ), 'singular_name' =&gt; __( 'Social Media' ) ), 'public' =&gt; false, 'has_archive' =&gt; false,   'rewrite' =&gt; array('slug' =&gt; 'social-media'), ) ); } ?&gt;</code></pre> <p>The important parts here are the fact that the post type is not public, and doesn't have an archive.  </p> <p>While this is a good start, it doesn't quite have all of the features we'll use.  I recommend reading up on<a href="https://codex.wordpress.org/Function_Reference/register_post_type"> register_post_type()</a> to learn about the types of options that are available.  For instance, we also disable the title field and use page capabilities, not really necessary, but it cleans up the post edit screen a little.</p> <p>Again, everything we're going to discuss you can do with little code snippets like this, and there are even some plugins that can help you create custom post types.  We use our own plugin, WP Builder, because it has a simple UI for creating post types and adding some of these features with absolutely no additional code.  </p> <h2>Custom Taxonomy</h2> <p>Now that we have our post type configured, we want a little more control over which social network a post will eventually be posted on.  For this, we use a custom taxonomy.  If you have never heard of a taxonomy, it's simply a way of classifying things.  Categories and Tags are examples of taxonomies, and you can read more about <a href="https://codex.wordpress.org/Taxonomies">Taxonomies as they relate to WordPress in the Codex</a>.  </p> <p>What we want is a set of terms that correlate to each social network we are going to post to.  This way, Facebook posts go only to Facebook, Twitter to Twitter, etc.  As with anything, there are multiple ways to achieve this, but as we'll see later, using Taxonomies provides some additional benefit.</p> <p>To create a custom taxonomy, you can add a snippet to your theme or in a plugin ( as stated, plugins are preferred ), or an existing plugin ( WP Builder in our case ).</p> <pre> <code class="language-php">&lt;?php function social_networks_init() { // create a new taxonomy register_taxonomy( 'social_network', 'social_media', array( 'label' =&gt; __( 'Social Network' ), 'rewrite' =&gt; array( 'slug' =&gt; 'social-network' ), 'capabilities' =&gt; array( 'assign_terms' =&gt; 'edit_social_network', 'edit_terms' =&gt; 'publish_social_network' ) ) ); } add_action( 'init', 'social_networks_init' ); ?&gt;</code></pre> <p>Like register_post_type(), <a href="https://codex.wordpress.org/Function_Reference/register_taxonomy">register_taxonomy() has a plethora of options</a> that you should read through.  </p> <p>Now we have a taxonomy, let's add a couple of terms ( or Social Networks ):</p> <ul><li>Facebook ( slug = facebook )</li> <li>Twitter ( slug = twitter )</li> <li>Google Plus ( slug = gplus )</li> </ul><p><img alt="Image removed." data-entity-type="file" data-entity-uuid="f57b393a-c1c2-482f-a014-c81d6a689754" src="/sites/default/files/inline-images/social-networks-wordpress.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /></p> <p>What you name your terms is ultimately not so important, they are just labels that we'll use to identify specific posts.  If you have 3 Twitter accounts, you could name them "twitter_1", "twitter_2", "twitter_3", for instance.  As long as you know which accounts each term represents, you are good.</p> <h2>Creating Social Media Content</h2> <p>Now we have a custom post type, Social Media, and custom taxonomy, Social Network, it's time to create some posts.  </p> <p>Depending on how you configured your post type, you should have a menu on you WordPress Dashboard navigation that looks a bit like this:</p> <p><img alt="Image removed." data-entity-type="file" data-entity-uuid="488e4970-86e3-49c0-a148-103930f6a157" src="/sites/default/files/inline-images/social-media-menu.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /></p> <p>When you click "Add New", your screen might look like this ( note: this site has some other plugins for SEO ):</p> <p><img alt="Image removed." data-entity-type="file" data-entity-uuid="d066a82c-b3e6-4992-8d31-51c6620c1bf2" src="/sites/default/files/inline-images/social-media-edit-screen.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /></p> <p>You might notice I have the Text tab active.  The reason for this is because I do not want any HTML in my post content.  Really, I should disable the editor to prevent any mistakes, but I will show you how I handle this later.</p> <p>After you create your post, you can set it to Draft, adjust the post date, whatever your workflow calls for.  But you will notice a side effect when you return to the Social Media page.</p> <p><img alt="Image removed." data-entity-type="file" data-entity-uuid="72600514-7bab-4ce6-b75e-bd3eb84333d6" src="/sites/default/files/inline-images/social-media-overview.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /></p> <p>WordPress requires a title for every post.  If you ask me ( and no one has ), this is a stupid design feature, I should be able to create whatever structure for content that I please.  However, the good folks who built WordPress probably never envisioned this particular use-case, so there it is.  Every post gets a default title, "Auto Draft".  If this really bothers you, there are a couple of options:</p> <ol><li>Enable the "Title" field on your custom post type ( just keep in mind, we won't be using it in our feed )</li> <li>Use a post_save hook to automatically write in a title that you like better.</li> <li>Something awesome I haven't thought of yet.</li> </ol><p>Personally, I think this screen is fine if I educate my customer about how to use it.  Click Auto Draft to view the content, publish when ready.  Easy stuff.</p> <h2>Accessing the RSS Feeds</h2> <p>A cool feature of WordPress is it's powerful RSS capability.  The default feed just contains posts, which is great, but other post types are accessible through some nifty URL parameters.</p> <p>We can access our published Social Media posts at something like:</p> <blockquote> <p>http://example.com/feed/?post_type=social_media</p> </blockquote> <p>This will show every published social media post on our site.  Which is nice, but not quite what we need.  What we want is a separate feed for each social network.   And WordPress makes this easy as well.</p> <p>This is where creating a custom taxonomy really pays off.  By adding the parameter "taxonomy=social_network", we are telling WordPress that we want to filter the feed using our custom taxonomy, Social Network.  Then we add the slug for each social network, in this case, generating 3 separate feeds.  </p> <ul><li>http://example.com/feed/?post_type=social_media&amp;taxonomy=social_network&amp;social_network=twitter</li> <li>http://example.com/feed/?post_type=social_media&amp;taxonomy=social_network&amp;social_network=facebook</li> <li>http://example.com/feed/?post_type=social_media&amp;taxonomy=social_network&amp;social_network=gplus</li> </ul><p>So, what does this look like?</p> <p><img alt="Image removed." data-entity-type="file" data-entity-uuid="bad5f3bb-6519-4226-a70e-c56a7e8917b0" src="/sites/default/files/inline-images/social-media-feed-1.png" title="This image has been removed. For security reasons, only images from the local domain are allowed." height="16" width="16" class="filter-image-invalid" /></p> <p>That is a lot of code!  </p> <p>We are now able to access just the posts for the specific social network we want!</p> <h2>Altering the WordPress Feed</h2> <p>However, we have a problem, Hootsuite doesn't use the &lt;description&gt; or &lt;content:encoded&gt;, which is where the content of our social media posts live.  Instead, it uses only the title and date fields.  This bites, because now we have to alter the feed to show our content in the title.  Otherwise, every social media post will just have Auto Draft!  Pretty terrible.</p> <p>Fortunately, <a href="https://codex.wordpress.org/Customizing_Feeds">altering the Feed template isn't the most challenging of tasks</a>.  But it's a bit tedious, so bare with me.  There are 3 steps to make the feed output in such a way that Hootsuite will post what we want.</p> <ol><li>Create a new Feed template.</li> <li>Alter the content so it will validate, even if someone adds HTML to the post.</li> <li>Tell WordPress to use our new template for our Social Media posts only.</li> </ol><h3>Create a new Feed template</h3> <p>The core of what we are going to do here is fairly straight forward, we're going to copy the WordPress template and make some changes.  The core WordPress RSS2 template ( and we want RSS2 ) is located at /wp-includes/feed-rss2.php, copy it into your theme or plugin, something like /feed/feed-social_media_rss2.php.</p> <p>This what you will have:</p> <pre> <code class="language-php">&lt;?php /**  * RSS2 Feed Template for displaying RSS2 Posts feed.  *  * @package WordPress  */ header('Content-Type: ' . feed_content_type('rss2') . '; charset=' . get_option('blog_charset'), true); $more = 1; echo '&lt;?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'&gt;'; /**  * Fires between the xml and rss tags in a feed.  *  * @since 4.0.0  *  * @param string $context Type of feed. Possible values include 'rss2', 'rss2-comments',  *                        'rdf', 'atom', and 'atom-comments'.  */ do_action( 'rss_tag_pre', 'rss2' ); ?&gt; &lt;rss version="2.0"     xmlns:content="http://purl.org/rss/1.0/modules/content/"     xmlns:wfw="http://wellformedweb.org/CommentAPI/"     xmlns:dc="http://purl.org/dc/elements/1.1/"     xmlns:atom="http://www.w3.org/2005/Atom"     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"     xmlns:slash="http://purl.org/rss/1.0/modules/slash/"     &lt;?php     /**      * Fires at the end of the RSS root to add namespaces.      *      * @since 2.0.0      */     do_action( 'rss2_ns' );     ?&gt; &gt; &lt;channel&gt;     &lt;title&gt;&lt;?php wp_title_rss(); ?&gt;&lt;/title&gt;     &lt;atom:link href="&lt;?php self_link(); ?&gt;" rel="self" type="application/rss+xml" /&gt;     &lt;link&gt;&lt;?php bloginfo_rss('url') ?&gt;&lt;/link&gt;     &lt;description&gt;&lt;?php bloginfo_rss("description") ?&gt;&lt;/description&gt;     &lt;lastBuildDate&gt;&lt;?php         $date = get_lastpostmodified( 'GMT' );         echo $date ? mysql2date( 'D, d M Y H:i:s +0000', $date, false ) : date( 'D, d M Y H:i:s +0000' );     ?&gt;&lt;/lastBuildDate&gt;     &lt;language&gt;&lt;?php bloginfo_rss( 'language' ); ?&gt;&lt;/language&gt;     &lt;sy:updatePeriod&gt;&lt;?php         $duration = 'hourly';         /**          * Filters how often to update the RSS feed.          *          * @since 2.1.0          *          * @param string $duration The update period. Accepts 'hourly', 'daily', 'weekly', 'monthly',          *                         'yearly'. Default 'hourly'.          */         echo apply_filters( 'rss_update_period', $duration );     ?&gt;&lt;/sy:updatePeriod&gt;     &lt;sy:updateFrequency&gt;&lt;?php         $frequency = '1';         /**          * Filters the RSS update frequency.          *          * @since 2.1.0          *          * @param string $frequency An integer passed as a string representing the frequency          *                          of RSS updates within the update period. Default '1'.          */         echo apply_filters( 'rss_update_frequency', $frequency );     ?&gt;&lt;/sy:updateFrequency&gt;     &lt;?php     /**      * Fires at the end of the RSS2 Feed Header.      *      * @since 2.0.0      */     do_action( 'rss2_head');     while( have_posts()) : the_post();     ?&gt;     &lt;item&gt;         &lt;title&gt;&lt;?php the_title_rss() ?&gt;&lt;/title&gt;         &lt;link&gt;&lt;?php the_permalink_rss() ?&gt;&lt;/link&gt; &lt;?php if ( get_comments_number() || comments_open() ) : ?&gt;         &lt;comments&gt;&lt;?php comments_link_feed(); ?&gt;&lt;/comments&gt; &lt;?php endif; ?&gt;         &lt;pubDate&gt;&lt;?php echo mysql2date('D, d M Y H:i:s +0000', get_post_time('Y-m-d H:i:s', true), false); ?&gt;&lt;/pubDate&gt;         &lt;dc:creator&gt;&lt;![CDATA[&lt;?php the_author() ?&gt;]]&gt;&lt;/dc:creator&gt;         &lt;?php the_category_rss('rss2') ?&gt;         &lt;guid isPermaLink="false"&gt;&lt;?php the_guid(); ?&gt;&lt;/guid&gt; &lt;?php if (get_option('rss_use_excerpt')) : ?&gt;         &lt;description&gt;&lt;![CDATA[&lt;?php the_excerpt_rss(); ?&gt;]]&gt;&lt;/description&gt; &lt;?php else : ?&gt;         &lt;description&gt;&lt;![CDATA[&lt;?php the_excerpt_rss(); ?&gt;]]&gt;&lt;/description&gt;     &lt;?php $content = get_the_content_feed('rss2'); ?&gt;     &lt;?php if ( strlen( $content ) &gt; 0 ) : ?&gt;         &lt;content:encoded&gt;&lt;![CDATA[&lt;?php echo $content; ?&gt;]]&gt;&lt;/content:encoded&gt;     &lt;?php else : ?&gt;         &lt;content:encoded&gt;&lt;![CDATA[&lt;?php the_excerpt_rss(); ?&gt;]]&gt;&lt;/content:encoded&gt;     &lt;?php endif; ?&gt; &lt;?php endif; ?&gt; &lt;?php if ( get_comments_number() || comments_open() ) : ?&gt;         &lt;wfw:commentRss&gt;&lt;?php echo esc_url( get_post_comments_feed_link(null, 'rss2') ); ?&gt;&lt;/wfw:commentRss&gt;         &lt;slash:comments&gt;&lt;?php echo get_comments_number(); ?&gt;&lt;/slash:comments&gt; &lt;?php endif; ?&gt; &lt;?php rss_enclosure(); ?&gt;     &lt;?php     /**      * Fires at the end of each RSS2 feed item.      *      * @since 2.0.0      */     do_action( 'rss2_item' );     ?&gt;     &lt;/item&gt;     &lt;?php endwhile; ?&gt; &lt;/channel&gt; &lt;/rss&gt; ?&gt;</code></pre> <p><br />  </p> <p>The parts we care about are in the &lt;item&gt; tag.  What we want is to change &lt;title&gt; from &lt;?php the_title_rss() ?&gt; to &lt;?php echo $content; ?&gt;.  To do this, we need to move &lt;?php $content = get_the_content_feed('rss2'); ?&gt; above the &lt;title&gt; tag.</p> <p>Another annoying thing that Hootsuite does that is automatically include the &lt;link&gt; tag.  WordPress populates this tag with a link to the original post, which is exactly what we don't want.  Unfortunately, without the link tag, Hootsuite will not accept your feed.  We have a couple of options here.</p> <ul><li>Hardcode a link, maybe point it at your customer's Website home page.</li> <li>Populate it dynamically.</li> </ul><p>Setting the link dynamically gives you ( or your customer ) the option of providing a custom link for each post. For populating it dynamically, you could use a custom field.  To use custom fields, you need to ensure your post type has custom fields enabled.  The plugin Advanced Custom Fields is another option.  We, again, turn to our WP Builder plugin which makes adding metaboxes and fields very easy, but that is another post for another time.  The point here is, you need a link, so ensure some link is included, and the link will be included in every post.</p> <p>I have removed a few features from the feed, like links to the comments, which I don't need.  Here is my final template:</p> <pre> <code class="language-php">&lt;?php /**  * RSS2 Feed Template for displaying RSS2 Posts feed.  *  * @package WordPress  */ header('Content-Type: ' . feed_content_type('rss2') . '; charset=' . get_option('blog_charset'), true); $more = 1; echo '&lt;?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'&gt;'; /**  * Fires between the xml and rss tags in a feed.  *  * @since 4.0.0  *  * @param string $context Type of feed. Possible values include 'rss2', 'rss2-comments',  *                        'rdf', 'atom', and 'atom-comments'.  */ do_action( 'rss_tag_pre', 'rss2' ); ?&gt; &lt;rss version="2.0"     xmlns:content="http://purl.org/rss/1.0/modules/content/"     xmlns:wfw="http://wellformedweb.org/CommentAPI/"     xmlns:dc="http://purl.org/dc/elements/1.1/"     xmlns:atom="http://www.w3.org/2005/Atom"     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"     xmlns:slash="http://purl.org/rss/1.0/modules/slash/"     &lt;?php     /**      * Fires at the end of the RSS root to add namespaces.      *      * @since 2.0.0      */     do_action( 'rss2_ns' );     ?&gt; &gt; &lt;channel&gt;     &lt;title&gt;&lt;?php wp_title_rss(); ?&gt;&lt;/title&gt;     &lt;atom:link href="&lt;?php self_link(); ?&gt;" rel="self" type="application/rss+xml" /&gt;     &lt;link&gt;&lt;?php bloginfo_rss('url') ?&gt;&lt;/link&gt;     &lt;description&gt;&lt;?php bloginfo_rss("description") ?&gt;&lt;/description&gt;     &lt;lastBuildDate&gt;&lt;?php         $date = get_lastpostmodified( 'GMT' );         echo $date ? mysql2date( 'D, d M Y H:i:s +0000', $date, false ) : date( 'D, d M Y H:i:s +0000' );     ?&gt;&lt;/lastBuildDate&gt;     &lt;language&gt;&lt;?php bloginfo_rss( 'language' ); ?&gt;&lt;/language&gt;     &lt;sy:updatePeriod&gt;&lt;?php         $duration = 'hourly';         /**          * Filters how often to update the RSS feed.          *          * @since 2.1.0          *          * @param string $duration The update period. Accepts 'hourly', 'daily', 'weekly', 'monthly',          *                         'yearly'. Default 'hourly'.          */         echo apply_filters( 'rss_update_period', $duration );     ?&gt;&lt;/sy:updatePeriod&gt;     &lt;sy:updateFrequency&gt;&lt;?php         $frequency = '1';         /**          * Filters the RSS update frequency.          *          * @since 2.1.0          *          * @param string $frequency An integer passed as a string representing the frequency          *                          of RSS updates within the update period. Default '1'.          */         echo apply_filters( 'rss_update_frequency', $frequency );     ?&gt;&lt;/sy:updateFrequency&gt;     &lt;?php     /**      * Fires at the end of the RSS2 Feed Header.      *      * @since 2.0.0      */     do_action( 'rss2_head');     while( have_posts()) : the_post();     ?&gt;     &lt;item&gt;     &lt;?php $content = get_the_content_feed('rss2'); ?&gt;       &lt;title&gt;&lt;?php echo example_alter_content_feed( $content ); ?&gt;&lt;/title&gt;       &lt;link&gt;&lt;?php echo get_post_meta( get_the_ID(), '_wp_builder_social_media_post_settings_link', true ); ?&gt;&lt;/link&gt;         &lt;pubDate&gt;&lt;?php echo mysql2date('D, d M Y H:i:s +0000', get_post_time('Y-m-d H:i:s', true), false); ?&gt;&lt;/pubDate&gt;         &lt;?php the_category_rss('rss2') ?&gt;     &lt;guid isPermaLink="false"&gt;&lt;?php the_guid(); ?&gt;&lt;/guid&gt;          &lt;?php if (get_option('rss_use_excerpt')) : ?&gt;         &lt;description&gt;&lt;![CDATA[&lt;?php the_excerpt_rss(); ?&gt;]]&gt;&lt;/description&gt; &lt;?php else : ?&gt;         &lt;description&gt;&lt;![CDATA[&lt;?php the_excerpt_rss(); ?&gt;]]&gt;&lt;/description&gt;     &lt;?php if ( strlen( $content ) &gt; 0 ) : ?&gt;         &lt;content:encoded&gt;&lt;![CDATA[&lt;?php echo $content; ?&gt;]]&gt;&lt;/content:encoded&gt;     &lt;?php else : ?&gt;         &lt;content:encoded&gt;&lt;![CDATA[&lt;?php the_excerpt_rss(); ?&gt;]]&gt;&lt;/content:encoded&gt;     &lt;?php endif; ?&gt; &lt;?php endif; ?&gt; &lt;?php rss_enclosure(); ?&gt;     &lt;?php     /**      * Fires at the end of each RSS2 feed item.      *      * @since 2.0.0      */     do_action( 'rss2_item' );     ?&gt;     &lt;/item&gt;     &lt;?php endwhile; ?&gt; &lt;/channel&gt; &lt;/rss&gt; ?&gt;</code></pre> <p>Two funky things here:</p> <ul><li>how my &lt;link&gt; tag is populated, which is how to access fields from our WP Builder plugin. </li> <li>a wrapper function example_alter_content_feed(), which I use to alter the content.</li> </ul><p>Also, a good idea when you are customizing your RSS template, use the <a href="https://validator.w3.org/feed/">W3C RSS validator</a>.</p> <h3>Alter the Feed Content</h3> <p>If you recall, our post edit screen in WordPress had the WYSIWYG editor, and even though I switched to Text, you can still get HTML tags in the content.  If you have HTML in your Title tag, it will not validate.  Also, social networks will convert any HTML to entities, making the tags visible in the posts, which is not cool.  </p> <p>What we want to do is strip any HTML from our content.  For that I created the wrapper function example_alter_content_feed().  I only call this function in the new custom template so it won't affect other RSS feeds on the site.</p> <pre> <code class="language-php">&lt;?php function example_alter_content_feed( $content ) {   $content = strip_tags( $content );   return $content; } ?&gt;</code></pre> <p>Very simple?  You could do more with it, like include a Twitter handle or some custom text that you want to appear in each post.  Bottom line, this fixes problems with how Hootsuite handles your RSS feed.</p> <h3>Tell WordPress to use the Template</h3> <p>This is pretty simple, in your plugin or theme, add this bit of code ( <a href="https://codex.wordpress.org/Customizing_Feeds">taken from WordPress Codex</a> )</p> <pre> <code class="language-php">&lt;?php remove_all_actions( 'do_feed_rss2' ); add_action( 'do_feed_rss2', 'social_media_feed_rss2' ); function social_media_feed_rss2( $for_comments ) {   $rss_template = get_template_directory() . 'feed/feed-social_media-rss2.php';   if ( get_query_var( 'post_type' ) == 'social_media' and file_exists( $rss_template ) )     load_template( $rss_template );   else      do_feed_rss2( $for_comments ); } ?&gt;</code></pre> <p>All this does is check for whether we're trying to get the Social Media RSS feed, and loading our custom template.</p> <p>You should now test the three RSS feeds, make sure they are loading the proper templates, make sure they validate.  </p> <h2>Add Your Feeds to Hootsuite</h2> <p>Now you are ready to add the feeds to Hootsuite.  This is pretty simple, and there are lot's of <a href="https://blog.hootsuite.com/hoottip-how-to-set-up-your-rss-feed-in-hootsuite/">guides directly from Hootsuite</a>.  The important part is to make sure you assign the proper feed to the corresponding network.  You can also custom text to the feed through Hootsuite, but it is very basic.  I think it's easier to control on your end in WordPress.</p> <h2>Conclusion</h2> <p>RSS is a really powerful, and in my opinion, often overlooked resource.  We looked at just one way using RSS can make our lives just a bit easier.  We took the humble RSS feed and turned it into a super-charged social media workflow manager.  </p> <p>As a marketer, understanding the tools at your disposal and making them work for your clients is a critical part of the trade.  WordPress gives you a lot, if you know how to customize it.  Rather than burden your customers with yet another tool, better leverage the tools you have.</p> <p> </p> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-tags--blog--rss.html.twig * field--node--field-tags--blog.html.twig * field--node--field-tags.html.twig * field--node--blog.html.twig * field--field-tags.html.twig * field--entity-reference.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper field field--name-field-tags field--type-entity-reference field--label-above field__items"> <div class="field-label field__label">Tags</div> <div class="field__item"> <a href="/taxonomy/term/44" hreflang="en"> WordPress</a> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> Tue, 30 May 2017 03:03:45 +0000 admin 119 at https://test.scottsawyerconsulting.com Server Based Development https://test.scottsawyerconsulting.com/blog/Server-Based-Development <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--title--blog--rss.html.twig * field--node--title--blog.html.twig x field--node--title.html.twig * field--node--blog.html.twig * field--title.html.twig * field--string.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <span class="field-wrapper">Server Based Development</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--uid--blog--rss.html.twig * field--node--uid--blog.html.twig x field--node--uid.html.twig * field--node--blog.html.twig * field--uid.html.twig * field--entity-reference.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <span class="field-wrapper"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'username' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> <span lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="">admin</span> <!-- END OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> </span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--created--blog--rss.html.twig * field--node--created--blog.html.twig x field--node--created.html.twig * field--node--blog.html.twig * field--created.html.twig * field--created.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <span class="field-wrapper">Wed, 03/01/2017 - 22:26</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'links__node' --> <!-- FILE NAME SUGGESTIONS: * links--node.html.twig x links.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- END OUTPUT from 'core/themes/stable/templates/navigation/links.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--body--blog--rss.html.twig * field--node--body--blog.html.twig * field--node--body.html.twig * field--node--blog.html.twig * field--body.html.twig * field--text-with-summary.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper body field field--name-body field--type-text-with-summary field--label-hidden field__items"> <div class="field__item"> <p>Modern development can be a complicated process, between build tools, deployment management, dependency management, version control, etc.  There are a lot of options out there, and we've spent a reasonable amount of time evaluating existing options and creating a process that works for us, for now.  In the end we reached the conclusion that a server-based development process works for us.  This post explains some of our challenges with other popular workflows, how a server-based workflow solves several of these challenges, and gives some insight about how our process works.</p> <h2>Local Development</h2> <p>The most common alternative that I am aware of is local development (duh), which generally involves running some local server(s) installed on a computes.  Vargrant is a popular option, giving the developer access to a variety of development environments with a simple command "vagrant up".  There are other options for local development, some purpose built solutions, like Aquia's Dev Desktop, primarily aimed at Drupal development, and even some IDE's include some basic internal server capabilities.  </p> <p>For our situation, local development presents some challenges.  I'll go more in depth into each of these.</p> <ul><li>Local servers often don't look like production servers.</li> <li>Spinning up a new project or switching quickly between projects is either slow or uses a lot of disk space.</li> <li>It's more difficult to get multiple sets of eyes on a problem.</li> </ul><h3>Local Server Differences</h3> <p>Solutions like Dev Desktop ship with a particular configuration.  In Dev Desktop, Apache is the server.  Well, we deploy to Nginx.  For basic coding, it doesn't really matter, but there are subtle differences that can affect your deployment if they haven't been addressed.  I don't know if it's possible to configure Dev Desktop to use Nginx locally, but that is not really what I need to do with my time.  </p> <p>One might argue that Vagrant can solve this problem, because when using Vagrant, you can configure your local environment exactly like your production server.  That may be true, but that also means one might need to spend a significant amount of time tweaking your Vagrant configuration to get it as close as possible to production.  We don't have a "dev ops" team in-house ( though, Kyle might argue that point ), so spending a lot of time working out Vagrant configurations is time we're not writing code.</p> <p>There is also the challenge that once you deploy to the Web, you have a host of new considerations that you don't have in local development.  Network latency, SSL certs, CORS, etc, can all work differently on a local box than on a live server living on the Web.</p> <h3>Project Switching</h3> <p>I think a lot of development workflows have been defined by large companies where developers might spend the bulk of their time working on a small number of projects at any given time.  In such a case, using a local server makes a ton of sense.  We, on the other hand, tend to jump back and forth between projects, often multiple times in a single day.</p> <p>Setting up a Vagrant box takes a fair amount of your local resource, usually there is an operating system image with RAM and disk space allocated to each box you need to run.  Even when idle, those Vagrant boxes are soaking up disk space, maybe to the tune of 20 GB each.  To get through a week's work, I would need 10 - 15 boxes ready to go at any given time, the problem is, I don't know which 10-15.  So to cover my bases, I would want somewhere around 30-40 boxes at the ready.</p> <p>Essentially, I see three options:</p> <ol><li>Keep a box on your local computer for every site that we've ever built, or</li> <li>Every time I need to work on a different project, install configured box, or</li> <li>Reuse one or two boxes and just wipe the current project and clone the repo for the next project.</li> </ol><p>The first one doesn't make a lot of sense once you've built more than about 50 sites.  Using up more than 100gb of local storage with servers that aren't getting updated regularly doesn't make sense to me.  </p> <p>The second option could make more sense, store a project's Vagrant config in git and spin up a new box to work on a project.  But the process is slow, maybe taking longer to spin up the environment than the actual dev time might take.</p> <p>Option three might be the best option, if you kept a fairly generic Vagrant box ( like, just a LEMP stack and some basic tools ) and just clone the repo of the project that needs attention.  But then, you run the risk of making a change that just doesn't work the same way in your production environment.  Overall, it's probably the best for making small changes from time to time.</p> <h3>Collaboration</h3> <p>How many times have you worked on a problem and just needed someone else to look at it to tell you that you missed a semicolon?  Hate to admit it, happens to me all the time.  Well, if you are working locally, that simple collaboration is really hard with a remote team.  </p> <p>What does that process look like?  Commit broken code, get the other person to clone your broken code ( maybe needs to spin up a box just to see what is happening ), explain how to recreate your issue, etc.  Sounds inefficient to me.</p> <h2>Remote Development</h2> <p>Before I get into how remote development solves some of these problems for us, I want to explain how we got here.  </p> <p>When we started building Websites, we had no corporate experience.  All of our tools and practices grew from trial and error, reading blogs, etc.  When we needed to work on a site, we would fire up an FTP client, download a file or two, upload, and cross our fingers.  Ok, bad.  Can't tell you how many times I broke something and started sweating.  </p> <p>Back then, we primarily deployed to shared hosts, and mostly on one provider.  Configuration didn't really matter, we knew what we were dealing with.  And most of our projects were very small, even when we totally borked something, we could fix it in a few minutes and know one would ever know the site was offline for 30 minutes.</p> <p>Now, our projects are bigger, the demands and expectations are higher.  We need a high degree of confidence that our code is going to work before deploying.  We typically deploy to VPS now, and configuration matters.</p> <p>Our process usually looks something like this.  </p> <ul><li>Separate Dev, Staging, and Production environments ( all similarly or identically configured VPS ).</li> <li>Git to manage code and deployment.</li> <li>Work is done over SSH.</li> </ul><p>We use Digital Ocean for most of our production and almost all of our dev work.  With Digital Ocean, we can configure a Production server exactly how we want it, clone the server and spin up an identical Dev environment.  We can store images of each environment so we're not starting from scratch each time, and we can install our dev tools and clone that separately.  </p> <p>For us, this totally solves the problem of managing a bunch of different environments.  Since it's all on Digital Ocean it uses zero local disk space.  </p> <p>It's fast.  I can spin up a full stack from image faster than I can install a new Vagrant box.  And if I mothball an old dev server, I can bring it back up in seconds.  Everything is there as I left it.</p> <p>We configure our VPS environments with everyone on our team's ssh key, so getting help is just a matter of giving out an IP address.</p> <p>There is another benefit for me.  I am often times out of the office, and while I do most of my work on a desktop, when in the field I can use my laptop to work on any project, seamlessly.</p> <h2>How To Develop Remotely</h2> <p>If you are coming from a local development process, there are a few things that you'll want to get somewhat familiar with.</p> <p>Either an FTP client like Filezilla ( remember that? ), or sshfs.  I prefer sshfs.  I don't really bother setting up sFTP on my dev servers, but if you have ssh enabled ( which you almost have to on Digital Ocean ), you can use sshfs to mount the remote file system to your local machine.  Once this is done, you can edit files locally, and when you save, they save directly to the server.</p> <p>Get familiar with the commandline.  I've learned to use the commandline for most everything.  I don't know much about Git clients, since I am always connected to a server, I just "cd" into my project and run commands through the terminal.  </p> <p>A lot of tools you might be accustomed to on your Macbook, may not work so well on the server.  If you want Sass, you need to install it on the server.  Basically, everything lives on the server, so whatever tools you want to use, whether nodejs or xdebug, you need to install it on your dev server.  I run gulp, webpack, whatever, right there on a live server.</p> <p>There can be some latency, depending on your connection.  If you have a fast network, it's not much, just be aware.</p> <h2>Limitations</h2> <p>Obviously I like working this way, or I wouldn't have bothered with this post, but I do have to contend with some limitations.  They aren't show stoppers, for me, but I don't always get to have my cake and eat it too.</p> <p>For starters, some IDEs do not like this workflow.  PHPStorm in particular expects a local dev environment.  I recently download an evaluation version of PHPStorm, I really like the UI, heard such great things, but it demands that I create local projects in order to use it.  I just don't see myself with trying to manage over 100 projects locally.  </p> <p>It does cost money, not much, but multiple servers, server images, etc, has a monthly cost associated with it.  </p> <p>Dev / Staging environments need a little extra consideration.  You don't want a cron job on a dev box sending emails.   For Drupal sites, we use maillog to capture outgoing emails, but everytime we sync the database back to dev, we need to delete the maillog table and re-enable maillog.  It's an extra step, but it's quick.  You just have to remember to do it.</p> <p>You don't want search engines and other bots crawling around. We usually throw an htpasswd file on dev just to keep out the cruft.</p> <p>Overall, there is just a slightly different mindset working on a live server on the Web.  It's liberating, not worrying about my local machine.  It's just a portal to my dev servers.</p> <p> </p> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> Thu, 02 Mar 2017 03:26:44 +0000 admin 112 at https://test.scottsawyerconsulting.com Rick Palmer https://test.scottsawyerconsulting.com/node/108 <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--title--reviews--rss.html.twig * field--node--title--reviews.html.twig x field--node--title.html.twig * field--node--reviews.html.twig * field--title.html.twig * field--string.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <span class="field-wrapper">Rick Palmer</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--title.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--body--reviews--rss.html.twig * field--node--body--reviews.html.twig * field--node--body.html.twig * field--node--reviews.html.twig * field--body.html.twig * field--text-with-summary.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper body field field--name-body field--type-text-with-summary field--label-hidden field__items"> <div class="field__item"> <p>Scott designed my website and has followed up with excellent, timely and efficient support. His company is big enough to get the job done and small enough to know me by name and give me a level of care that I only wish others gave, too.</p> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--uid--reviews--rss.html.twig * field--node--uid--reviews.html.twig x field--node--uid.html.twig * field--node--reviews.html.twig * field--uid.html.twig * field--entity-reference.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <span class="field-wrapper"> <!-- THEME DEBUG --> <!-- THEME HOOK: 'username' --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> <span lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="">admin</span> <!-- END OUTPUT from 'core/themes/stable/templates/user/username.html.twig' --> </span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--uid.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--created--reviews--rss.html.twig * field--node--created--reviews.html.twig x field--node--created.html.twig * field--node--reviews.html.twig * field--created.html.twig * field--created.html.twig * field.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <span class="field-wrapper">Mon, 02/13/2017 - 15:50</span> <!-- END OUTPUT from 'core/themes/stable/templates/field/field--node--created.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-star-rating--reviews--rss.html.twig * field--node--field-star-rating--reviews.html.twig * field--node--field-star-rating.html.twig * field--node--reviews.html.twig * field--field-star-rating.html.twig * field--integer.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper field field--name-field-star-rating field--type-integer field--label-hidden field__items"> <div class="field__item"> 5 </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-review-source--reviews--rss.html.twig * field--node--field-review-source--reviews.html.twig * field--node--field-review-source.html.twig * field--node--reviews.html.twig * field--field-review-source.html.twig * field--link.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper field field--name-field-review-source field--type-link field--label-hidden field__items"> <div class="field__item"> <a href="https://www.google.com/search?q=Scott%20Sawyer%20Consulting%2C%20LLC&amp;ludocid=13000690622832620555#lrd=0x0:0xb46bbb3da8b0b40b,1">Google</a> </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> <!-- THEME DEBUG --> <!-- THEME HOOK: 'field' --> <!-- FILE NAME SUGGESTIONS: * field--node--field-reviewer-company--reviews--rss.html.twig * field--node--field-reviewer-company--reviews.html.twig * field--node--field-reviewer-company.html.twig * field--node--reviews.html.twig * field--field-reviewer-company.html.twig * field--string.html.twig x field.html.twig --> <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' --> <div class="field-wrapper field field--name-field-reviewer-company field--type-string field--label-hidden field__items"> <div class="field__item"> Palmer CPA </div> </div> <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' --> Mon, 13 Feb 2017 20:50:46 +0000 admin 108 at https://test.scottsawyerconsulting.com