Blog, CMS, Web, Wordpress

Enterprise Website Consolidation: What I Did, and Why You Should

When you are a responsible party concerning your companies’ websites, many challenges come up along the way. And one of the toughest challenges I have faced in my career supporting enterprise architecture was working with business partners to make an enterprise decision over an easy one.

The Problem: Over the course of weeks, my discovery revealed 25 separate websites across 5 different content management systems (CMS), hosted in 10 different servers and locations. Websites in the same CMS platforms were on different versions of the same CMS as well as infrastructure patching schedules. There was no form of source control nor any consistent configuration around the administration services. These complexities not only led to continual issues that had to be managed daily but in turn tied up development resources from focusing on other work. The conclusion was clear that over time the management of the web CMS systems and IT resources would continue to bloat cost and time to delivery on new projects.

What seems like the right idea: As these problems continue to come up, I recall this being presented in ideas and exploration, “Let’s just put more people on all of these to get them updated. The issue with the easy decision, however, is that the one-time fixes only prolong the root problems. You may have very sharp employees that are more than capable of knocking out these odds and ends jobs, but as any other updates begin to repeat themselves, the cycle repeats itself once more.

The Enterprise Solution: After all research had been done, the answer was clear: consolidating websites down into the same CMS would reduce the ongoing people support issues while improving the time to delivery on projects. The CMS itself needed to be a platform that allowed for scalability and ease of configuration. Finally, automation was going to be key in how it would assist in accomplishing operations and tasks that reduced unneeded internal labor.

The Results? 80% overall savings: After a 2 1/2-year transformation, 25 external websites were consolidated into WordPress via WP Engine. WP Engine was our manage services platform of choice, providing enterprise capabilities for all sites with a single pane of glass CMS management experience. Comparing against the 3-year cost-to-date prior spend of 1.5 million dollars we were able to move all sites and cover hosting in a single platform and cover it all 20% the cost. We not only realized cost savings to give dollars saved back to the business but was able to reallocate 2.5 FTEs worth of employees’ time onto other transformative efforts.

In addition, not only did we improve our hosting and patching automations, but we also enabled development pipelines from source control to have a controlled deployment strategy that went across multiple environments. This empowered a level of Quality Assurance testing and site monitoring we had yet to achieve.

Customer feedback: Our website editors and stakeholders were beyond thrilled to have only one editing experience to learn and use day to day. Our support teams were also happy, and our overall calls and reported issues were reduced!

Enterprise principles that supported my decision:

  • Consolidating competing CMS technologies allows for the management of a single platform
  • Leveraging a managed services platform allows a hands-off approach from development resources with ongoing maintenance; maintenance becomes core to the platform and is more easily managed
  • Developing your code within a source control platform allows for version management and prepares you to start considering your deployment strategies

Enterprise ROI savings can be realized by:

  • Retiring dedicated or hosting infrastructure
  • Reducing editor licenses in separate CMS systems
  • Removing extra 3rd party dependencies specific to an unneeded system
  • Removing unneeded external resources and/or support services costs to assist with troubleshooting
  • Leveraging your existing resources to be focused on new development and no longer in maintain mode

Regardless of your end decision on a specific product set to support your development team skillsets, one of the keys to drive repeatable enterprise development is to align decisions around simplifying management and driving automation of patching and version upgrades. CMS companies that thrive in licensing will nickel and dime you to bits on progress that you’ll never achieve with always fighting against yourself within their own products. If you’re not able to click less than 5-7 clicks to deliver a fully automated blank site to use, then reconsider your options. Make it a goal to center your platform decisions around their ability to leverage automation in how you can reduce unneeded activities. Automation will empower your staff to focus on new development.

HTML, JavaScript, Troubleshooting, Web, Wordpress

SOLVED: Contact form 7 Submission Won’t Send, Stuck on Spinning Wheel

In a recent update on WordPress CMS and my existing plugins I noticed that form submissions started slowing a bit on entries. In checking this I found that the form would attempt to submit but would stay in a spinning stage and never validate or submit it.

So, here’s what I did to update for a fix.

1) Head to the plugin editor, update the link below:

https://yourwebsite.com/wp-admin/plugin-editor.php?plugin=contact-form-7%2Fwp-contact-form-7.php&Submit=Select

2) Look for the section:

if ( ! defined( 'WPCF7_LOAD_JS' ) ) {
	define( 'WPCF7_LOAD_JS', true );
}

3) Update this to:

if ( ! defined( 'WPCF7_LOAD_JS' ) ) {
	define( 'WPCF7_LOAD_JS', false );
}

4) Clear cache and try your form again. a good way to see if the spinning wheel issue goes away is if your required fields respond.

Caveats:

  • The form will no longer send with ajax since you have disabled the javascript.
  • If you update the plugin in any way and have the problem again you will need to reapply this change.

You can keep up with the ongoing reference to this issue on Contact Form 7’s website.

HTML, JavaScript, Web, Wordpress

Need A Quick CSS Override On Just One Page Via JavaScript?

Found this to work really well for a WordPress custom theme where the only option I had was to drop an override via a header/footer plugin option:

<script>
var ref= window.location.pathname;
var search="/youruniquepagelink/";
if (ref.indexOf(search) > -1) {
let myElements = document.querySelectorAll(".your-class");
for (let i = 0; i < myElements.length; i++) {
	myElements[i].style.display = "none";
}
}
</script>
Programming, SharePoint, Web

SOLVED: Redirect a SharePoint page using a meta tag to a new URL

I have a SharePoint tenant where we are working to redirect some existing pages over to landing pages that are providing instructions for migrating. Needed something short and sweet to flip it over without much trouble. It’s easier to manage with a meta rather than fighting the “making your external client side javascript work with SharePoint” fight. This one takes less than 5 minutes.

So via SharePoint Designer:

<meta http-equiv="refresh" content="0;url=http://your-url-goes-here" />

That’s it. Onto the next one!

API, Box, C#, Certificates, Web, XML

How To Use the Box API To Adjust User Properties and Make Read-Only in Bulk (w/example)

  • Get up to date on the APIs you need for users @ https://developer.box.com/v2.0/reference
  • Sign up for your developer account at your enterprise @ https://yourenterprise.app.box.com/developers/console (replace with your enterprise application name in the link above)
  • Create your Box app & API Key – link here and here
  • Pull down the Box Windows SDK @ – https://github.com/box/box-windows-sdk-v2
  • Update the pem file with your actual pem information from the app you created
    • in case you’re wondering it should contain the —–BEGIN ENCRYPTED PRIVATE KEY—– and —–END ENCRYPTED PRIVATE KEY—–
  • Update the properties appropriately in the app.config
  <appSettings>
    <add key="boxClientId" value="uniquestringhere" />
    <add key="boxClientSecret" value="uniquestringheretoo" />
    <add key="boxEnterpriseId" value="1234567" />
    <add key="boxPrivateKeyPassword" value="uniquestringhereforpassword" />
    <add key="boxPublicKeyId" value="uniquepublickeyid" />
    <add key="ClientSettingsProvider.ServiceUri" value="useifneeded" />
  </appSettings>
  • From there you can update your Main runner in the program.cs appropriately. In the case of my sample below I am getting authorized, retrieving my users and looping through everyone but the main admin account and making them read-only. I’m also writing the information out to a file so I’ll have the logs of who was set / not set.
 
            var privateKey = File.ReadAllText("private_key.pem");

            var boxConfig = new BoxConfig(CLIENT_ID, CLIENT_SECRET, ENTERPRISE_ID, privateKey, JWT_PRIVATE_KEY_PASSWORD, JWT_PUBLIC_KEY_ID);
            var boxJWT = new BoxJWTAuth(boxConfig);

            var adminToken = boxJWT.AdminToken();
            Console.WriteLine("Admin Token: " + adminToken);
            Console.WriteLine();

            var adminClient = boxJWT.AdminClient(adminToken);

            var items = await adminClient.UsersManager.GetEnterpriseUsersAsync("", 0, 1000);
            items.Entries.ForEach(async i =>
            {
                if (i.Login != "myspecialadminaccount@domain.com")
                {
                    BoxUserRequest userRequest = new BoxUserRequest()
                    {
                        Id = i.Id,
                        Status = "cannot_delete_edit_upload"
                    };
                    System.Console.WriteLine("\t{0}", i.Name);
                    System.Console.WriteLine("\t{0}", i.Id);
                    System.Console.WriteLine("\t{0}", i.Login);
                    System.Console.WriteLine("\t{0}", i.Type);
                    System.Console.WriteLine(" ");
                    // Turn on for prod
                    BoxUser user = await adminClient.UsersManager.UpdateUserInformationAsync(userRequest);
                    Console.WriteLine(userRequest.Name + "updated to read-only");
                    System.Threading.Thread.Sleep(2000);
                    stringtext = i.Name.ToString() + " - " + i.Id.ToString() + " - " + i.Login.ToString() + " - " + i.Type.ToString() + " - updated to readonly" + Environment.NewLine;
                    System.Console.WriteLine(" ");
                    
                }
                else
                {
                    BoxUserRequest userRequest = new BoxUserRequest()
                    {
                        Id = i.Id
                    };
                    System.Console.WriteLine("\t{0}", i.Name);
                    System.Console.WriteLine("\t{0}", i.Id);
                    System.Console.WriteLine("\t{0}", i.Login);
                    System.Console.WriteLine("\t{0}", i.Type);
                    System.Console.WriteLine(" ");
                    Console.WriteLine(userRequest.Name + " NOT updated to read-only");
                    System.Threading.Thread.Sleep(2000);
                    stringtext = i.Name.ToString() + " - " + i.Id.ToString() + " - " + i.Login.ToString() + " - " + i.Type.ToString() + " - NOT updated to readonly" + Environment.NewLine;
                    System.Console.WriteLine(" ");
                    
                }
            });
            File.AppendAllText("C:\\Temp\\" + "log.txt", stringtext);
  • Enable your box application to your enterprise accounts – link here
  • Run your app (In TEST with test accounts! Then, with approval, prod.)
    • If the app won’t run…check:
      • code syntax errors
      • certificate pem
      • values in the app config
      • authorization status in the admin Console on Box
      • that your app is enabled and still available on the enterprise developer site

Hope this helps! I can send the source out on request if needed (just let me know).