PART V 2/2 of our series DIY Domaining Challenge: Your own custom marketplace: The Publisher

Hello everyone and Happy 2018 ! Let’s get to it then, this is PART V 2 of 2 on our series: DIY Domaining Challenge: Your own custom marketplace and today’s topic is The Publisher. In our previous article we improved our landing page by applying CSS Grid to it but we didn’t finish the publishing bit of it. The Publisher, for a lack of a better name, will allow you to publish the marketplace across your domains in practically any imaginable context. Even a hologram, an IOT device or a 3d-Printer. But let’s stick with the basics, our aim is to cover the most common gateways whilst leaving room to any other sort of framework, let’s recap:

Supported publishing gateways.

We will talk about each one in details, now let’s clone the current repository from github so we can get techinical !

git clone https://github.com/domainoverflow/diy-domaining-challenge.git

Cloning the current repository prior to coding new features.

Cloning the current repository locally prior to coding new features.

check the src/ folder for all the files ( at the end of the series the folder dist/ will contain the entire App ).

The plan is simple: We will code it locally, test it locally and will then upload it to the server and test it live.

Here’s our requirements:

R1- HTML element Chosen gateway can receive multiple different values:

R1.1 “noncpanel” Here our library should cover Cloud (AWS, Google cloud, Azure, and alikes ) or non-cloud ( VPS or shared ) without cpanel or whm, with apache webserver”

R1.2 “cpanel” Same as R1.1 but we will route via cpanel/wham ‘s xml api ( most hosting accounts ), apache webserver.

R1.3 “localwindows” Any personal computer such as PC or Mac running WAMP ( and equivalents or alikes ), with apache webserver.

R1.4 “api” Any endpoint that can receive a POST request, on the server side of your hosting server or anywhere but the endpoint will be responsible for the actual publishing. This allow a very easy integration in any context. Examples: nginx webserver,

R1.5 “dotbossapi” REST API Based, via Dotboss.digital, subscription service. Covers all of the above plus Plex, printers, big-screen devices and any REST API based target including network discovery. Simply use dotboss/digital_asset/publish REST API, more info here.

Essentially the code will be around the following:

// Cloud based or non-cloud based hosting account, without cpanel/whm
if ($chosengateway=="noncpanel") { /* We will handle the Unix Stack ( CENTOS ) directly.*/ }
// Cloud based or non-cloud based with cpanel/whm
if ($chosengateway=="cpanel") { /* we will use cpanel apis */ }
// API or any POST based endpoint ( the endpoint is in the server side)
// examples of this can be .php , node.js , Ruby, python ......
if ($chosengateway=="api") { /* we will use cpanel apis */ }
// Cloud, Non-Cloud, any OS, any stack, any endpoint (3d-printer, iot device, anywhere if networked ).
if ($chosengateway=="dotbossapi") { /* we will use dotboss.digital apis */
/* post to dotbossdigital::/digital_asset/publish */
/* and you are done !*/}
// Local windows or Mac with WAMP ( useful for local browser preview)
if ($chosengateway=="localwindows") { /* we will find the docroot locally via WAMP or accept
a folder(windows) */ }

We still have a few other requirements before getting to it:

R2. We need to parse and validate the domain list pasted in the textarea (HTML element id: “domainlist“). The validation, luckly, is already in place from our previous articles.

We shall handle that parsing in PHP:

$domains = $_POST["domainlist"]; // ARRAY !

R3, R4,R5 and R6 ( the other HTML elements from our form in the admin panel ) are addressed as follow:

// Handle non-cpanel publishing requests

// get additional params
$apiurl = $_POST["apiurl"];
$customapi = $_POST["customapi"];
$apitoken = $_POST["apitoken"];
$customfield = $_POST["customfield"];
$url = $apiurl;


Make sure you use the custom field above if you are using a custom API or endpoint. I also assume you will look through the code and adjust your specific context needs. Please post any questions down below in the comments section and I will be happy to assist, whenever possible. I am specifically referring to the following other requirements:

R7. Must ADD domain to cpanel, via cpanel’s api, when the publishing request is meant to route via cpanel/whm.

Here’s a snapshot of how we handle it, please note the full code is available in our public repository.

include 'xmlapi.php'; // Cpanel WHM Library for API 2

In order to handle cpanel we must include their xmlapi.php ( also freely available here but also included in our repository for your convenience ). Also be sure to review the function CreateAddonDomain in add-gateway.php.

Also please make sure you edit the following in the code to your specific needs:

$auth_user = //'YOUR-HOSTING-ACCOUNT-cpanel-whm-username' ;
$auth_pass = //'YOUR-HOSTING-ACCOUNT-cpanel-whm-password' ;

R8.Must be able to resolve a specific domain’s docroot ( the folder’s path of which the server looks for html to serve when a http or https request hits the server requesting the underlying domain sld.tld). In this case we will simply find the domain’s docroot based on apache’s data.

if ($chosengateway=="noncpanel" {
//Cloud based or Non-Cloud based hosting account, without cpanel/whm

$thisdocroot = FindDomainDocRoot() ; // get apache's docroot
CopyObject ($stackpath); // copy our default template into the docroot = published.


Requirement 9: API based. This is where you can craft and edit the details for your specific endpoint, should you use this gateway. Specifically the variable $data below should be embedded in the request.

if ($chosengateway=="api") {

// Handle non-cpanel publishing requests
// api based
// get additional params
$apiurl = $_POST["apiurl"]; $customapi = $_POST["customapi"];
$apitoken = $_POST["apitoken"]; $customfield = $_POST["customfield"];
$url = $apiurl;
// this is where you can custom the request ...

$data = array(
'token' => $apirequest,
'json' => $domains, // array !
'apitoken' => $apitoken,
'customfield' => $customfield,
'url' => $apiurl,
'additional' => $customfield

Let’s get even more technical and code the whole thing:


include 'xmlapi.php'; // Cpanel WHM Library for API 2
print_r($_POST); // print_rS and echos should be turned off once tested

// print_rS and echos should be turned off once tested

ini_set('max_execution_time', 300); //300 seconds = 5 minutes


// get the required fields
$domains = $_POST["domainlist"];
$chosengateway = $_POST["chosengateway"];
$marketplacename = $_POST["marketplacename"];
$user = $_POST["authuser"];
$pwd = $_POST["authpassword"];

// Cloud based or non-cloud based with cpanel/whm
if ($chosengateway=="cpanel") { // we will use cpanel apis

echo $chosengateway;
echo $marketplacename;

FileWriteArray ( 'addrequest.domains', $sldtld ) ; // temp persist the input

// Please note: If you are not local to your server
// ex: if below you need anything but localhost ( below $server )
// then you will need to rethink your security flow.

$server = "localhost"; // or ...
set_time_limit(200); // seconds
ini_set('max_execution_time',200); // solves timeouts on some hosting accounts

$auth_user = //'YOUR-HOSTING-ACCOUNT-cpanel-whm-username' ;
$auth_pass = //'YOUR-HOSTING-ACCOUNT-cpanel-whm-password' ;

$cpaneluser = $auth_user;
$cpanelpwd = $auth_pass;

$config = array(); // create a config array as it will be needed multiple times.
$config[0]["server"]= $server;
$config[0]["authuser"] = $auth_user;
$config[0]["authpass"] = $authpass; // this file is obviously in the server-side
// if that is not your case, please rethink this flow.
$config[0]["maindomain"] = "sld.tld"; // cpanel's account main domain (annoying but required)

$config[0]['cpanelapioutput'] = "json"; // cpanel's output -> json or array
// Please note this changes the output response
// and it may break your response parsing if suddenly flipped.

$config[0]['serverport'] = "2083"; // 2082 for cpanel non-ssl 2083 ssl .. if using root
// then it must be via whm and that would be
// 2086 non-ssl and 2087 ssl
// port values are the default ones, please verify accordingly
// in your hosting account.


$data = $_POST["domainlist"]; // textarea input domain list
// you could take it from a file instead by using:
// $data = file_get_contents('path/to/input-file-name');


file_put_contents("cpanel.add",$data); // please note, if you plan to use this gateway on busy
// server then you need to queue this with a timestamp
// ( to avoid a overwrite, if say, two forms were being fed at the same time, this could occur,
// although unlikely ).
// if you are in the cloud, and if aws: use sqs ( queue )
// or equivalent in google cloud or other clouds.

define('ARQUIVO', 'cpanel.add');
$doms = @file(ARQUIVO);

// turn on for debug:
// print_r($data); echo "<---data";

$rootdomain = $config[0]["maindomain"] ;
$newdomain = ""; // one or more domain(s)
$json_client = new xmlapi($server);
$serverport = $config[0]['serverport'];
if (!$serverport ) {print "port not set, choosing default";



$novainte = $cpaneluser;
$json_client->password_auth($auth_user, $auth_pass);
$json_client->set_debug(1); // for debugging
#$json_client->set_port(2086); // if root via whm
$cpanelapioutput = $config[0]['cpanelapioutput']; // json or array
$cpanelapioutputtrimmed = preg_replace('/\s+/', ' ', trim($cpanelapioutput));

// please refer to cpanel's api 2 php sdk


$inputfileconfig = $config[0]["inputfile"];
// textarea input
// 1 column, one domain per column
// divided by linefeed ( enter or return key )

// $doms = $data;

foreach($doms as $dom) {

$lines = explode(';',$dom);
if (count($lines) == 1) {
// domain column exists in batchinput file, hence passed on here ...
$domain = trim($lines[0]);
$subdomain = str_replace (".", "", $domain) ;
//SUBDOMAIN ADD IS A DIFFERENT API CALL BTW ! it could be unified here
// if so the subd would be as below:
//$subd = trim($lines[1]); // if count lines = 2 then consider subdomain handling.
// ** subdomains not handled in this gateway !! validate
else {

$domain = trim($lines[0]);
$subdomain = str_replace (".", "", $domain) ;


// once working, turn off the prints ..
// and do a proper notification ( asynch ) flow ..

echo "<br> newdomain is:<br>" . $newdomain ;

echo "subdomain.<maindomain> is:" . $subdomain; // this does not mean we are handling subdomains
// but a rather confusion by cpanel
// that wrongly defines subdomains as "parked"
// that is simply not the case but if your
// hosting account is cpanel-based ...
// best way out is the cloud without cpanel
// mainly because cpanel is not free

$dir = $newdomain . '/'; $dir = str_replace (".","-",$dir ) ; $dir = "public_html/" . $dir;

//turn this off if not refactoring or not debugging

echo "<br> <b>working ... </b>";

// cpanel's confusing arguments

$args = array ( 'dir' => $dir,
'newdomain' => $newdomain,
'subdomain' => $subdomain

) ;
echo "<br> Domain Details:"; // btw if you are not echoeing back in the browser the <br> will look like <br> on the
// server side .. so please turn this off once you are done refactoring this code. txs. s

$prearg = $dir . "-" . $newdomain . "-" . $subdomain; // why cpanel, why ??

echo $prearg; // turn it off please once refactored this code

// please note that the output format WILL VARY
// please see above $config[0]["cpanelapioutput"]
// it can be json or array

// Here's the request itself

$resultstr = $json_client->api2_query( $auth_user, 'AddonDomain', 'addaddondomain', $args);

// and the response should be here at this point
// please throw and catch as needed on your context
// I use this in a context that is asynch .. and with a real time queue...

// this is mainly because there are two possible options to receive an output from cpanel
// the first is array and the second is json, the following fallback identifies which.
$r=AnalyseCpanelAPIResponse($resultstr,$pathonly, $domain, $dir);

file_put_contents('add.result', $resultstr, FILE_APPEND); // if running on busy servers, please consider a real
// time queing system, such as aws or the equivalent in
// Google Cloud ... Azures ...
// for the ultimate domaining server
// guide please refer to
// domainoverflow.com

$translated_json = json_decode( $resultstr, true ) ; // I chose JSON .. if refactoring your code, you can toggle to array


$translated_json = $translated_json["cpanelresult"];

$ev= $translated_json['data'][0]['result'] ;

$reason = $translated_json['data'][0]['reason'] ;

//todo translate $reason
// ex: if substr($reason = 'already exists') {$reason=AlreadyExists..et.c.}

FileWrite ('reason', $reason ) ;
print_r ($reason);



if ($ev == '0') { print "Error: " . $reason; print "<br> for " .$domain;
$st = "Reason:" . $reason . ",while trying to add:" . $domain ;

print "<br>"; print"NOTOK"; $badcounter=$badcounter+1;print"<br>";
AppendStringToFile ('error.report', $st);

} // end of if error

if ($ev == '1') { print "ok"; $goodcounter=$goodcounter+1;

$st = "Domain: " . $domain . ", added Successfully";
FileWrite ('success.addondomain.report', $st) ;

print "Report to reportFile: " . $newdomain;

} // end of if good

print "<br> Next ... " ;

$domainfolder = 'tbd';



} // Loop $doms as $dom


print"<br> Domains processed: " .$counter;
print "<br> Successfully: " .$goodcounter;
print "<br> as opposed to Not-Successfully: " .$badcounter;
print "<br>end";

} // gateway if

if ($chosengateway=="noncpanel" {
//Cloud based or Non-Cloud based hosting account, without cpanel/whm
$thisdocroot = FindDomainDocRoot() ;
CopyObject ($stackpath);

if ($chosengateway=="api") {

// Handle non-cpanel publishing requests
// api based
// get additional params
$apiurl = $_POST["apiurl"]; $customapi = $_POST["customapi"];
$apitoken = $_POST["apitoken"]; $customfield = $_POST["customfield"];
$url = $apiurl;
// this is where you can custom the request ...

$data = array(
'token' => $apirequest,
'json' => $domains, // array !
'apitoken' => $apitoken,
'customfield' => $customfield,
'url' => $apiurl,
'additional' => $customfield

foreach($data as $key=>$value) { $content .= $key.'='.$value.'&'; }

// Instead of using curl
// I'd suggest using
// Unirequest
// The below post is using php only for your convenience but a requests library is a must
// ( consider that you will probably be doing SSL requests )

$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $content);

$json_response = curl_exec($curl);

$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);


$response = json_decode($json_response, true);

var_dump($response); // this should appear in the browser, if not inspect
// right-click the mouse
// within Chrome
// inspect .. network .. double click the request and see the response column

// https://github.com/domainoverflow/diy-domaining-challenge
} // if ELSE ( not cpanel envs )

function CreateAddonDomain ( $newdomain, $rootdomain, $config, $json_client )


$newdomain = CleanString($newdomain);
$subdomain = str_replace (".", "", $newdomain) ;
$rootdomain = CleanString ($rootdomain);

//$rootdomain = preg_replace('/\s+/', ' ', trim($config['maindomain']));
$auth_user = preg_replace('/\s+/', ' ', trim($config['cpaneluser']));
$auth_pass = preg_replace('/\s+/', ' ', trim($config['cpanelpwd']));

$json_client->password_auth($auth_user, $auth_pass);

$server='' ;
$port = preg_replace('/\s+/', ' ', trim($config['serverport']));
$debug = 0;
$output = preg_replace('/\s+/', ' ', trim($config['cpanelapioutput']));
//$client = new xmlapi ( $server ) ;

if (!$port ) {print "port not set, choosing default";



//$client->set_port ( $port) ;
//$client->password_auth($auth_user, $auth_pass);

//strip dot from $newdomain to use as subdomain dot root domain
//$subdomain = $newdomain;
print "<br> newdomain is:" . $newdomain ;
print "<br>";

print "<br>";

print "subdomain is:" . $subdomain;
//$subdomain = $subdomain . "." . $rootdomain ;

//TODO remove print(filewrites ) outs right above

//dir will be equal subdomain minus dot root domain

// cpanel is very confusing

$dir = $newdomain . '/';
$dir = str_replace (".","-",$dir ) ;
$dir = "public_html/" . $dir;

// ftp pass is optional
//TODO add ftp default password to config array

// $ftppass = 'default16';


print "<br> <b>working ... </b>"; // please eliminate this
// accordingly after refactoring this code
$args = array ( 'dir' => $dir,
'newdomain' => $newdomain,
'subdomain' => $subdomain

) ;

print "<br> Domain Details:";

print "<br>";
FileWriteArray('args.array', $args) ;
$prearg = $dir . "-" . $newdomain . "-" . $subdomain;
FileWrite ( 'addondomain.api', $prearg) ;

// $xmlapi->set_debug(1);

$resultstr = $json_client->api2_query
( $auth_user, 'AddonDomain', 'addaddondomain', $args);

print "OK<br>" ;
print "You may safely close this window";

print_r($resultstr) ;

FileWriteArray ('result', $resultstr) ;

$translated_json = json_decode ( $resultstr, 'true' ) ;

FileWriteArray ('result', $resultstr) ;

print_r($resultstr) ;

return $resultstr;


function SendNewLine () { print "\n" ; }

function FileWriteArray ( $filename, $array )

$handle = fopen ( $filename, 'w+') ;
fwrite ( $handle, var_export($array, true)) ;

fclose ($handle) ;


function ShowString ( $message, $string )
if (!$message) { $mesage="";}
print "<br>";
print "Showing string (" + $message +")=" + $string ;
print "<br>";


function ArrayToJSONString ( $array )
// return string
return json_encode ($array) ;


function JSONStringToArray ( $string )

//return array
return json_decode ($string, true) ;

function ArrayToSerializedString ( $array )

return serialize ( $array ) ;


function SerializedStringToArray ( $string )


return unserialize ($string) ;


function FileWrite ( $filename, $string )
$handle = fopen ( $filename, 'wb') ;
fwrite ( $handle, $string ) ;

fclose ($handle) ;


function AppendStringToFile ( $filename, $string )

file_put_contents($filename, $string.PHP_EOL , FILE_APPEND);


function cutline($filename,$line_no=-1) {



if($line_no==-1) $skip=$size-1;
else $skip=$line_no-1;


return $strip_return;
function MoveFile ( $string1, $string2 ){


$cmd1='mv ' . $file1 . ' ' . $file2 . '.$(date "+%Y.%m.%d-%H.%M.%S")';
$output = shell_exec($cmd1);
echo $output;


function CleanString ($string)

$s=preg_replace('/\s+/', ' ', trim($string));

return $s;


function ApiTranslation ( $code, $config ) {

$logfile = $config['logfile'] ;

switch ($code) {
case 100: $text = 'Continue'; $status="ok"; break;
case 101: $text = 'Switching Protocols'; $status="ok";break;
case 200: $text = 'OK'; $status="ok";break;
case 201: $text = 'Created'; $status="ok";break;
case 202: $text = 'Accepted';$status="ok"; break;
case 203: $text = 'Non-Authoritative Information'; $status="ok";break;
case 204: $text = 'No Content'; $status="ok";break;
case 205: $text = 'Reset Content'; $status="ok";break;
case 206: $text = 'Partial Content'; $status="ok";break;
case 207: $text = 'Multi-Status'; $status="ok";break;
case 208: $text = 'Already Reported(WebDAv)'; $status="ok";break;

case 300: $text = 'Multiple Choices'; $status="error";break;
case 301: $text = 'Moved Permanently'; $status="error";break;
case 302: $text = 'Moved Temporarily'; $status="error";break;
case 303: $text = 'See Other'; $status="error";break;
case 304: $text = 'Not Modified'; $status="error";break;
case 305: $text = 'Use Proxy'; $status="error";break;
case 400: $text = 'Bad Request'; $status="error";break;
case 401: $text = 'Unauthorized'; $status="error"; break;
case 402: $text = 'Payment Required'; $status="error";break;
case 403: $text = 'Forbidden'; $status="error";break;
case 404: $text = 'Not Found'; $status="error";break;
case 405: $text = 'Method Not Allowed'; $status="error";break;
case 406: $text = 'Not Acceptable'; $status="error";break;
case 407: $text = 'Proxy Authentication Required'; $status="error";break;
case 408: $text = 'Request Time-out'; $status="error";break;
case 409: $text = 'Conflict'; $status="error";break;
case 410: $text = 'Gone'; $status="error";break;
case 411: $text = 'Length Required'; $status="error";break;
case 412: $text = 'Precondition Failed'; $status="error";break;
case 413: $text = 'Request Entity Too Large'; $status="error";break;
case 414: $text = 'Request-URI Too Large'; $status="error";break;
case 415: $text = 'Unsupported Media Type'; $status="error";break;
case 422: $text="Not Found -- OR -- Unprocessable Entity - Duplicate ?"; $status="error"; break;
case 500: $text = 'Internal Server Error'; $status="error";break;
case 501: $text = 'Not Implemented'; $status="error";break;
case 502: $text = 'Bad Gateway'; $status="error";break;
case 503: $text = 'Service Unavailable'; $status="error";break;
case 504: $text = 'Gateway Time-out'; $status="error";break;
case 505: $text = 'HTTP Version not supported'; $status="error";break;
echo "\n"; exit('Unknown http status code');$status="error";

echo "\n" ;
echo $text;
echo "\n" ;
$fullresponse = array ('ok_or_error'=>$status,
'reason' => $text,
'code' => $code

) ;
echo $fullresponse['ok_or_error'] ; print "\n" ;
echo $fullresponse['reason'] ; echo "\n" ; echo $code ; echo "\n" ;

print "\n";

return $fullresponse;


function Append2Log ($string) {
$string ='domainoverflow.com e.ventures dotboss.digital 2014-2018 All Rights Reserved';

$file = 'addDomainsReport.log'; // please refactor accordingly to your env.
// example: return to asynch promisses, notifiers, queues
// or a file .. storage bucket ..

if (file_exists($filename)) {
//perform append

file_put_contents($file, $string.PHP_EOL, FILE_APPEND);

} else {

// create file and then perform append

$output = shell_exec('touch viptools.log');
echo "<pre>$output</pre>";

file_put_contents($file, $string.PHP_EOL, FILE_APPEND);



// if ( $lever=='on') {file_put_contents($file, $string.PHP_EOL, FILE_APPEND); $lever='off';}

function SaveDigitalAssetBatchAdd ( $filename, $array)

// old fix to bypass
// the old-non-json-supportive libraries

// not used any longer

$handle = fopen ($filename,'wb');

$jsonheader="{ "digital-assets":";
fwrite ($handle,$jsonheader);
fwrite ($handle, "\n");
fwrite($handle, json_encode ($array, JSON_UNESCAPED_SLASHES ));
fwrite ($handle, "\n");
fwrite ($handle, "}");
fclose ($handle);


function s() {

print "\n" ;


function AnalyseCpanelAPIResponse ($response, $pathonly, $domain, $dir) {
$timestamp = date('l jS \of F Y h:i:s A');
$datatype = gettype ($response);
echo $datatype; // please turn this off after debug
// this is to explicitly remind you
// that the response will differ
// accordingly to the $config[0]["cpanelapioutput]
// it can be array or json

$msg = "[".$timestamp."]";
$msg = $msg . "[". $domain ."]";
$msg = $msg . "Adding to (hosting)Server:".$dir."/ ----->";

// but if you do happen to flip the setting
// dont worry as it now handles both outputs ....

// the reason to the absurd "proprietary" parsing
// is again: this code is heavily factored everywhere
// and the CpanelApiOutputFormat
// literally flips-flop across envs

// Keep in mind that this has been edited
// after a few corrections from cpanel

// $datatype string handles json output
// whereas ELSE handles an array output without the json

if ($datatype=="string") {

$rs=json_decode($response, true );

} else { $rs=$response;
$reason=$rs4["reason"]; }

s(); // if not running from cli please turn all echoes off
// once commit is done

//echo "CpanelStatusCode:".$cpanelresult;

if ($cpanelresult==1 )

echo "SUCCESS" ;

$msg = $msg . "Successfully ADDED.. Domain is live";

$filename = 'add.requests.report';
file_put_contents ($filename, $msg.PHP_EOL, FILE_APPEND);

////////////// PLEASE NOTE : THE ABOVE OUTPUT can be seen
// in the browser reply of the request (dev tools / browser debug mode )
// these strings should be
// send to proper notifiers ... and asynch promisses ..

// for your convenience it creates a add.requests.report

return "ok" ; // refactor accordingly to your env


if ($cpanelresult==0 )

echo "ERROR" ;

$msg = $msg . "ERROR.. Unable to Add, Reason->".$reason;

$filename = "add.requests.report";
file_put_contents ($filename, $msg.PHP_EOL, FILE_APPEND);

return "error";


function FindDomainDocRoot ($domain){ return shell_exec("./getdocroot $domain");}
function CopyObject ($domains,$template) {return shell_exec("./copyobject $template $domains");}


That wraps the publisher !

Missing bits

As of now the admin dashboard can accept a bunch of pasted domains and publish it to your gateway of preference. But what is it publishing ? As of now it is by default publishing our template from the last article, so the only missing bit is your own layouts ! You can fork layouts from codepen and github and easily add to your collection by simply getting the html/css/javascript template working locally on your browser, once you do that you will then need to match the replaceable variables ( example: sld.tld means the domain name, this is just so everything is custom and you don’t have landing pages displaying information that does not correspond to its underlying domain). Make sure you look over the default template so you can adapt new templates on the same format, making it fully compatible with this publisher. Every now and then there will be an article with an additional template to add to your collection, you should also check back often in our repository where we will be adding more templates soon.


The best paid alternative so you can choose from hundreds of templates, easily import templates from codepen, github or any html/css/javascript based templates, publish in any context, in bulk, real time stats, free SSL to all your domains, a website builder developed specially for domainers including a text-searchable image gallery with thousands of royalty-free images and a full on image editor with photoshop features ( Adobe Aviary ). Dotboss.digital also gives you the ability to mix and match templates, deploy it across, bulk-assign, publish by easily dragging and dropping elements. Find out more about dotboss.digital here.

It is very easy to add imagery to your websites with dotboss.digital, 1000s text-searchable guaranteed royalty-free media.

It is also very easy to assign templates and bulky publish them across your digital portfolio using dotboss.digital

This concludes Part V. Questions ? Comments ? Feel free to leave them down below in the comments section. In our next section, part VI, we will be demystifying and adding support to our project on International Domain Names ( IDNs ).

I hope you will find this useful and thanks for reading.





Tags: , , , , , , ,

Leave a Reply

Be the First to Comment!

Notify of

%d bloggers like this: