Skip to content

Instantly share code, notes, and snippets.

@tonypartridge
Created October 5, 2022 03:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tonypartridge/fc2ae6dce12acec4bb527dd4af739a4e to your computer and use it in GitHub Desktop.
Save tonypartridge/fc2ae6dce12acec4bb527dd4af739a4e to your computer and use it in GitHub Desktop.
JomClassifieds to DJClassifieds Migration Script - Joomla 3 -> 4
<?php
/**
* This script is to be placed in the root of Joomla! and run via the browser,
* it will empty DJ Classifieds tables so can only be used on w J4 sites
* you MUST have already copied the Joomla! Users over too as we just set the user_ids.
**/
define('_JEXEC', 0);
$mediaFolderReplacement = 'com_jomclassifieds'; // replace com_jomclassifieds with this value; i.e. /media/classifieds_archive instead of the original /media/jom_classifieds
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// Saves the start time and memory usage.
$startTime = microtime(1);
$startMem = memory_get_usage();
if (file_exists(dirname(__DIR__) . '/includes/defines.php')) {
include_once dirname(__DIR__) . '/includes/defines.php';
}
if (!defined('_JDEFINES')) {
define('JPATH_BASE', dirname(__DIR__) . '/public_html');
require_once JPATH_BASE . '/includes/defines.php';
}
// Check for presence of vendor dependencies not included in the git repository
if (!file_exists(JPATH_LIBRARIES . '/vendor/autoload.php') || !is_dir(JPATH_ROOT . '/media/vendor')) {
echo file_get_contents(JPATH_ROOT . '/templates/system/build_incomplete.html');
exit;
}
require_once JPATH_BASE . '/includes/framework.php';
use Joomla\CMS\Factory;
// Fetch the JomClassifieds Records
$db = Factory::getContainer()->get('DatabaseDriver');
$db->truncateTable('#__djcf_items'); // Remove Items(adverts)
$db->truncateTable('#__djcf_images'); // Remove Images
$db->truncateTable('#__djcf_categories'); // Remove Categories
$db->truncateTable('#__djcf_regions'); // Remove Regions
$db->truncateTable('#__djcf_types'); // Remove Field Types
$db->truncateTable('#__djcf_fields'); // Remove Fields
$db->truncateTable('#__djcf_fields_values');// Remove Field Values
$db->truncateTable('#__djcf_fields_xref'); // Remove Field Category Maps
// Fetch the JomClassifieds categories
$query = $db->getQuery(true)->select('*')->from($db->quoteName('#__jomcl_categories'))->order('id ASC');
$db->setQuery($query);
$categories = $db->loadObjectList(); // id - title - alias - parent - icon - ordering - published - metakeywords - metadescription
foreach($categories as $category) {
$cat = new stdClass();
$cat->id = $category->id;
$cat->name = $category->title;
$cat->alias = $category->alias;
$cat->parent_id = $category->parent;
$cat->price = 0.00;
$cat->description = '';
$cat->ordering = $category->ordering;
$cat->published = $category->published;
$cat->autopublish = 0;
$cat->metakey = $category->metakeywords;
$cat->metadesc = $category->metadescription;
$cat->access = 0;
$cat->points = 0;
$cat->ads_disabled = 0;
$cat->theme = 0;
$cat->access_view = 1;
$cat->access_iew_item = 1;
$cat->restriction_18 = 0;
$cat->rev_group_id = 0;
$cat->schema_type = 'Offer';
$cat->metarobots = '';
$cat->metatitle = '';
$cat->ads_limit = 0;
$cat->header_text = '';
$catID = $db->insertObject('#__djcf_categories', $cat);
}
// Now fetch and build the regions / locations
// Fetch the JomClassifieds categories
$query = $db->getQuery(true)->select('*')->from($db->quoteName('#__jomcl_locations'))->order('id ASC');
$db->setQuery($query);
$locations = $db->loadObjectList(); // id - name - alias - type - parent - ordering - published
foreach($locations as $location) {
$loc = new stdClass();
$loc->id = $location->id;
$loc->name = $location->name;
$loc->parent_id = $location->parent;
$loc->country = $location->parent > 0 ? 0 : 1; // Assume that it has no parent if it is a country
$loc->city = 0; // No way of determining without a complex loop. Can always batch re-order in Joomla!
$loc->published = $location->published;
$loc->latitude = 0.000000000000000;
$loc->longitude = 0.000000000000000;
$loc->country_iso = ((int) $location->parent === 0) ? getIsoCode($location->name) : '';
$loc->header_text = '';
$loc->alias = $location->alias;
$loc->ordering = $location->ordering;
$loc->metatitle = '';
$loc->metakey = '';
$loc->metatitle = '';
$loc->metadesc = '';
$loc->metarobots = '';
$loc->ads_disabled = 0;
$locID = $db->insertObject('#__djcf_regions', $loc);
}
// Now build the property types(djclass) / tags (jomclassifieds)
$query = $db->getQuery(true)->select('*')->from($db->quoteName('#__jomcl_tags'))->order('id ASC');
$db->setQuery($query);
$tags = $db->loadObjectList(); // id - name - type - image - txtcolor -bgcolor - bdrcolor - style - ordering - published
foreach($tags as $tag) {
$type = new stdClass();
$type->id = $tag->id;
$type->name = $tag->name;
$type->price = 0.00;
$type->points = 0.00;
$type->ordering = $tag->ordering;
$type->published = $tag->published;
$type->params = '{"bt_class":"bt_exchange","bt_use_styles":"1","bt_color":"' . $tag->txtcolor . '","bt_bg":"' . $tag->bgcolor . '","bt_border_color":"' . $tag->bdrcolor . '","bt_border_size":"1","bt_style":"border-radius:2px;padding:2px 4px;;margin:3px 5px;"}';
$typeId = $db->insertObject('#__djcf_types', $type);
}
// Build custom field mapping... sheesh!
$query = $db->getQuery(true)->select('*')->from($db->quoteName('#__jomcl_extrafields'))->order('id ASC');
$db->setQuery($query);
$cFields = $db->loadObjectList(); // id - label - catids (space seperated) - type - value - description - required - searchable - searchtype (seems same as type) - ordering - published - is_compare
$fieldsArray = []; // We need this to save another DB Call for values etc - Shouldn't be heavy.
foreach($cFields as $eField) {
$field = new stdClass();
$field->id = $eField->id;
$field->group_id = 0;
$field->name = \Joomla\CMS\Filter\OutputFilter::stringURLSafe($eField->label);
$field->label = $eField->label;
$oldTypes = ['textfield', 'minmax'];
$newTypes = ['inputbox', 'inputbox'];
$field->type = str_replace($oldTypes, $newTypes, $eField->type);
// Fetch and decode original values
$values = json_decode($eField->value);
$groupedValues = [];
$fieldsArray[$eField->id] = []; // set as array
foreach($values as $value) {
if(empty($value->value)) continue;
$groupedValues[] = trim($value->name);
$fieldsArray[$eField->id][$value->value] = trim($value->name);
}
$fieldsArray[$eField->id]['type'] = $eField->type;
$field->values = implode(';', $groupedValues);
$field->default_value = '';
$field->params = '';
$field->in_search = $eField->searchable;
$field->search_type = '';
$field->search_value1 = '';
$field->search_value2 = '';
$field->published = $eField->published;
$field->required = $eField->required;
$field->description = $eField->description;
$field->access = 1;
$field->in_table = 0;
$field->in_blog = 0;
$field->in_item = 0;
$field->in_module = 0;
$field->source = 0;
$field->ordering = $eField->ordering;
$field->numbers_only = 0;
$field->in_registration = 0;
$field->hide_on_start = 0;
$field->profile_source = 0;
$field->core_source = '';
$field->in_search_on_start = 0;
$field->date_format = '';
$field->edition_blocked = 0;
$field->chx_filter_logic = 0;
$field->class = '';
$field->attribs = '';
$field->all_cats = ($eField->catids == 0) ? 1 : 0;
$field->input_type = 'text';
$field->placeholder = '';
$field->search_show_label = 1;
$field->icon = '';
$field->use_in_word_search = 0;
$field->sortable = 0;
$field->search_placeholder1 = '';
$field->search_placeholder2 = '';
$fieldID = $db->insertObject('#__djcf_fields', $field);
// Now we need to assign this field to its categories if it has any.
if($eField->catids != 0) {
$cats = explode(' ', $eField->catids);
foreach($cats as $c) {
if(empty($c)) continue;
$cat = new stdClass();
$cat->cat_id = $c;
$cat->field_id = $eField->id;
$cat->ordering = 1;
$catMapID = $db->insertObject('#__djcf_fields_xref', $cat);
}
}
}
// Fetch and the field Values....
$query = $db->getQuery(true)->select('*')->from($db->quoteName('#__jomcl_extrafields_values'))->order('id ASC');
$db->setQuery($query);
$cFieldValues = $db->loadObjectList();
foreach($cFieldValues as $cfv) {
if(!empty($cfv) && !isset($fieldsArray[$cfv->fieldid][trim($cfv->value)])) continue;
$cfvi = new stdClass();
$cfvi->field_id = $cfv->fieldid;
$cfvi->item_id = $cfv->advertid;
if($fieldsArray[$cfv->fieldid]['type'] === 'radio' || $fieldsArray[$cfv->fieldid]['type'] === 'selectlist')
{
$cfvi->value = $fieldsArray[$cfv->fieldid][trim($cfv->value)];
} else {
$cfvi->value = trim($cfv->value);
}
if(!empty($cfvi->value))
{
$cfvID = $db->insertObject('#__djcf_fields_values', $cfvi);
}
}
// Fetch the JomClassifieds Records
$query = $db->getQuery(true)->select('*')->from($db->quoteName('#__jomcl_adverts'))->where($db->quoteName('catid') . ' <> 0 ' )->where($db->quoteName('userid') . ' <> 919')->order('id ASC');
$db->setQuery($query);
$adverts = $db->loadObjectList();
$count = 0;
foreach($adverts as $record) {
$djRecord = new stdClass();
$djRecord->id = $record->id;
$djRecord->cat_id = $record->catid;
$djRecord->type_id = $record->tagid;
$djRecord->user_id = $record->userid;
$djRecord->name = $record->title;
$djRecord->alias = $record->alias;
$djRecord->description = $record->description;
$djRecord->intro_desc = '';
$djRecord->date_start = $record->createddate;
$djRecord->date_exp = $record->expirydate;
$djRecord->date_mod = $record->updateddate;
$djRecord->date_sort = $record->createddate;
$djRecord->display = 1;
$djRecord->special = 0;
$djRecord->notify = 0;
$djRecord->published = $record->published;
$djRecord->ordering = 0;
$djRecord->price = $record->price;
$djRecord->price_negotiable = 0;
$contactInfo = '';
if(!empty($record->phonenumber)) {
$contactInfo = 'Phone on: ' . $record->phonenumber;
}
$djRecord->contact = $contactInfo;
$djRecord->pay_type = NULL;
$djRecord->address = $record->address;
$djRecord->region_id = $record->region;
$djRecord->exp_days = $record->expired ? 0 : 14; // Two weeks by default?
$djRecord->promotions = '';
$djRecord->post_code = $record->postalcode;
$djRecord->video = '';
$djRecord->website = '';
$djRecord->ip_address = $record->ip_address;
$djRecord->currency = '£';
$djRecord->metakey = $record->meta_keywords;
$djRecord->metadesc = $record->meta_description;
$djRecord->latitude = (int) $record->latitude;
$djRecord->longitude = (int) $record->langtitude;
$djRecord->email = $record->email;
$djRecord->token = '';
$djRecord->access_view = 0;
$djRecord->extra_images = 0;
$djRecord->extra_images_to_pay = 0;
$djRecord->extra_chars = 0;
$djRecord->extra_chars_to_pay = 0;
$djRecord->auction = 0;
$djRecord->bid_min = 0.00;
$djRecord->bid_max = 0.00;
$djRecord->bid_autoclose = 0;
$djRecord->price_reserve = 0.00;
$djRecord->price_start = 0.00;
$djRecord->quantity = 0;
$djRecord->buynow = 0;
$djRecord->unit_id = 0;
$djRecord->offer = 0;
$djRecord->blocked = 0;
$djRecord->metarobots = '';
$djRecord->new_draft = 0;
$djRecord->last_view = $record->recently_visiteddate;
$djRecord->new = $record->isnew;
$djRecord->date_renew = $record->expirydate;
$result = $db->insertObject('#__djcf_items', $djRecord);
$recordID = $db->insertid();
if($recordID) {
// Now insert the images
foreach(explode(',', $record->images) as $img) {
$imagePathParts = explode('/', $img);
$imagePathPartsCount = count($imagePathParts);
$fileName = $imagePathParts[$imagePathPartsCount-1];
$fileParts = explode('.', $fileName);
$filePartsCount = count($fileParts);
$fileExt = $fileParts[$filePartsCount -1];
$image = new stdClass();
$image->item_id = $recordID;
$image->type = 'item';
$image->name = str_replace('.' . $fileExt, '', $fileName);
$image->ext = $fileExt;
$image->path = str_replace('com_jomclassifieds', $mediaFolderReplacement, '/' . str_replace($fileName, '', $img));
$image->caption = ucwords(str_replace(['_'], ' ', $fileName));
$image->ordering = 1;
$image->optimized = 0;
$imgInsertResult = $db->insertObject('#__djcf_images', $image);
}
++$count;
}
}
echo 'Successfully imported ' . $count . ' Records';
function getIsoCode($name) {
$countries_list = array(
"AF" => "Afghanistan",
"AX" => "Aland Islands",
"AL" => "Albania",
"DZ" => "Algeria",
"AS" => "American Samoa",
"AD" => "Andorra",
"AO" => "Angola",
"AI" => "Anguilla",
"AQ" => "Antarctica",
"AG" => "Antigua and Barbuda",
"AR" => "Argentina",
"AM" => "Armenia",
"AW" => "Aruba",
"AU" => "Australia",
"AT" => "Austria",
"AZ" => "Azerbaijan",
"BS" => "Bahamas",
"BH" => "Bahrain",
"BD" => "Bangladesh",
"BB" => "Barbados",
"BY" => "Belarus",
"BE" => "Belgium",
"BZ" => "Belize",
"BJ" => "Benin",
"BM" => "Bermuda",
"BT" => "Bhutan",
"BO" => "Bolivia",
"BQ" => "Bonaire, Sint Eustatius and Saba",
"BA" => "Bosnia and Herzegovina",
"BW" => "Botswana",
"BV" => "Bouvet Island",
"BR" => "Brazil",
"IO" => "British Indian Ocean Territory",
"BN" => "Brunei Darussalam",
"BG" => "Bulgaria",
"BF" => "Burkina Faso",
"BI" => "Burundi",
"KH" => "Cambodia",
"CM" => "Cameroon",
"CA" => "Canada",
"CV" => "Cape Verde",
"KY" => "Cayman Islands",
"CF" => "Central African Republic",
"TD" => "Chad",
"CL" => "Chile",
"CN" => "China",
"CX" => "Christmas Island",
"CC" => "Cocos (Keeling) Islands",
"CO" => "Colombia",
"KM" => "Comoros",
"CG" => "Congo",
"CD" => "Congo, Democratic Republic of the Congo",
"CK" => "Cook Islands",
"CR" => "Costa Rica",
"CI" => "Cote D'Ivoire",
"HR" => "Croatia",
"CU" => "Cuba",
"CW" => "Curacao",
"CY" => "Cyprus",
"CZ" => "Czech Republic",
"DK" => "Denmark",
"DJ" => "Djibouti",
"DM" => "Dominica",
"DO" => "Dominican Republic",
"EC" => "Ecuador",
"EG" => "Egypt",
"SV" => "El Salvador",
"GQ" => "Equatorial Guinea",
"ER" => "Eritrea",
"EE" => "Estonia",
"ET" => "Ethiopia",
"FK" => "Falkland Islands (Malvinas)",
"FO" => "Faroe Islands",
"FJ" => "Fiji",
"FI" => "Finland",
"FR" => "France",
"GF" => "French Guiana",
"PF" => "French Polynesia",
"TF" => "French Southern Territories",
"GA" => "Gabon",
"GM" => "Gambia",
"GE" => "Georgia",
"DE" => "Germany",
"GH" => "Ghana",
"GI" => "Gibraltar",
"GR" => "Greece",
"GL" => "Greenland",
"GD" => "Grenada",
"GP" => "Guadeloupe",
"GU" => "Guam",
"GT" => "Guatemala",
"GG" => "Guernsey",
"GN" => "Guinea",
"GW" => "Guinea-Bissau",
"GY" => "Guyana",
"HT" => "Haiti",
"HM" => "Heard Island and Mcdonald Islands",
"VA" => "Holy See (Vatican City State)",
"HN" => "Honduras",
"HK" => "Hong Kong",
"HU" => "Hungary",
"IS" => "Iceland",
"IN" => "India",
"ID" => "Indonesia",
"IR" => "Iran, Islamic Republic of",
"IQ" => "Iraq",
"IE" => "Ireland",
"IM" => "Isle of Man",
"IL" => "Israel",
"IT" => "Italy",
"JM" => "Jamaica",
"JP" => "Japan",
"JE" => "Jersey",
"JO" => "Jordan",
"KZ" => "Kazakhstan",
"KE" => "Kenya",
"KI" => "Kiribati",
"KP" => "Korea, Democratic People's Republic of",
"KR" => "Korea, Republic of",
"XK" => "Kosovo",
"KW" => "Kuwait",
"KG" => "Kyrgyzstan",
"LA" => "Lao People's Democratic Republic",
"LV" => "Latvia",
"LB" => "Lebanon",
"LS" => "Lesotho",
"LR" => "Liberia",
"LY" => "Libyan Arab Jamahiriya",
"LI" => "Liechtenstein",
"LT" => "Lithuania",
"LU" => "Luxembourg",
"MO" => "Macao",
"MK" => "Macedonia, the Former Yugoslav Republic of",
"MG" => "Madagascar",
"MW" => "Malawi",
"MY" => "Malaysia",
"MV" => "Maldives",
"ML" => "Mali",
"MT" => "Malta",
"MH" => "Marshall Islands",
"MQ" => "Martinique",
"MR" => "Mauritania",
"MU" => "Mauritius",
"YT" => "Mayotte",
"MX" => "Mexico",
"FM" => "Micronesia, Federated States of",
"MD" => "Moldova, Republic of",
"MC" => "Monaco",
"MN" => "Mongolia",
"ME" => "Montenegro",
"MS" => "Montserrat",
"MA" => "Morocco",
"MZ" => "Mozambique",
"MM" => "Myanmar",
"NA" => "Namibia",
"NR" => "Nauru",
"NP" => "Nepal",
"NL" => "Netherlands",
"AN" => "Netherlands Antilles",
"NC" => "New Caledonia",
"NZ" => "New Zealand",
"NI" => "Nicaragua",
"NE" => "Niger",
"NG" => "Nigeria",
"NU" => "Niue",
"NF" => "Norfolk Island",
"MP" => "Northern Mariana Islands",
"NO" => "Norway",
"OM" => "Oman",
"PK" => "Pakistan",
"PW" => "Palau",
"PS" => "Palestinian Territory, Occupied",
"PA" => "Panama",
"PG" => "Papua New Guinea",
"PY" => "Paraguay",
"PE" => "Peru",
"PH" => "Philippines",
"PN" => "Pitcairn",
"PL" => "Poland",
"PT" => "Portugal",
"PR" => "Puerto Rico",
"QA" => "Qatar",
"RE" => "Reunion",
"RO" => "Romania",
"RU" => "Russian Federation",
"RW" => "Rwanda",
"BL" => "Saint Barthelemy",
"SH" => "Saint Helena",
"KN" => "Saint Kitts and Nevis",
"LC" => "Saint Lucia",
"MF" => "Saint Martin",
"PM" => "Saint Pierre and Miquelon",
"VC" => "Saint Vincent and the Grenadines",
"WS" => "Samoa",
"SM" => "San Marino",
"ST" => "Sao Tome and Principe",
"SA" => "Saudi Arabia",
"SN" => "Senegal",
"RS" => "Serbia",
"CS" => "Serbia and Montenegro",
"SC" => "Seychelles",
"SL" => "Sierra Leone",
"SG" => "Singapore",
"SX" => "Sint Maarten",
"SK" => "Slovakia",
"SI" => "Slovenia",
"SB" => "Solomon Islands",
"SO" => "Somalia",
"ZA" => "South Africa",
"GS" => "South Georgia and the South Sandwich Islands",
"SS" => "South Sudan",
"ES" => "Spain",
"LK" => "Sri Lanka",
"SD" => "Sudan",
"SR" => "Suriname",
"SJ" => "Svalbard and Jan Mayen",
"SZ" => "Swaziland",
"SE" => "Sweden",
"CH" => "Switzerland",
"SY" => "Syrian Arab Republic",
"TW" => "Taiwan, Province of China",
"TJ" => "Tajikistan",
"TZ" => "Tanzania, United Republic of",
"TH" => "Thailand",
"TL" => "Timor-Leste",
"TG" => "Togo",
"TK" => "Tokelau",
"TO" => "Tonga",
"TT" => "Trinidad and Tobago",
"TN" => "Tunisia",
"TR" => "Turkey",
"TM" => "Turkmenistan",
"TC" => "Turks and Caicos Islands",
"TV" => "Tuvalu",
"UG" => "Uganda",
"UA" => "Ukraine",
"AE" => "United Arab Emirates",
"GB" => "United Kingdom",
"US" => "United States",
"UM" => "United States Minor Outlying Islands",
"UY" => "Uruguay",
"UZ" => "Uzbekistan",
"VU" => "Vanuatu",
"VE" => "Venezuela",
"VN" => "Viet Nam",
"VG" => "Virgin Islands, British",
"VI" => "Virgin Islands, U.s.",
"WF" => "Wallis and Futuna",
"EH" => "Western Sahara",
"YE" => "Yemen",
"ZM" => "Zambia",
"ZW" => "Zimbabwe"
);
foreach($countries_list as $k => $c) {
if(strtolower(trim($name)) === strtolower($c)) {
return $k;
}
}
return '';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment