├── LICENSE ├── README.md └── magento2-theme-manager.sh /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # magento2-theme-manager 2 | Interactive bash script for managing themes in Magento 2 3 | -------------------------------------------------------------------------------- /magento2-theme-manager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | clear 4 | CORE_PATH="app/design/frontend" 5 | REFERENCE_FILE="app/etc/config.php" 6 | REFERENCE_VIEW_XML_FILE="vendor/magento/theme-frontend-blank/etc/view.xml" 7 | 8 | # sql queries run when extending theme 9 | MYSQL_COMMAND_1='select distinct theme_id, theme_path from theme where area="frontend"' 10 | MYSQL_COMMAND_2='select theme_path from theme where theme_id=' 11 | 12 | # sql queries run when deleting themes 13 | MYSQL_COMMAND_3='select count(parent_id) from theme where parent_id=' 14 | MYSQL_COMMAND_4='select theme_path, theme_title, preview_image from theme where theme_id=' 15 | MYSQL_COMMAND_5='delete from theme where theme_id=' 16 | 17 | # the script must be run from document root folder 18 | isMagento2RootFolder () { 19 | if [ ! -f "$REFERENCE_FILE" ]; then 20 | printf "\nThe script must be run from document root!" 21 | exitScript 22 | fi 23 | } 24 | 25 | # get user input and create vendor folder 26 | promptVendorName () { 27 | printf "\nPlease specify vendor name: " 28 | read -r VENDOR_NAME 29 | 30 | VENDOR_PATH=$CORE_PATH"/"$VENDOR_NAME 31 | 32 | # if vendor folder doesn't exists, create it 33 | if [ ! -d "$VENDOR_PATH" ]; then 34 | mkdir -p "$VENDOR_PATH" 35 | printf "Created vendor folder: %s" "$VENDOR_PATH" 36 | fi 37 | } 38 | 39 | # get user input and create theme folder 40 | promptThemeName () { 41 | printf "\nPlease specify theme name: " 42 | read -r THEME_NAME 43 | 44 | THEME_PATH=$VENDOR_PATH"/"$THEME_NAME 45 | 46 | # if theme folder doesn't exists, create it 47 | if [ ! -d "$THEME_PATH" ]; then 48 | mkdir -p "$THEME_PATH" 49 | printf "Created theme folder: %s" "$THEME_PATH" 50 | fi 51 | } 52 | 53 | # process themes theme.xml file 54 | renderThemeXmlFile () { 55 | # check if argument has been passed to the function 56 | if [ ! -z "$1" ] ; then 57 | PARENT_PATH="$1" 58 | fi 59 | 60 | THEME_XML_FILE=$THEME_PATH"/theme.xml" 61 | 62 | if [ -f "$THEME_XML_FILE" ]; then 63 | printf "\nERROR: found: %s" "$THEME_XML_FILE" 64 | exitScript 65 | else 66 | 67 | # get user input for theme title that will be visible in admin area 68 | printf "\nPlease specify theme title: " 69 | read -r THEME_TITLE 70 | 71 | THEME_XML_CONTENT=' 77 | 78 | '$THEME_TITLE' 79 | '$PARENT_PATH' 80 | 81 | media/preview.jpg 82 | 83 | ' 84 | 85 | # output configuration to .xml file 86 | echo "$THEME_XML_CONTENT" > "$THEME_XML_FILE" 87 | printf "Created file: %s" "$THEME_XML_FILE" 88 | fi 89 | } 90 | 91 | # process themes registration.php file 92 | renderRegistrationPhpFile () { 93 | VENDOR=$VENDOR_NAME"/"$THEME_NAME 94 | REGISTRATION_PHP_FILE=$THEME_PATH"/registration.php" 95 | 96 | if [ -f "$REGISTRATION_PHP_FILE" ]; then 97 | printf "\nERROR: found: %s" "$REGISTRATION_PHP_FILE" 98 | exitScript 99 | else 100 | REGISTRATION_PHP_CONTENT=" "$REGISTRATION_PHP_FILE" 114 | printf "\nCreated file: %s" "$REGISTRATION_PHP_FILE" 115 | fi 116 | } 117 | 118 | # this function is run only when creating new theme 119 | renderEtcViewXmlFile () { 120 | ETC_PATH="$THEME_PATH/etc" 121 | 122 | # if etc folder doesn't exists, create it 123 | if [ ! -d "$ETC_PATH" ]; then 124 | mkdir "$ETC_PATH" 125 | printf "\nCreated folder: %s" "$ETC_PATH" 126 | fi 127 | 128 | VIEW_XML_FILE="$ETC_PATH/view.xml" 129 | 130 | if [ -f "$VIEW_XML_FILE" ]; then 131 | printf "\nERROR: found: %s" "$VIEW_XML_FILE" 132 | exitScript 133 | else 134 | if [ ! -f "$REFERENCE_VIEW_XML_FILE" ] ; then 135 | printf "\nFile not found: $REFERENCE_VIEW_XML_FILE" 136 | exitScript 137 | fi 138 | # always copy view.xml file from Magento/blank theme 139 | cp "$REFERENCE_VIEW_XML_FILE" "$ETC_PATH" 140 | printf "\nCopied vendor/magento/theme-frontend-blank/view.xml to %s" "$ETC_PATH" 141 | printf "\nBrowse this file and customize its configuration" 142 | fi 143 | } 144 | 145 | # each new theme must have its own preview image 146 | downloadPreviewImage () { 147 | IMAGE_LINK="http://inchoo.net/wp-content/uploads/2016/02/Inchoo-logo.jpg" 148 | 149 | MEDIA_PATH=$THEME_PATH"/media" 150 | 151 | # if media folder doesn't exists, create it 152 | if [ ! -d "$MEDIA_PATH" ]; then 153 | mkdir "$MEDIA_PATH" 154 | printf "\nCreated folder: %s" "$MEDIA_PATH" 155 | fi 156 | 157 | MEDIA_IMG=$MEDIA_PATH"/preview.jpg" 158 | if [ -f "$MEDIA_IMG" ]; then 159 | printf "\nERROR: found: %s" "$MEDIA_IMG" 160 | exitScript 161 | else 162 | # download image from specified link and save it into media folder 163 | # and rename it to preview.jpg 164 | wget -c -q $IMAGE_LINK -O "$MEDIA_PATH/preview.jpg" 165 | printf "\nDownloaded preview image to %s" "$MEDIA_PATH" 166 | fi 167 | } 168 | 169 | createInchooLessFile () { 170 | WEB_PATH=$THEME_PATH"/web" 171 | # if media folder doesn't exists, create it 172 | if [ ! -d "$WEB_PATH" ]; then 173 | mkdir "$WEB_PATH" 174 | printf "\nCreated folder: %s" "$WEB_PATH" 175 | fi 176 | 177 | WEB_CSS_PATH=$WEB_PATH"/css" 178 | if [ ! -d "$WEB_CSS_PATH" ]; then 179 | mkdir "$WEB_CSS_PATH" 180 | printf "\nCreated folder: %s" "$WEB_CSS_PATH" 181 | fi 182 | 183 | DESIGN_FILE=$WEB_CSS_PATH"/inchoo.less" 184 | if [ ! -f "$DESIGN_FILE" ]; then 185 | touch "$DESIGN_FILE" 186 | printf "\nCreated file: %s" "$DESIGN_FILE" 187 | fi 188 | 189 | DESIGN_FILE_CONTENT="@inchoo-green: #79AD36; 190 | body { 191 | background-color: @inchoo-green !important; 192 | }" 193 | echo "$DESIGN_FILE_CONTENT" > "$DESIGN_FILE" 194 | } 195 | 196 | promptLocale () { 197 | DEFAULT_LOCALE="en_US" 198 | 199 | printf "\nPlease specify themes locale setting or press Enter for default (en_US): " 200 | read -r THEME_LOCALE 201 | 202 | # if user did press Enter, update variable to default 203 | if [ -z "$THEME_LOCALE" ]; then 204 | THEME_LOCALE=$DEFAULT_LOCALE 205 | printf "Theme is using default locale: %s" "$THEME_LOCALE" 206 | else 207 | printf "Custom locale: %s" "$THEME_LOCALE" 208 | fi 209 | } 210 | 211 | updateThemeJs () { 212 | printf "\nIn your text editor, open the follwoing file:" 213 | printf "\n" 214 | printf "\ndev/tools/grunt/configs/themes.js" 215 | printf "\n" 216 | printf "\nand paste the following code just before the last closing curly bracket: " 217 | printf "\n" 218 | printf ", 219 | %s: { 220 | area: 'frontend', 221 | name: '%s', 222 | locale: '%s', 223 | files: [ 224 | 'css/inchoo' 225 | ], 226 | dsl: 'less' 227 | }" "$THEME_NAME" "$VENDOR" "$THEME_LOCALE" 228 | } 229 | 230 | displayDeploymentCommands () { 231 | printf "\n" 232 | printf "\nPlease open Magento Admin Dashboard -> Content -> Themes" 233 | printf "\n" 234 | printf "\nNow, copy and paste the following commands:" 235 | printf "\n" 236 | printf "\ngrunt clean" 237 | printf "\ngrunt exec:%s" "$THEME_NAME" 238 | printf "\nphp bin/magento cache:clean" 239 | printf "\nphp bin/magento setup:static-content:deploy" 240 | printf "\n" 241 | printf "\nTheme preview image is located in folder pub/media/theme/preview" 242 | printf "\nCompiled css file is located in folder pub/static/frontend/%s/%s/css" "$THEME_PATH" "$THEME_LOCALE" 243 | } 244 | 245 | updatePermissions () { 246 | IFS='\ ' read -r OWNER_USER OWNER_GROUP <<< "$(ls -ld "$REFERENCE_FILE" | awk '{print $3, $4}')" 247 | printf "\n\nSetting permissions: (%s:%s) to %s\n" "$OWNER_USER" "$OWNER_GROUP" "$THEME_PATH" 248 | sudo chown -R "$OWNER_USER":"$OWNER_GROUP" "$THEME_PATH" 249 | } 250 | 251 | # get user input for mysql credentials 252 | promptMysqlCredentials () { 253 | printf "\nType in your mysql username: " 254 | read -r MYSQL_USERNAME 255 | 256 | printf "Type in your mysql password: " 257 | read -r -s MYSQL_PASSWORD 258 | 259 | printf "\nType in database name: " 260 | read -r MYSQL_DB_NAME 261 | } 262 | 263 | # define mysql connection 264 | mysql_conn () { 265 | mysql -N -s -u "$MYSQL_USERNAME" -p"$MYSQL_PASSWORD" -D "$MYSQL_DB_NAME" -e "$1" 266 | } 267 | 268 | # perform simple mysql connection 269 | testMysqlConnection () { 270 | mysql_conn "use $MYSQL_DB_NAME" 271 | 272 | # if error occured, the script will exit 273 | if [ ! "$?" = "0" ]; then 274 | exitScript 275 | fi 276 | } 277 | 278 | # display all available magento themes 279 | listExistingThemes () { 280 | printf "\nListing existing themes:\n" 281 | 282 | mysql_conn "$MYSQL_COMMAND_1" | while read -r line 283 | do 284 | IFS=$'\t' read -r THEME_ID THEME_PATH <<< "$line" 285 | echo "[$THEME_ID, $THEME_PATH]" 286 | done 287 | 288 | printf "\nPlease, select one of the numbers: " 289 | read -r SELECTED_INPUT_THEME_ID 290 | 291 | PARENT_VENDOR=$(mysql_conn "$MYSQL_COMMAND_2$SELECTED_INPUT_THEME_ID") 292 | } 293 | 294 | promptAndDeleteTheme () { 295 | # parse sql results 296 | read -r HOW_MANY_CHILD_THEMES <<< "$(mysql_conn "$MYSQL_COMMAND_3$SELECTED_INPUT_THEME_ID")"; 297 | 298 | if [ "$HOW_MANY_CHILD_THEMES" -eq 0 ] ; then 299 | # theme exists in database 300 | 301 | # parse results 302 | read -r THEME_PATH THEME_TITLE THEME_IMAGE<<< "$(mysql_conn "$MYSQL_COMMAND_4$SELECTED_INPUT_THEME_ID")"; 303 | 304 | if [ -n "$THEME_TITLE" ] ; then 305 | # theme is not parent theme, it is safe to remove it 306 | 307 | # remove theme folder and its files 308 | printf "\nDeleting theme files in: %s/%s" "$CORE_PATH" "$THEME_PATH" 309 | rm -rf "$CORE_PATH"/"$THEME_PATH" 310 | 311 | if [ ! -z $THEME_IMAGE ] ; then 312 | printf "\nDeleting theme preview image in pub/media/theme/preview/%s" "$THEME_IMAGE" 313 | PUB_THEME_IMAGE="pub/media/theme/preview/$THEME_IMAGE" 314 | rm "$PUB_THEME_IMAGE" 315 | fi 316 | 317 | # remove theme entry in database 318 | printf "\nDeleting database entry in table 'theme'" 319 | mysql_conn "$MYSQL_COMMAND_5$SELECTED_INPUT_THEME_ID" 320 | 321 | # notify user to delete content in grunts theme.js file 322 | IFS='/' read -a DB_THEME_PATH <<< "$THEME_PATH" 323 | printf "\n\nIn your text editor, open the following file:" 324 | printf "\ndev/tools/grunt/configs/themes.js" 325 | printf "\nand delete content that is related to key '%s'" "${DB_THEME_PATH[1]}" 326 | 327 | printf "\n\nDone" 328 | else 329 | # row entry in database table does not exist 330 | printf "\nERROR - theme with [theme_id, %s] is not found in database!" "$SELECTED_INPUT_THEME_ID" 331 | exitScript 332 | fi 333 | else 334 | # theme is parent theme, do nothing 335 | echo "Cannot delete $PARENT_VENDOR, theme is parent to total of $HOW_MANY_CHILD_THEMES theme(s)!" 336 | exitScript 337 | fi 338 | } 339 | 340 | createNewTheme () { 341 | promptVendorName 342 | promptThemeName 343 | renderThemeXmlFile 344 | promptLocale 345 | renderRegistrationPhpFile 346 | renderEtcViewXmlFile 347 | downloadPreviewImage 348 | createInchooLessFile 349 | updatePermissions 350 | updateThemeJs 351 | displayDeploymentCommands 352 | } 353 | 354 | extendExistingTheme () { 355 | promptMysqlCredentials 356 | testMysqlConnection 357 | listExistingThemes 358 | promptVendorName 359 | promptThemeName 360 | renderThemeXmlFile "$PARENT_VENDOR" 361 | promptLocale 362 | renderRegistrationPhpFile 363 | downloadPreviewImage 364 | createInchooLessFile 365 | updatePermissions 366 | updateThemeJs 367 | displayDeploymentCommands 368 | } 369 | 370 | deleteTheme () { 371 | promptMysqlCredentials 372 | testMysqlConnection 373 | listExistingThemes 374 | promptAndDeleteTheme 375 | } 376 | 377 | exitScript () { 378 | echo " " 379 | echo "The script is going to exit" 380 | exit 381 | } 382 | 383 | # this is where script output starts 384 | printf "*********** Magento2 Theme Manager ***********" 385 | 386 | isMagento2RootFolder 387 | 388 | printf "\nWould you like to:" 389 | printf "\n1) create a new theme" 390 | printf "\n2) create a child theme" 391 | printf "\n3) delete a theme" 392 | printf "\nPlease, enter your option: " 393 | read -r THEME_OPTION 394 | 395 | # : ' 396 | case "$THEME_OPTION" in 397 | 1 ) createNewTheme ;; 398 | 2 ) extendExistingTheme ;; 399 | 3 ) deleteTheme ;; 400 | * ) printf "\nUnknown argument specified: %s" "$THEME_OPTION" 401 | exitScript ;; 402 | esac 403 | #' 404 | 405 | echo " " 406 | echo "*********** Magento2 Theme Manager has finished successfully ***********" --------------------------------------------------------------------------------