Tenseghttps://www.tenseg.net/blogTenseg[email protected]Getting to know Statamic2024-12-07T12:00:00-06:00
https://www.tenseg.net
/blog/2024/12/07/getting-to-know-statamic
<p>The recent unrest in the WordPress community has got us exploring other ways of building websites. We’ve been building sites with WordPress since the late 2000’s, so this is a big deal. We did try building a few sites with Jekyll, looking for an easy way to build static websites, but while Jekyll had some real benefits, it never seemed like something we could ship for clients.</p>
<p>A few months ago someone suggested we look at <a href="https://statamic.com/">Statamic</a>. We had not heard of Statamic nor <a href="https://laravel.com/">Laravel</a>, upon which it is built. (Yes, we’ve been living under a WordPress rock.) Laravel is a PHP framework that is much more general than WordPress, a way to build almost any web app. Laravel is highly regarded, growing, and considered quite securly architected. Statamic is a content management system built as a Laravel app.</p>
<p>At a glance, the Statamic control panel looks an awful lot like the WordPress dashboard. Upon deeper inspection it turns out to be both less chaotic and more capable out of the box. Statamic includes the equivalent of WordPress custom post types, custom fields, and forms while maintaining a clear and approachable interface. Where WordPress has the feel of a system cobbled together over the years with little sense of where it would end up and not much attention to internal consistency, Statamic feels like it knew what it wanted to be before it was created. Deep down, Statamic is nothing like WordPress even though any casual WordPress user would feel totally comfortable using it.</p>
<p>For the developer, Statamic is a joy. There is a massive learning curve, to be sure. Although both WordPress and Statamic run on PHP, the two could not be more different. Getting to know Statamic means learning Laravel, and that’s a whole new universe for some of us. But actually, we have seen way less PHP while building a Statamic site than we typically see building a WordPress site. Templates are built using an engine called <a href="https://statamic.dev/antlers">Antlers</a> that lives right in your HTML files in a way that feels much more harmonious than PHP. In fact, if you go with the flow and also adopt <a href="https://medium.com/@simonhamp/why-and-how-you-should-use-tailwind-to-build-your-next-statamic-theme-dc19a3f28237">Tailwind CSS</a> for your templates, then you will also hardly see any CSS at all. We have built two sites already in Statamic and hardly had to touch any PHP beyond a few config files. It is remarkable, a throwback to the days when we could just write pages in HTML.</p>
<p>Custom post types, custom fields, and forms all feel like awkward bolt-ons in WordPress, but in Statamic they share one common workflow of <a href="https://statamic.dev/blueprints">blueprints</a> that display <a href="https://statamic.dev/fieldtypes">fields</a> or <a href="https://statamic.dev/fieldsets">fieldsets</a>. A custom post type is just a collection of entries that shares a particular blueprint. A form is also just a blueprint bringing together and arrangement of fields. Custom fields are simply fields, which can be used in any blueprint. So you build specialized collections and forms (and even global variables for the site) with the same set of tools. In fact, there is nothing special or privilaged about the default collections, they use exactly the same blueprints and fields. With Statamic there is no friction if you need a particular piece of data in a collection, just add the field to the blueprint.</p>
<p>By default, Statamic requires no database. All data is stored in <a href="https://statamic.dev/core-concepts">plain files</a>. The beauty of this is that everything from the content of your pages to the blueprints and fields to the templates and configuration is just files in the filesystem ready to be managed in a source control system like Git. If you really want a database, the tools for keeping elements in a database are available, but for most sites they are not necessary. Statamic benefits from the terrific caching Laravel provides to keep sites speedy without the database. Statamic even provides a static site generator that can spin the whole site out as static files that do not even require PHP to be presented.</p>
<p>Although you would not know it, because the design is nearly identical to what we had in place last week, this week we rolled out a new version of our website being generated by Statamic. The site has been rebuilt using Tailwind CSS classes as well. Our experience recreating this site has taught us a lot about Statamic, Laravel, and Tailwind, and we have a lot more to learn. But the biggest lesson is that building sites this way feels really good. We feel silmultaneously “closer to the metal,” able to focus on HTML, and free of constraints, easily adding the elements we need to the user experience to make the site easy to edit and manage.</p>
<p>If you are not a developer, then you may have to stick with WordPress, as we note, there is a learning curve to picking up Statamic and it does require that you be comfortable with code and the command line. If you are a developer interested in an alternative to WordPress, Statamic is worth your time. If you are a developer new to building a website, there few places better to start than Statamic.</p>
Repairing the Chain of Trust2021-10-11T12:00:00-05:00
https://www.tenseg.net
/blog/2021/10/11/repairing-the-chain-of-trust
<p>Some of you may have heard from your customers or website users that your site is no longer accessible and instead is showing a message warning that the site is “not private” or that a “secure connection” cannot be established. We wanted to explain what is happening and how your users can resolve the problem.</p>
<p>The web has been with us for nearly 30 years, and one of the big changes behind the scenes on websites has been how we verify that a site is what we think it is. As the web emerged in 1993 there was no effort to demonstrate that trust, we just believed what we saw. But over the last ten years there has been a shift to “secure” the web using certificates, facilitated by the emergence of free and inexpensive certificates from trustworthy sources. We use the most common of those free sources with our client sites: <a href="https://letsencrypt.org">Let’s Encrypt</a>.</p>
<p>At the end of September 2021 an old “root certificate” for Let’s Encrypt expired. Let’s Encrypt had long since moved on to a new copy of that root certificate and most modern devices have since had software updates that included this new root certificate. But “most” is not “all” and some older devices have not been updated. These devices don’t know about the new Let’s Encrypt root certificate and, as a consequence, are not aware that they can trust other Let’s Encrypt certificates like the ones on your site.</p>
<p>You and we can do little to fix this problem. Indeed, we may not even experience it if our browsers have been updated recently enough. If you do field a complaint of this sort, though, the person who is experiencing the problem can fix it by installing the new Let’s Encrypt root certificate manually. In order to help them do this we have prepared a brief “how-to” post that they can follow. Please direct anyone who needs this information to our “<a href="http://www.tenseg.net/install-cert/">Installing the new Let’s Encrypt root certificate</a>” post. Make sure they use the insecure HTTP version of this link since they will not be able to access the regular secure version of our website: <a href="http://www.tenseg.net/install-cert/">http://www.tenseg.net/install-cert/</a>.</p>
Installing the new Let’s Encrypt root certificate2021-10-10T12:00:00-05:00
https://www.tenseg.net
/blog/2021/10/10/installing-the-new-lets-encrypt-root-certificate
<p>All of our websites (and many others across the web) use certificates for encrypted connections issued by Let’s Encrypt. On 30 September 2021 the root certificate for Let’s Encrypt, which validates every certificate issued by them, expired. Most computers and other devices have automatically been updated to support the new chain of certificate trust provided by <a href="https://letsencrypt.org">Let’s Encrypt</a>.</p>
<p>However, older devices may not receive this update. If you have trouble accessing a website we manage, please follow these instructions to manually install the new certificate chain. Unfortunately we cannot do this for you. Each computer that did not automatically install the updated certificate will have to have the certificate manually installed.</p>
<h2>macOS</h2>
<p>Your older version of macOS or iOS is probably holding onto the expired <code>R3 > DST Root CA X3</code> certificate chain even though it should no longer be used. For older macOS systems not updated by Apple:</p>
<ul>
<li>Download the ISRG Root X1 certificate file from <a href="http://x1.i.lencr.org/">http://x1.i.lencr.org/</a></li>
<li>Open the Keychain Access app and drag the “ISRG Root X1” certificate file you just downloaded into the System keychain in Keychain Access.</li>
<li>Find the ISRG Root X1 certificate in the System keychain and double click on it. Open the Trust option in that window and change “Use System Defaults” to “Always Trust”. If you are asked for your password, please enter it and close this window.</li>
</ul>
<h2>Windows PCs</h2>
<p>On older Windows with an outdated trust store you can manually install the “ISRG Root X1” certificate:</p>
<ul>
<li>Browse to <a href="http://x1.i.lencr.org/">http://x1.i.lencr.org/</a> in order to download the file for ISRG Root X1 (your browser may warn about the file type and you may need to click “Keep” to save the file).</li>
<li>Open the file, click “Install Certificate…”, Choose default option “automatically select…”, Next, and Finish.</li>
<li>Reboot your computer.</li>
</ul>
<p><em>[Note, these instructions are from <a href="https://docs.certifytheweb.com/docs/kb/kb-202109-letsencrypt/">Certify the Web</a>, but since their page is secure and thus inaccessible to the people who most need it, we are repeating them here.]</em></p>
Checking Old Sites on 4042021-08-05T12:00:00-05:00
https://www.tenseg.net
/blog/2021/08/05/checking-old-sites-on-404
<p>We recently ran into the situation where a page on a client’s site was returning 404 (File Not Found) because the page really lives in the archived copy of the site, but had the URL as if it were on the current website. It was easy enough to update the URL in page content where we referred to it. However, in this instance the docunent that was linked was a PDF that had links in it that were broken in the same way. Editing the PDF was not something we had the source material to do, nor wanted to do as it was part of the archived site. So we had to come up with an automatic solution.</p>
<p>We went about looking into how WordPress could redirect 404 errors over to the archived site if the requested path was not found on the current site, but was found on the archived site. The result is the <strong><a href="/software/404sitechecker">TG 404 Site Checker</a></strong> plugin. Since it is a simple enough plugin we thought that we’d make it available to anyone else who may find it useful. Configuration instructions are in the readme file. Feel free to use this plugin. If you find any problems or want to suggest any features, <a href="https://bitbucket.org/tenseg/tg-404-site-checker/issues?status=new&status=open">just submit an issue</a>.</p>
<p>Bottom line, we had a problem on a client’s site, and made a fix that is generic enough we think it may help others. So, here is the plugin we wrote with the fix. Generally, whenever we can we like writing plugins that are more generic, because that way we can use them on all our client websites as needed. <strong><a href="/software/404sitechecker">TG 404 Site Checker</a></strong> is a simple plugin that fills a very real need, and has a simple configuration. We hope you find it as useful as we do.</p>
Moving from Master to Main in Git2020-08-06T12:00:00-05:00
https://www.tenseg.net
/blog/2020/08/06/master-to-main-in-git
<p>Following the recent unrest around race relations after the death of George Floyd one of the lesser-known movements has been to move Git repositories from using <code>master</code> as the default branch to something else, most commonly <code>main</code>. We took the time to transition all of our projects’ repos in this manner. The process we took, which was based on <a href="https://dev.to/rhymu8354/git-renaming-the-master-branch-137b">this article</a>, is documented here for anyone else (including our future selves) who want to do the same.</p>
<h2>Transitioning a Repository</h2>
<p>To start this transition on the local repository on your computer you should make sure to <code>stash</code> any uncommited changes if there are any, then run the following at the command line in your project’s folder and take note of what remotes the repository has for later use:</p>
<pre><code>git remote -v
</code></pre>
<p>Then actually move the <code>master</code> branch, here to <code>main</code>:</p>
<pre><code>git branch -m master main
</code></pre>
<p>Now it is time to push this new branch to remotes, so for each remote you took note of:</p>
<pre><code>git push -u <remote_name> main
</code></pre>
<p>Once the branch is up on the remotes you’ll need to set the new branch as the <strong>Main</strong> branch. This is in different places on different sites, here are the ones we’ve used:</p>
<ul>
<li>For <a href="https://github.com">Github</a>: Under <em>Settings</em> for a repo choose <em>Branches</em> and change the <em>Default branch</em></li>
<li>For <a href="https://bitbucket.org">Bitbucket</a>: Under <em>Repository settings</em> choose <em>Repository details</em>, then open the <em>Advanced</em> section and change the <em>Main branch</em></li>
<li>For <a href="https://gitea.com">Gitea</a>: Under <em>Settings</em> for a repo choose <em>Branches</em> and change the <em>Default Branch</em></li>
</ul>
<p>Back in your local repository you’ll need to delete the <code>master</code> branch from each remote:</p>
<pre><code>git push <remote_name> --delete master
</code></pre>
<p>And finally set your head to the appropriate remote, usually <code>origin</code>, as well as <code>pop</code> your stashed chagnes if there were any:</p>
<pre><code>git remote set-head origin -a
</code></pre>
<h2>Changing Repositories on Other Computers</h2>
<p>Once you have transitioned the repository on one computer, all other computers which have cloned it will need to run through the following:</p>
<pre><code>git fetch --all
git remote set-head origin -a
git branch --set-upstream-to origin/main
git branch -m master main
git pull
</code></pre>
<h2>Changing the Default Branch Name Used for New Repositories</h2>
<p>Now that you’ve taken the time to transition existing repositories you’ll want to always use the new name for future projects as well. Unfortunately Git does not have a simple setting to change, there seemed to be one but it didn’t seem to work. So instead you’ll want to make a custom repository template to use.</p>
<p>The first trick here is figuring out where Git is installed. On Macs you may have used <a href="https://brew.sh">Homebrew</a> to install Git. In that case the base tremplate files would be found at <code>/usr/local/share/git-core/templates</code>. The next step will be determining where you want to store your custom template files. I chose <code>~/.config/git/template/</code> as my location, but anywhere in your user account would work. Then run the following, replacing the placeholders as needed:</p>
<pre><code>cp -r <system_git_template> <user_git_template>
echo 'ref: refs/heads/main' > <user_git_template>HEAD
git config --global init.templateDir <user_git_template>
</code></pre>
<p>When you run <code>git init</code> Git will say it is reinitializing the repository even though it is a brand new repository. This is a side-effect of the reality that your template has a <code>HEAD</code> file in it. Don’t worry about this. But now any new Git repository you make will have the <code>main</code> branch from the start.</p>
Zoom Zero-Day Flaw2019-07-09T12:00:00-05:00
https://www.tenseg.net
/blog/2019/07/09/zoom-zero-day-flaw
<p>Yesterday <a href="https://medium.com/@jonathan.leitschuh/zoom-zero-day-4-million-webcams-maybe-an-rce-just-get-them-to-visit-your-website-ac75c83f4ef5">a report</a> came out describing a zero-day flaw in the Mac client for the popular online meeting service <a href="https://zoom.us">Zoom</a>. The report is quite technical, but describes some very serious security flaws in the client software. I’m going to unpack the basics here, and most importantly give you a (fairly) straightforward way to secure your Mac if you have Zoom installed. I highly encourage everyone to follow these steps as soon as possible.</p>
<h2>The Flaw</h2>
<p>The core of the security flaw is that a malicious website can trigger you to enter a Zoom meeting with video and audio automatically enabled. This is acheived through the the website calling out to a webserver on your Mac that Zoom installed, which incidentally remains even if you uninstall Zoom, and will reinstall Zoom if you ask to join a meeting, all without asking you for permission. The launching of Zoom through this server is acheived through a specially-crafted image, which they use to bypass sandbox security implemented by browsers to try and stop this sort of thing. This was reported to Zoom back in March, and by yesterday, the public disclosure deadline, Zoom still hadn’t fully fixed the problems (they had made one fix, but a workaround was discovered). You can read all the technical details at the report linked earlier in this post.</p>
<h2>Instructions for how to Protect Your Mac</h2>
<p>To secure your Mac against this zero-day you need to run a series of commands at the command-line on your Mac. You do this using the <strong>Terminal</strong> application, found in <code>/Applications/Utilities</code>. Copy and paste each of these commands exactly as they are below (with the exception of the one where you enter the <code>PID</code> unique to your Mac), hitting return after each one. I may get around to providing a simple tool anyone can run to with one-click perform these actions, but this is serious enough that getting them documented and out to folks is far higher of a priority.</p>
<p>Disable Zoom’s ability to turn on video by default:</p>
<blockquote>
<pre><code class="language-bash">
</code></pre>
</blockquote>
<p>defaults write ~/Library/Preferences/us.zoom.config.plist ZDisableVideo 1</p>
<pre><code>
Check for the hidden Zoom webserver:
>```bash
lsof -i :19421
</code></pre>
<p>If this command returns any output then the server is running. In that case, take note of the number in the <code>PID</code> column.</p>
<p>Kill the server:</p>
<blockquote>
<pre><code class="language-bash">
</code></pre>
</blockquote>
<p>kill -9 (PID number from the previous step)</p>
<pre><code>
Remove the server's files:
>```bash
rm -rf ~/.zoomus
</code></pre>
<p>Create a new file in its place:</p>
<blockquote>
<pre><code class="language-bash">
</code></pre>
</blockquote>
<p>touch ~/.zoomus</p>
<pre><code>
Change its permissions so that Zoom cannot overwrite it and add the server back:
>```bash
chmod 000 ~/.zoomus
</code></pre>
<p>You will need to perform these steps in every user account on your Mac that you have used Zoom in.</p>
<h2>Side-Effects</h2>
<p>After performing these steps your Mac will be immune to this zero-day flaw. Unfortunately, Zoom will also no longer act quite as it has in the past. Specifically:</p>
<ul>
<li>You will need to manually turn on video in all meetings.</li>
<li>The Zoom links to enter meetings will no longer work. Instead you’ll have to launch Zoom yourself, ask to join a meeting, and enter in the meeting id.</li>
<li>Zoom will no longer auto-update. Instead, every so often make sure to redownload the Zoom app <a href="https://zoom.us/download#client_4meeting">from their website</a>.</li>
</ul>
<p>Once this issue is confirmed fixed, and if you ever again trust Zoom’s full install, then you should only need to delete the file you created and Zoom will set itself up as intended again:</p>
<pre><code class="language-bash">rm .zoomus
</code></pre>
<p>I <strong>strongly</strong> urge everyone that has ever used Zoom on their Mac to perform these steps. Yes, it will make joining a meeting more difficult, but it will make it so that you can’t unknowingly join a meeting with video enabled.</p>
<h2>Update 10 July 2019 7 pm Central Time</h2>
<p>Apple has <a href="https://eclecticlight.co/2019/07/10/apple-has-pushed-an-update-to-mrt-to-remove-zooms-hidden-web-server/">pushed an update to the Malware Removal Tool</a> built into macOS that removes the local Zoom web server from all Macs automatically.</p>
<h2>Update 10 July 2019 3:40 pm Central Time</h2>
<p>Zoom did release an update that removes the local server overnight last night. This version should not have the zero-day flaw in it.</p>
<h2>Update 9 July 2019 4:20 pm Central Time</h2>
<p>Zoom <a href="https://blog.zoom.us/wordpress/2019/07/08/response-to-video-on-concern/">has announced</a> that they plan to release an update by midnight tonight that removes the local web server.</p>
<h2>Update 9 July 2019 3:40 pm Central Time</h2>
<p>I noticed that my Mac’s Zoom client was slightly out of date. When I went to download the latest version what they give you is an installer package. That is the first red flag, as very few developers need more than drag and drop to install their apps. I always open installer packages first with <a href="https://www.mothersruin.com/software/SuspiciousPackage/get.html">Suspicious Package</a>, to examine what they’ll do before installing them. Now even more red flags appeared… The package runs a script upon opening, before you can even intervene. Now, this usually is just checking that you meet system requirements, but Zoom’s installer is messing with the Dock and doing a bunch of other things, some of which may be nefarious, I haven’t deciphered the script entirely yet. But even more troubling, the installer package does not have any files it installs, and the scripts in the package include what appears to be the file structure of a kernel extension and web browser plugin, with almost no sign of a regular Mac app other than an entitlements file. But that isn’t how it should be. The scripts should just be scripts (<code>preinstall</code>, <code>postinstall</code>, and <code>Distribution</code>), and regular installer packages would put the files they install into the regular installation mechanism, which would appear as files in the package. The app itself is in the scripts folder in the <code>zm.7z</code> archive. You can use the <code>7z</code> command (which can be installed with <code>brew install p7zip</code>) to extract the app. <em>I would recommend doing this rather than running the installer package.</em> I think we’re starting to see why Zoom hasn’t fixed these flaws yet. It seems possible that they need to do a significant rearchitecting of the entire app and service to fix these problems. Zoom was such a good service… These flaws, and this unorthodox download, very much hurt their reputation in my book.</p>
Concerns About the State of App Store Review2019-02-20T12:00:00-06:00
https://www.tenseg.net
/blog/2019/02/20/concerns-about-the-state-of-app-store-review
<p>As an interesting sidebar to <a href="/blog/2019/02/20/subcalc-three/">our post about SubCalc 3’s release</a> today that will be of interest to fellow developers…</p>
<p>In releasing <a href="/software/subcalc">SubCalc 3</a> to the App Store we accidentally had a severe bug in it that caused the app to show just a white screen when opened. This was a side-effect of our build process not quite working when preparing the app for submission to the App Store, which is why we didn’t catch it. Shortly after we found out we pulled SubCalc 3.0.0 from the U.S. App Store (because, even with a call to developer support, we couldn’t get Apple to reject the update and leave the working 2.0.1 on the store). We have since fixed the problem and modified our procedures to catch such issues in the future. Always export for ad-hoc distribution the archived app you’re about to submit to the App Store. Install it to your device to be sure that it works as expected. The problem came down to two basic things we failed to do in our build phase script that builds the React app:</p>
<ol>
<li>We were not quoting paths that were used in our <code>build-react-app.sh</code> run script build phase. This meant that we were using the wrong paths for where to write out the built React app to. Instead of ending up in the proper product it was in a “mirror” version within the source code when archiving.</li>
<li>We had been using <code>${BUILT_PRODUCTS_DIR}</code> to access the built product. This failed to give us the product path when being run while archiving the app for App Store submission. Instead what is stable across all build configurations is to use <code>${CONFIGURATION_BUILD_DIR}</code>.</li>
</ol>
<p>The thing is, this is among the kind of issues we expect the App Store’s review team to flag for rejecting updates. They let our initial 3.0.0 update out on to the App Store. This means that in their review process they evidently didn’t even bother trying to run our app. I’m not sure if I’m more scared of this as a developer or as a user. How can Apple be 100% sure that apps aren’t doing bad things if they don’t even run them? This feels like a potential security problem waiting to happen, since as users we trust that apps provided from the iOS and Mac App Stores are safe and operate as intended.</p>
<p>Have any other developers of apps for Apple’s devices had a similar experience? I’m all for the speedier (about 3/4 of a day for both SubCalc 3.0.0 and 3.0.1) app review times, or so I thought. But if this is allowing outright broken apps at best, and malicous apps at worst, on to the App Stores then this is a real problem. Users deserve confidence in the software they install, and because I’m also a developer I am especially concious of this as a user. Beyond my own practice as a developer, this experience makes me worried about the overall quality of the apps I use on my devices that ostensibly are coming from a secure and trusted source.</p>
SubCalc 3 Released2019-02-20T12:00:00-06:00
https://www.tenseg.net
/blog/2019/02/20/subcalc-three
<p>Today we are pleased to announce that <a href="/software/subcalc">SubCalc</a>, the Subcaucus Calculator, has been updated to version 3. Those of you with SubCalc on your iPhone or iPad should recieve the update shortly if you have app auto-updating on, and everyone else can install it from <a href="https://itunes.apple.com/us/app/subcalc/id352454097?mt=8">the App Store</a>. As before, <a href="https://subcalc.tenseg.net/">a web app version</a> is also available for those without iPhones or iPads, or those who need to use SubCalc on desktops. This is a major new version that we rewrote and redesigned from the ground up. This version introduces numerous new features:</p>
<ul>
<li>Save multiple snapshots of meetings</li>
<li>Duplicate a meeting</li>
<li>Sort the subcaucus name and members columns (thanks CT for the suggestion)</li>
<li>Hide the delegates column (thanks CT for the suggestion)</li>
<li>Share snapshots as text, code, spreadsheet, or a link to the iOS share sheet</li>
<li>Import snapshots via link either by viewing in Safari or using the Paste clipboard option in the app</li>
<li>More detailed explanations of the numbers this calculator gives you</li>
<li>Quickly reset the members column for the next walk (thanks CT for the suggestion)</li>
<li>Quickly remove empty rows</li>
</ul>
<p>We have also made SubCalc available as <a href="https://github.com/tenseg/subcaucus-calculator-ios">a public open source project on Github</a>. Both the iOS app, and the web app at its core, are open source. We did this partly so that people can audit the code that performs the mathematical operations to trust the results it gives more. Feel free to participate in the future development of SubCalc, even if only by opening issues for bugs you find or new features you desire.</p>
<p>We hope you enjoy the refreshed SubCalc. Please don’t hesitate to send us feedback either <a href="mailto:[email protected]">in email</a> or <a href="https://github.com/tenseg/subcaucus-calculator-ios/issues?q=is%3Aopen+is%3Aissue">at Github</a> if you find bugs or have feature requests.</p>
Losing Your Head2018-10-25T12:00:00-05:00
https://www.tenseg.net
/blog/2018/10/25/losing-your-head
<p>Today I am giving a brief presentation at our <a href="https://mspwp.com">Minneapolis St. Paul WordPress User Group</a> about our experiment with “headless WordPress.” We recently built a site that needed to stay super-simple for users while incorporating a back end for managing images and comments. We also wanted the site to eventually turn into a static website with no back end at all. Our solution was to build the front end in <a href="https://reactjs.org">React</a> and use the <a href="https://developer.wordpress.org/rest-api/">WordPress API</a> to provide a connection to a WordPress install that could manage the incoming images and comments.</p>
<p>My <a href="/assets/headless-wp.pdf">slides for the presentation</a> tell the basic story. Since the demo is not really available online, instead you can visit the <a href="http://sharing.robberkley.com">Sharing Rob</a> site that inspired this solution (please don’t add anything there unless you knew Rob). Another resource to explore might be <a href="https://medium.com/@jchiatt/headless-wordpress-with-react-d573bca02ee0">this introduction to headless WordPress with React</a>.</p>
<p>One of the really nice features of this solution is that as soon as we want to “freeze” the site and stop further contributions, all we have to do is put a static version of the file returned by our API call onto the website. Once we do that, we can remove every trace of WordPress (except the static uploaded image files) and be left with a site that requires no updates or maintenance.</p>
Signing Your Work2018-08-27T12:00:00-05:00
https://www.tenseg.net
/blog/2018/08/27/signing-your-work
<p>Git has the notion of defined authorship for commits and tags. This is done at either a repository or global level, using the <code>git config</code> command. This allows Git, and in turn sites like <a href="https://github.com">Github</a>, to recognize who authored what changes to code. But config settings in plain text only go so far. Much like (regular) email, really anyone can impersonate you. Nothing can stop someone from putting your name and email in their Git config. All of a sudden you’d see commits that “you” authored which you know were in fact not you.</p>
<p>There is a way to get around this issue, and confirm authentic authorship, should you want a more certain way of letting people know that you authored code in certain commits. You can use a GPG/PGP key to digitally sign commits and tags. This means that though anyone could impersonate your name and email, someone could only digitally sign commits as you if they got ahold of your private key, a much larger challenge than merely editing a text file.</p>
<p>I have set this up on my Macs, and wanted to document the process here for future reference and in case anyone else wants this higher bar of certainty on their Git commits. The following sections describe the necessary, and optional, steps to getting this set up.</p>
<h2>Git Version</h2>
<p>Only versions of Git >= 2 have the GPG signing features. macOS High Sierra should have a sufficient version, but I recommend installing Git via Homebrew anyway (<code>brew install git</code>) to always have the latest release if you’re a serious user of Git. An advantage of the Homebrew Git install is that it comes with the git-prompt script, which allows you to show Git info in your command line prompt. Additionally, this will put the version of Git you’re using within the same paths as the GPG software.</p>
<h2>GPG Tools</h2>
<p>While you can install GPG software on the Mac via Homebrew, I recommend installing the free <a href="https://gpgtools.org">GPG Suite</a>. A word of caution, you should customize the install and uncheck the GPGMail plugin for Apple’s Mail app. Even if you intend to digitally sign or encrypt email (which I don’t) you can still use the systemwide Services to sign or encrypt email contents, and the plugin has caused problems with composing mail for me in the past.</p>
<p>After the install finishes it should automatically open the GPG Keychain app and ask you to generate your GPG key. If you already have a key you can cancel this and import your existing key. But I’m assuming you don’t have a key for the purposes of this post. As soon as it has generated your key it should open the main window. At this time I highly recommend exporting your public/secret keypair to a secure location for safekeeping (but more on that, too, later).</p>
<p>It is worth going to System Preferences and opening the newly added GPG Suite prefpane. You should check that your key is the default, and I find it safe enough to let it store key passwords in the macOS Keychain (but that one is up to you). You can change any of these preferences to your liking.</p>
<h2>gitconfig</h2>
<p>You’ll need to add some information to your global <code>gitconfig</code> file in order to tell Git about GPG. Open that file and add the following:</p>
<pre><code>[commit]
gpgsign = true
[gpg]
program = /usr/local/MacGPG2/bin/gpg
[user]
signingkey = { your key id, found in Details drawer of GPG Keychain }
</code></pre>
<p>You should now be able to commit to any repo and that commit will be digitally signed using your GPG key. In order to confirm that the commits are now being signed use <code>git log --show-signature</code> to have the log also display signature information.</p>
<h2>gpg.conf</h2>
<p>While Git from the command line will now be able to sign all commits and tags, you need to add one line to your <code>~/.gnupg/gpg.conf</code> file to allow IDEs (like Xcode) to do so. Just add <code>no-tty</code> to the bottom of the file and save it. Now Xcode will no longer only give you a fatal error when trying to commit.</p>
<h2>GPG and Github</h2>
<p>Now that you are digitally signing your commits you need to tell Github about your key so it can verify commit authenticity. To do so go into your Github settings, and choose <em>SSH and GPG keys</em>. That’s right, the same place you’ve come to add SSH keys you now go to add your GPG key. You can export your public key, open the file in a text editor, and copy the key block from there. From here on out, any signed commits of yours will show a green “Verified” label, both to you and others on the project.</p>
<p>Note that, unfortunately, Bitbucket Cloud does not currently support showing GPG and signed commit information.</p>
<h2>Publishing your Key</h2>
<p>It is a good idea, though optional, to publish your key. GPG Keychain can do this by sending the key to the network of public keyservers using the option for it under the Key menu. You can also simply put your public key block somewhere on your website. Facebook also allows you to add your public key to the Contact Information section of your profile. You can, of course, also email it to people or send it along like any other attatchment using any service.</p>
<p>Since trust is behind the strength of GPG keys, it is important that your public key is accessible to others. Just make sure that you keep the secret key close and secure. Mine is only in the keyrings on the Macs I use, and one export file that is encrypted and secured in a safe place.</p>
<h2>keybase.io</h2>
<p>Recently I found the Keybase website and software. This is a system that gives you <a href="https://keybase.io/alexclst">a public profile</a> (link is to my own profile), and lets you publish your GPG key, and verified ownerships of other online profiles and websites. Though totally unnecessary to use GPG to sign Git commits, Keybase can be a home for verified identities and sharing your GPG key. Further, it provides truly end-to-end encrypted storage and chat for yourself, teams, and between individuals, as well as digitally signed public folders. All based on the GPG key technology. Keybase actually has its own entire Mac app and command line interface, but you still need the regular GPG software to use your key with Git (and having it makes sense anyway so the key is usable in normal ways). So, Keybase is a collection of tools to help connect people who have GPG keys.</p>
<h2>Conclusion</h2>
<p>This post gives the briefest overview of how to set up Git to digitally sign Git commits. You can look through <a href="https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work">Git docs</a> to learn more, including how to sign tags. If you follow the first sections you’ll have a key, so it suggests further uses regarding sharing that key. GPG is still quite complex, so won’t be used by that many who aren’t very good with technology (though Keybase’s hope is to change that) at this time. But it is a useful thing to know about and use, if not for all possible uses, so that if you have a more important need of it you’ve already begun learning.</p>
Using a Private Git Server2018-07-28T12:00:00-05:00
https://www.tenseg.net
/blog/2018/07/28/using-a-private-git-server
<p>While services like <a href="https://github.com">Github</a> and <a href="https://bitbucket.org/">Bitbucket</a> are invaluable to our work as web and software developers, they are run by other companies, and as such aren’t in our direct control. They may go down at inconvieient times, or be buggy in other ways. You may also find yourself doing projects that you don’t want to actually put in the clutches of external entities at all. As a supplement to these (or similar services) you may want to consider running your own self-hosted (and potentially completely private) Git Server. I recently set up just this. I thought that it would be worth describing what we have going in case it would help anyone else.</p>
<p>The first thing that you’ll need is some computer to run as the server. In some cases a <a href="https://www.raspberrypi.org">Raspberry Pi</a> may do, but we were offered an old Mac Mini by family, and also have more complex uses for an internal server (like running <a href="https://www.plex.tv">Plex</a>), so went with a full-fledged Mac instead. It is that configuraton that I’ll be discussing here. My first bit of advice is to <a href="https://support.apple.com/en-us/HT204904">clean install</a> whatever the latest version of macOS that runs on the computer is, in our case that was macOS High Sierra. The reason to do this is to ensure that when you build your server it is as clean as it can be. We don’t want leftover cruft from when the Mac was being used as an everyday computer.</p>
<p>When you are setting up the fresh install I recommend first creating a dedicated <code>apple</code> account as the only admin user, and setting a strong password on it. You will rarely actually be in this account directly. Create a separate standard user, I named ours <code>server</code>, that is set to log in automatically. This is the account that will actually run the Git server. You’ll also want to ensure that the server starts up automatically after a power faiilure, and that it is automatically updating at least security updates. I also turned on screen sharing, file sharing, and remote login so we could manage the server from our own Macs, with the server itself running completely headless.</p>
<p>There are a number of projects that are Github clones, I chose <a href="https://gitea.io/en-us/">Gitea</a> to run as our internal Git server. Installing Gitea could not be easier, since it can be done via <a href="https://brew.sh">Homebrew</a>:</p>
<pre><code class="language-bash">brew tap go-gitea/gitea
brew install gitea
</code></pre>
<p>You will also need <a href="https://dev.mysql.com/downloads/mysql/">MySQL</a> installed. Then you can go and create a user and database for Gitea to use. After that just run</p>
<pre><code class="language-bash">gitea web
</code></pre>
<p>to start the server. It should tell you what the URL is to access the server, going there will take you to the Gitea setup screen. Basically, enter the database information and a few other details and you’ll be all set. Gitea should provide you with helpful hints as a brand new admin user.</p>
<p>By default Gitea is using <code>/usr/local/bin</code> as its home directory. So I recommend changing that to something within the <code>server</code> user. We chose to make this a <code>gitea</code> folder in the <code>server</code> user’s home directory. To do this you need to simpy run Gitea specifying a custom path to its config file:</p>
<pre><code class="language-bash">gitea web -config /Users/server/gitea/conf/app.ini
</code></pre>
<p>The file should be under <code>custom/conf</code> in <code>/usr/local/bin</code> right now, so just move the file to a <code>conf</code> folder in whatever folder you want Gitea to use for data. Open that file and you’ll see a number of other file paths specified. I sugest changing all of these to be subfolders of the folder that you’ve set for Gitea to use. You should also look at the <a href="https://docs.gitea.io/en-us/config-cheat-sheet/">config cheat sheet</a> and set specific folders for all of the path settings the config file can have. For the most part these should be subfolders, except I would reccommend that logs go into a <code>gitea</code> subfolder of the user’s logs folder at <code>~/Library/Logs</code> so that Console can be easily used to navigate logs. You should also set the URL and Port as appropriate for your environment.</p>
<p>The final step in setting up Gitea is to ensure that it runs at login (which is system startup if the user logs in automatically). Do this be creating a Launchd plist file for this service at <code>~/Library/LaunchAgents</code>, maybe name it <code>io.gitea.gitea.plist</code>. The contents of this file should essentially be:</p>
<pre><code class="language-xml"><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>WorkingDirectory</key>
<string>/Users/server</string>
<key>EnvironmentVariables</key>
<dict>
<key>GITEA_WORK_DIR</key>
<string>/Users/server/gitea</string>
<key>GITEA_CUSTOM</key>
<string>/Users/server/gitea/conf</string>
<key>HOME</key>
<string>/Users/server</string>
</dict>
<key>StandardOutPath</key>
<string>/Users/server/Library/Logs/gitea/launchd.log</string>
<key>StandardErrorPath</key>
<string>/Users/server/Library/Logs/gitea/launchd_error.log</string>
<key>ProgramArguments</key>
<array>
<string>sh</string>
<string>-c</string>
<string>/usr/local/bin/gitea web -config /Users/server/gitea/conf/app.ini</string>
</array>
<key>UserName</key>
<string>server</string>
<key>RunAtLoad</key>
<true/>
<key>Label</key>
<string>io.gitea.gitea</string>
</dict>
</plist>
</code></pre>
<p>Pay attention to the paths in this file to make sure that you change them from this example as needed. To start the service run:</p>
<pre><code class="language-bash">launchctl load /Users/server/Library/LaunchAgents/io.gitea.gitea.plist
</code></pre>
<p>From here on out is should be kept running by macOS, and started on user login. At this point you have your own Git server running. You should explore it as much as you’d like, and start playing with it.</p>
<p>To use the second server, just add it like normal to your repo with <code>git remote add</code>, but remember that its name needs to be something other than <code>origin</code>. To fully integrate this new server as a backup of your primary remote you should push to it anytime that you push to the primary remote. Git makes this quite easy. A single remote can have more than one URL to use when pushing, so you set up the remote like so:</p>
<pre><code class="language-bash">git remote set-url --add --push origin [email protected]:test/my-project.git
</code></pre>
<p>You actually need to run this same command for the original remote URL to keep pushing to it as well. From here on out whenever you push you will be pushing to both your prinary and internal remotes. No need to worry about keeping your internal remote current. You can only pull from one remote at a time, and should only regularly do this from your primary remote, but you should still set up your internal remote the traditional way so you can pull from it if needed. The next time Github or Bitbucket go down, or even just your local internet connection, you will be able to continue pushing as normal so your partners can get your changes and you have the peace of mind to know that your changes aren’t on just one machine.</p>
Changing the email WordPress sends administrators when passwords change2018-07-15T12:00:00-05:00
https://www.tenseg.net
/blog/2018/07/15/wp-password-change-notification
<p>WordPress offers two little-known hooks for changing the email WordPress sends administrators and users when passwords are changed. These two filters (<code>wp_password_change_notification</code> and <code>password_change_email</code>) behave a little differently from one another. The biggest factor that caught me by surprise was the fact that <code>wp_password_change_notification</code> does not work at all when activated on a subsite of a multisite network (at least when that network is using subdirectories to distinguish sites).</p>
<p>Let’s define a small plugin called <code>passworder</code> to demonstrate how this filter can be used. Here is the <code>passworder.php</code> file that defines the plugin.</p>
<pre><code class="language-php">&lt;?php
/*
* Plugin Name: Passworder
* Description: Modifies the email that goes out when passwords are changed.
*/
function password_change_email_admin( $email, $user, $blogname ) {
$message = sprintf( __( 'Dear admin: password changed for %s: %s %s' ),
$user->display_name,
$user->ID,
$user->user_login
) . "\r\n";
error_log( $message );
$email['message'] = $message;
return $email;
}
add_filter( 'wp_password_change_notification_email', 'password_change_email_admin', 10, 3 );
</code></pre>
<p>Note that the <code>wp_password_change_notification_email</code> filter will not work at all unless it is <em>network activated</em>. This is because the whole password recovery process is executed at the network level and not within the bounds of a specific subsite. In this case, if the plugin were activated on a subsite, it would never be loaded and thus the filter would never be called.</p>
<p>This is not the case for the other filter, <code>password_change_email</code>, designed to send mail to the user when an admin changes their password using the profile. In this case the filter should be in a plugin activated on the subsite, not at the network level.</p>
LBF Container2018-03-08T12:00:00-06:00
https://www.tenseg.net
/blog/2018/03/08/lbf-container
<p>A large part of my work these days is writing plugins and themes for WordPress. I use a tool called <a href="https://local.getflywheel.com">Local by Flywheel</a> to run copies of client sites, and other experimental sandbox sites, for development purposes locally on my Mac. That way I can mess around as much as I need to without compromising the actual websites. Local has a somewhat unintuitive feature to open a (fake, since it is just Docker containers) SSH connection to the sites it runs locally. You access it from the contextual menu of sites in the main window. This gets old fast when you have a dozen or more windows open on your desktop, and it may be that Local is even in another desktop space altogether, behind yet more windows. That is just the reality of software/web development, lots of windows, regardless how organized you are. Usually up front in my development environments is my code editor, and most advanced code editors these days (including the one I use for web development, Visual Studio Code) have integrated terminals in their single window per project interfaces. So, all in all, digging around for a window just to launch a different Terminal and copy the command it runs to enter the Local site’s “SSH” in the integrated terminal was getting really annoying.</p>
<p>So, I thought it could be done better. Between last night and this morning I’ve put together my response to this inconvieient arrangement, <a href="https://bitbucket.org/alexclst/lbf-container">LBF Container</a>. This shell script can be called from any folder that is part of a Local site and it will drop you right into that site’s bash prompt. No getting lost trying to find Local’s window. No leaving your work environment whatsoever, in fact. It is somewhat blissfull being able to just type a simple command in the integrated terminal and end up with the same thing that used to take a few steps and digging around my Mac. I thought that others may be interested in this script as well, which is why I <a href="https://bitbucket.org/alexclst/lbf-container">provide you with access to it</a>. Let me know if this is useful to you, I’d love to hear your feedback.</p>
Git Commit Info in your App2017-08-03T12:00:00-05:00
https://www.tenseg.net
/blog/2017/08/03/git-commit-info-in-your-app
<p>For a while now we have been computing the build number for our iOS apps from the Git commit that the code was at when the project was compiled. This is done using a custom Run Script Build Phase in Xcode. We have recently expanded upon simply rewriting <code>CFBundleVersion</code> in the <code>Info.plist</code> to be that number, to also write out everything we’d need to know in order to know the current branch, the commit hash, and how many changes were made since the last commit (when shipping an app this really should be 0, but when developing it often will be some larger value).</p>
<p>The original version of this, which only wrote out the computed build number, came from <a href="http://tgoode.com/2014/06/05/sensible-way-increment-bundle-version-cfbundleversion-xcode/">a post on Tommy’s Domain</a>. This only reported the build number, and also required manually setting what branch the count would be based on. As such, we have built upon this. We set out first to automatically set the branch based on the current branch, and along the way found ourselves deciding to actually write out a lot more information to the <code>Info.plist</code> as well.</p>
<p>All the code I’ll be discussing in the remainder of this post can be found at the very bottom, embedded from a Github Gist. Feel free to also discuss this post in comments on <a href="https://gist.github.com/alexclst/675e02c457b02b8a88868809a84ac8b7">the Gist</a>.</p>
<p>While you can write entire shell scripts directly in the Run Script Build Phase editor, this has a few pitfalls to be aware of, and so we don’t recommend it. The main pitfalls include a tiny editor space that does not have the autocompletion and other smarts we expect in Xcode, for each target you’ll need to copy and paste the script, which is unfriendly to further editing, and also the script contents is a part of the project file, so unfriendly to Git if ever you need to diff it.</p>
<p>Instead we reccommend writing a shorter shell (no pun intended) script as the Run Script Build Phase that itself calls an external script file that is in your project like any other source file. The <code>build phase.sh</code> script in the below Gist is what we use, based on <a href="http://kelan.io/2008/xcode-run-script-build-phase-tip/">a tip about Run Script Build Phases</a>. You only really need the code starting with line 8 and on in your build phases, though take note that the shell to set this build phase to is bash. Also note that it expects the script itself to be in a <code>scripts</code> subfolder, but of course you can do whatever you’d like.</p>
<p>The <code>git-commit-num-to-build-num.sh</code> script in the below Gist is the script that actually does the fun stuff here. It first collects the information from the project directory (reporting it into the build log as it goes) and then writes that out to the <code>Info.plist</code> files. Since we write to the dSYM bundle as well, you’ll need to set your <code>Debug Information Format</code> build setting to <code>DWARF with dSYM File</code> for Debug builds as well as Release builds, which last I checked isn’t the Xcode default. This script also doesn’t need to be included in any of your targets, so when creating the new file you should uncheck all targets. You should also change the <code>TSCommit</code> key to something specific to your environment, as <code>TS</code> is simply Tenseg’s prefix.</p>
<p>If you’re wondering how to expose all this in your app we have also included example code for generating a <code>versionString</code> that you can use in an About view, logged string, or really anything you can dream up. That is in the <code>version-string.swift</code> file in the below Gist.</p>
<p>We hope that this may help you encode important details about your projects into your apps. Since the project is under Git already (if it isn’t, please stop reading this and put it under Git, then come back, also if it isn’t then this post really doesn’t apply to you) the targets might as well include Git-centric records that point back to the exact point in your project’s life they came from. If exposed to the user, or just included in bug and crash reports, having these details at your fingertips in each target can be very handy.</p>
<script src="https://gist.github.com/alexclst/675e02c457b02b8a88868809a84ac8b7.js"></script>
<p>Please feel free to ask questions, leave comments, or just generally discuss in the comments section of <a href="https://gist.github.com/alexclst/675e02c457b02b8a88868809a84ac8b7">this Gist</a>.</p>
Introducing HelloGameKitiOS2017-07-20T12:00:00-05:00
https://www.tenseg.net
/blog/2017/07/20/hellogamekitios
<p>Alex and I have been trying to write a turn-based game for iOS for quite some time. Last year we set it aside because we were seeing too many bugs in Apple’s Game Center and Apple’s documentation of turn-based games was severely lacking.</p>
<p>A few weeks ago I noticed that Apple released an example app called <a href="https://developer.apple.com/library/content/samplecode/HelloGameKit/Introduction/Intro.html">HelloGameKit</a> last October. Unfortunately, this is a watchOS example, and Apple provided no instructions for how to actually get the code to work properly (Game Center games need to be registered with Apple, and we could not figure out which components needed what registration and capabilities in order to actually run properly on the watch).</p>
<p>Still, the Swift code was very helpful. We have now transformed this example into one that targets iOS instead of watchOS and released it as <a href="https://bitbucket.org/tenseg/hellogamekitios">HelloGameKitiOS</a>. We even included a few hints about how to actually get the game to run on your device (note, this will require an Apple developer account).</p>
<p>The “game” is pretty rudimentary. Players alternate turns and during their turn they can poke the other players. A turn simply captures the player’s id and a timestamp. The pokes disappear with each turn. But the game is sufficient to demonstrate how to communicate with the Game Center servers, how to update players of progress during a turn, and how to notice and trap errors coming from Game Center.</p>
<p>Now we will turn our attention back to the game we were working on last year. I hope this skeleton will help us resolve the Game Center issues we were encountering. And I hope that sharing this example may help others struggling with the same issues find some clues.</p>
<p>So please, if you are trying to get a turn-based game working with Swift, iOS, and Apple’s Game Center, give <a href="https://bitbucket.org/tenseg/hellogamekitios">HelloGameKitiOS</a> a look. If you have ideas about how to improve this example, feel free to communicate with us via the BitBucket <a href="https://bitbucket.org/tenseg/hellogamekitios/issues?status=new&status=open">issue tracker</a>.</p>
Docker and Visual Studio Code for Local WordPress Development2017-02-24T12:00:00-06:00
https://www.tenseg.net
/blog/2017/02/24/docker-and-visual-studio-code-for-local-wordpress-development
<p>On February 23rd Eric and Alex gave a presentation at their local WordPress user group, <a href="https://mspwp.com">MSPWP</a>, on using <a href="https://www.docker.com">Docker</a> to mount local copies of WordPress sites for development. They demonstrated editing a site from <a href="https://code.visualstudio.com">Visual Studio Code</a>. Finally, they covered getting started with debugging using <a href="https://xdebug.org">XDebug</a> in VS Code. Only a week and a half before they gave their presentation they first began experimenting with Docker, and quickly recognized it as the future for their local development sandboxes of client (and personal) websites. It was recognizing its potential so immediately that led them to want to share their finding with others.</p>
<p>The remainder of this post is a reproduction of the tutorial document that they made available after the presentation to the user group (and this post is, for all intents and purposes, their own place to archive it for anyone to find in the future, and they hope for those who find it that it is useful to you).</p>
<!--more-->
<h1>Install Docker</h1>
<p>To install Docker go to the <a href="https://docs.docker.com/docker-for-mac/install/">Docker download page</a>.</p>
<h1>An Example docker-compose.yml</h1>
<p>The first part of our presentation showed how to create a WordPress install using the standard WordPress image. Here is the contents of the <code>docker-compose.yml</code> we used:</p>
<pre><code class="language-yaml">version: '2'
services:
db:
image: mysql:5.7
ports:
- "3999:3306"
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: wordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8999:80"
volumes:
- ./html:/var/www/html
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_PASSWORD: wordpress
volumes:
db_data:
</code></pre>
<p>We created a new folder, <code>mspwp</code>, put this <code>docker-compose.yml</code> in that folder, and created a folder named <code>html</code> in that folder. For the purposes of trying this out yourself, do the same.</p>
<h1>Run your Docker WordPress Site</h1>
<p>In a Terminal at the folder that contains your <code>docker-compose.yml</code>:</p>
<p>Start the Docker container:</p>
<pre><code class="language-bash">docker-compose up -d
</code></pre>
<p>Hint: You can omit the <code>-d</code> if you want to see the log stream for the Docker in your Terminal output (but not be returned to a command prompt).</p>
<p>The first time you run the container it will take longer to start as it downloads and sets up the images specified in your YAML.</p>
<p>At this point you should be able to point your browser at <code>localhost:8999</code> and see the WordPress set up screen. You can run through the setup as usual, and now you have a WordPress site running on your Mac.</p>
<p>To see all the containers Docker is running type the following in Terminal:</p>
<pre><code class="language-bash">docker ps
</code></pre>
<h1>A Note on the Files for this WordPress Install</h1>
<p>After running the container once notice that the files for this WordPress installation are all in the <code>html</code> folder. You can edit any of them there and the changes will be reflected the next time you reload a page of the WordPress site.</p>
<p>To demonstrate this, add a new PHP file named <code>info.php</code> to your <code>html</code> folder that runs:</p>
<pre><code class="language-php">&lt;?php
echo "Hello MSPWP!";
phpinfo();
</code></pre>
<p>Save the file, then point your browser to <code>localhost:8999/info.php</code>. That file should load, and show you details on the PHP installation in your Docker.</p>
<h1>Stopping your Docker</h1>
<p>Take down the container by running the following in a Terminal at the folder you created above:</p>
<pre><code class="language-bash">docker-compose down
</code></pre>
<p>Or simply quit the Docker app from the menubar; in this case when you relaunch Docker the containers (in this case, your WordPress site and its database) will automatically be ready to use. But to continue with this tutorial, for now leave it running.</p>
<h1>Install Visual Studio Code</h1>
<p>To install Visual Studio Code go to the <a href="https://code.visualstudio.com">Visual Studio Code download page</a>.</p>
<h1>Installing Extensions</h1>
<p>Visual Studio Code has a number of extensions. To access these go to the <strong>Extensions</strong> area by clicking the square item at the bottom of items in the lefthand sidebar of the window. You can install whatever extensions you’d like, but for the purposes of this tutorial make sure to install <em>PHP Debug</em>.</p>
<h1>Opening a folder in Visual Studio Code</h1>
<p>Going back to the top item in the lefthand sidebar (<strong>Explorer</strong>) a <strong>Welcome</strong> screen should still be shown. In it select the <em>Open folder…</em> option, and select your <code>mspwp</code> folder.</p>
<h1>Editing Local Files</h1>
<p>Open up <code>info.php</code> from the files list in the folder you opened in Visual Studio Code. Edit the <code>echo</code> line to say something else. Save the file and reload your browser window (or if it is pointed elsewhere, point it to <code>localhost:8999/info.php</code>).</p>
<p>Try your hand at navigating in Visual Studio Code and editing some more by making a change to the <code>header.php</code> file of the active theme (probably <code>twentyseventeen</code>) and loading <code>localhost:8999</code>.</p>
<h1>Set up XDebug</h1>
<p>To set up XDebug in your container we need to modify <code>docker-compose.yml</code>. First take down your container.</p>
<p>Change the <code>image</code> line for <code>wordpress</code> to use the <code>eceleste/docker-wordpress-xdebug</code> image. Also add <code>XDEBUG-CONFIG: remote_host={your ip}</code> to the <code>environment</code> section under <code>wordpress</code>. This new image includes XDebug, whereas the standard WordPress image is just the vanilla WordPress install with minimum other software.</p>
<p>Note, to find your Mac’s IP Address run the following in Terminal:</p>
<pre><code class="language-bash">ifconfig | grep "inet " | grep -Fv 127.0.0.1 | awk '{print $2}'
</code></pre>
<p>You can now restart your container.</p>
<h1>Using XDebug to Debug PHP in Visual Studio Code</h1>
<p>Go to the Debug area by choosing the debug item from the lefthand sidebar (thrd item down). Click on the green Run button, the first time you do this it should give you a menu to choose what kind of debugging to do, select PHP. This will create and open your <code>launch.json</code> file, which defines how the debugger should work. It is stored in the <code>.vscode</code> folder in your workspace (the folder you opened). The contents of this file should be:</p>
<pre><code class="language-json">{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9000,
"localSourceRoot": "${workspaceRoot}/html",
"serverSourceRoot": "/var/www/html"
},
{
"name": "Launch currently open script",
"type": "php",
"request": "launch",
"program": "${file}",
"cwd": "${fileDirname}",
"port": 9000
}
]
}
</code></pre>
<p>To test debugging, add a breakpoint in your <code>header.php</code> (click in the gutter by the line number to set a breakpoint at that line). Then run the debugger using the green Run button in the Debug area. With the debugger running you’ll have a debug control bar towards the top of the Visual Studio Code window.</p>
<p>Just reload the page in your browser and the debugger should come forward when your breakpoint gets hit. Look at the variables in the <code>Variables</code> section of this view. You can find and inspect all the usual WordPress variables, including <code>WP_Post</code>.</p>
<p>You can also manipulate the page as it loads using the Debug Console (should be towards the bottom of the Visual Studio Code window). For example, you can modify the post title by typing the following into the console and hitting return: <code>php $post-&gt;post_title = "Hello MSPWP"</code></p>
<p>The debugger can also be invoked for PHP notices, warnings, and exceptions. It will also let you follow all the way through your theme or plugin files, to parent theme and even core files, should you wish.</p>
<h1>Copying a Live Site to your Container</h1>
<p>To copy a live WordPress website to your container you need to both copy the <code>wp-content</code> files, and copy the database. We do not copy core files, as those might as well be the cleaner versions from the Docker image that was used.</p>
<p>Copy the <code>wp-content</code> files with the following while in your <code>mspwp</code> folder:</p>
<pre><code class="language-bash">rsync -a example.com/wp-content html/
</code></pre>
<p>If WordPress is installed in a subdirectory, be sure to include that in the path to copy from.</p>
<p>Assuming that you’re using something other than <code>wp_</code> as the table prefix, remember to update <code>wp-config.php</code> with the proper prefix for your site.</p>
<p>To copy the database, in an SSH connection to the live server, first dump the database contents (check in the live <code>wp-config.php</code> for the proper username and password):</p>
<pre><code class="language-bash">mysqldump -u username -p password > backup.sql
</code></pre>
<p>Copy <code>backup.sql</code> to your Mac. Then you may want to drop the current contents of the database in your container, so in a Terminal on your Mac:</p>
<pre><code class="language-bash">echo "drop database wordpress; create database wordpress;" | docker exec -i mspwp_db_1 mysql -u wordpress -pwordpress
</code></pre>
<p>Then import your backup file:</p>
<pre><code class="language-bash">docker exec -i mspwp_db_1 mysql -u wordpress -pwordpress wordpress < backup.sql
</code></pre>
<p>Yes, this will generate a warning about the idiocy of including the password on the command line, but in this case we don’t really care. To make a fresh backup of the database in your container, just grab it from MySQL:</p>
<pre><code class="language-bash">docker exec -i mspwp_db_1 mysqldump -u wordpress -pwordpress wordpress > backup.sql
</code></pre>
<h1>Further Reading</h1>
<ul>
<li><a href="https://wptavern.com/composing-a-wordpress-development-environment-with-docker">Composing a WordPress Development Environment with Docker</a></li>
<li><a href="https://docs.docker.com">Docker Documentation</a></li>
<li><a href="https://xdebug.org/docs/">XDebug Documentation</a></li>
</ul>
<h1>About the Presenters</h1>
<p>Eric and Alex Celeste do WordPress site management and development as <a href="https://www.tenseg.net">Tenseg LLC</a>. We have clients both locally and across the nation who work in a number of fields. We can be reached at <a href="mailto:[email protected]">[email protected]</a>.</p>
New version of the Subcaucus Calculator2015-12-19T12:00:00-06:00
https://www.tenseg.net
/blog/2015/12/19/new-version-of-the-subcaucus-calculator
<p>The new version 2.0 of our subcaucus calculator <a href="https://www.tenseg.net/software/subcalc">SubCalc</a> is now <a href="https://itunes.apple.com/us/app/subcalc/id352454097?mt=8">available on the App Store</a> for iPhones.</p>
<p>This is pretty important because caucuses are coming up here in Minnesota and the old version no longer worked on most recent iPhones. SubCalc is back and better than ever. It now shares the exact same calculation engine that we use on the <a href="https://www.sd64dfl.org/sub/">web version of SubCalc</a>.</p>
<p>It is still free, so if there is any chance you may need some help doing the proportional representation math during the coming caucus and convention season, go get version 2.0 of SubCalc right away.</p>
Admin Bar ID now on the Dashboard2012-12-13T12:00:00-06:00
https://www.tenseg.net
/blog/2012/12/13/admin-bar-id-now-on-the-dashboard
<p>We’ve tweaked the <a href="https://www.tenseg.net/software/adminbarid">WP Admin Bar ID Menu plugin</a> to also add ID numbers when you are in the Dashboard. It can be frustrating to not know the ID number of an item you are working on, and digging those numbers out of the crowded URL gets old fast. Now Admin Bar ID Menu adds that ID number to the “view” item in the admin bar. It uses various techniques to figure out what the right number should be, we hope the bases are covered, but welcome your input if you find a case we missed.</p>
<p>You can get the update by simply checking for updates in WordPress if the plugin is already installed.</p>
Subversion to Git Migration Checklist2012-03-03T12:00:00-06:00
https://www.tenseg.net
/blog/2012/03/03/subversion-to-git-migration-checklist
<p>Just a heads up for everyone, this post is a highly technical one for fellow developers, it is not something we expect most of you to find helpful or even fully comprehend.</p>
<p>Earlier this week we took the dive and migrated all of our active projects (not all of these have been publicly announced much less released) from <a href="https://projectlocker.com/">ProjectLocker</a> Subversion to <a href="https://bitbucket.org/">BitBucket</a> Git. In the process we formulated a checklist of the steps needed in this migration process. We’ve decided to post that checklist as a guide for anyone else interested in migrating projects. Please note that this checklist is entirely independent of what services you use for Subversion and Git. Anything that is within “[]” is a variable that you have to replace with the appropriate value given your setup. We hope this checklist may save you some time searching for pieces of this process on various websites.</p>
<p><em>A. Setup</em></p>
<ul>
<li>Make sure that all changes are committed into the SVN repo from Xcode</li>
</ul>
<em>B. Migration</em>
<ol>
<li>cd to svn checkout (project) directory</li>
<li>svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors-transform.txt</li>
<li>Edit the authors-transform.txt file to match desired Git user details</li>
<li>cd to home directory root (or any other place for the temporary Git repo)</li>
<li>mkdir temp_git_repo</li>
<li>cd temp_git_repo</li>
<li>git svn init [URL-TO-SVN-REPO] --no-metadata</li>
<li>git config svn.authorsfile [PATH-TO-AUTHORS-TRANSFORM-FILE]</li>
<li>git svn fetch</li>
</ol>
<em>C. Push to Git Remote</em>
<ol>
<li>git remote add origin [GIT-REMOTE-LOCATION]</li>
<li>git push -u origin master</li>
</ol>
<em>D. Replace SVN Version of project on filesystem/in Xcode with Git Version</em>
<ul>
<li>This is self-explanatory and specific instructions for this can be found within Xcode and its documentation</li>
<li>Essentially what is important to remember is that you use the "Checkout or Clone Repository" option in the Repositories organizer and paste in the same [GIT-REMOTE-LOCATION] used above</li>
<li>You can also delete the temp_git_repo folder at this time along with the old SVN-backed project folder</li>
</ul>
WP Admin Bar ID Menu updated for WP 3.32011-12-16T12:00:00-06:00
https://www.tenseg.net
/blog/2011/12/16/wp-admin-bar-id-menu-updated-for-wp-3-3
<p>We love WordPress updates and WP 3.3 is a doozy! Many things have changed, including the internals of how the admin bar is constructed. Today we introduce version 0.4 of our <a href="https://www.tenseg.net/software/adminbarid">WP Admin Bar ID Menu plugin</a> which allows the plugin to work with WP 3.3. Nothing else has changed about this plugin, it remains a very simple tool that just puts the ID number of a page or post into the admin bar alongside the “edit” menu item.</p>
<p>You can get the update by simply checking for updates in WordPress if the plugin is already installed.</p>
2024-12-07T12:00:00-06:00