mirror of
https://gh.wpcy.net/https://github.com/DecisiveDesignDE/wp-quickstart-installer.git
synced 2026-04-26 00:24:00 +08:00
- Added a new step (Step02_5) for users to select a WordPress setup type (e.g., Elementor, Blog, All Items). - Modified Step03 to dynamically display plugins and themes based on the chosen setup. - Updated APP_CONFIG (defined in step03.py) to store setup configurations, including plugin/theme details (id, name, icon, path). - Changed selections.json to store a list of dictionaries for selected items, providing richer data (including paths) for the installation process. - Updated Step05 to correctly parse the new selections.json structure and use item names for downloading. - Adjusted navigation in SetupApp.py, step02.py, and step03.py to accommodate the new flow.
235 lines
12 KiB
Python
235 lines
12 KiB
Python
import tkinter as tk
|
|
from tkinter import ttk
|
|
import subprocess
|
|
from PIL import Image, ImageTk
|
|
import os
|
|
import json
|
|
import sys
|
|
|
|
# APP_CONFIG: Central configuration for setups, plugins, and themes
|
|
# This would ideally be in a separate app_data.py or managed by the controller
|
|
APP_CONFIG = {
|
|
"setups": {
|
|
"elementor_focus": {
|
|
"name": "Elementor Website",
|
|
"description": "Ideal for building rich, visual websites with Elementor page builder.",
|
|
"plugins": [
|
|
{"id": "elementor", "name": "Elementor", "icon": "img/elementor.jpg", "path": "plugins/elementor.zip"},
|
|
{"id": "contact_form_7", "name": "Contact Form 7", "icon": "img/contact_form_7.jpg", "path": "plugins/contact-form-7.zip"},
|
|
{"id": "yoast_seo", "name": "Yoast SEO", "icon": "img/yoast_seo.jpg", "path": "plugins/wordpress-seo.zip"},
|
|
{"id": "litespeed_cache", "name": "LiteSpeed Cache", "icon": "img/litespeed_cache.jpg", "path": "plugins/litespeed-cache.zip"},
|
|
],
|
|
"themes": [
|
|
{"id": "hello_elementor", "name": "Hello Elementor", "icon": "img/hello.jpg", "path": "themes/hello-elementor.zip"},
|
|
{"id": "astra", "name": "Astra", "icon": "img/astra.jpg", "path": "themes/astra.zip"},
|
|
]
|
|
},
|
|
"blogging_setup": {
|
|
"name": "Just a Blog Setup",
|
|
"description": "Perfect for starting a blog with essential SEO and writing tools.",
|
|
"plugins": [
|
|
{"id": "yoast_seo", "name": "Yoast SEO", "icon": "img/yoast_seo.jpg", "path": "plugins/wordpress-seo.zip"},
|
|
{"id": "yoast_duplicate_post", "name": "Yoast Duplicate Post", "icon": "img/yoast_duplicate_post.jpg", "path": "plugins/yoast-duplicate-post.zip"},
|
|
{"id": "autoptimize", "name": "Autoptimize", "icon": "img/autoptimize.jpg", "path": "plugins/autoptimize.zip"},
|
|
],
|
|
"themes": [
|
|
{"id": "generatepress", "name": "GeneratePress", "icon": "img/generatepress.jpg", "path": "themes/generatepress.zip"},
|
|
{"id": "kadence", "name": "Kadence", "icon": "img/kadence.jpg", "path": "themes/kadence.zip"},
|
|
]
|
|
},
|
|
"all_items": {
|
|
"name": "All Items (Manual Selection)",
|
|
"description": "Choose from all available plugins and themes.",
|
|
"plugins": [
|
|
{"id": "elementor", "name": "Elementor", "icon": "img/elementor.jpg", "path": "plugins/elementor.zip"},
|
|
{"id": "contact_form_7", "name": "Contact Form 7", "icon": "img/contact_form_7.jpg", "path": "plugins/contact-form-7.zip"},
|
|
{"id": "yoast_seo", "name": "Yoast SEO", "icon": "img/yoast_seo.jpg", "path": "plugins/wordpress-seo.zip"},
|
|
{"id": "woocommerce", "name": "WooCommerce", "icon": "img/woocommerce.jpg", "path": "plugins/woocommerce.zip"},
|
|
{"id": "litespeed_cache", "name": "LiteSpeed Cache", "icon": "img/litespeed_cache.jpg", "path": "plugins/litespeed-cache.zip"},
|
|
{"id": "really_simple_ssl", "name": "Really Simple SSL", "icon": "img/really_simple_ssl.jpg", "path": "plugins/really-simple-ssl.zip"},
|
|
{"id": "yoast_duplicate_post", "name": "Yoast Duplicate Post", "icon": "img/yoast_duplicate_post.jpg", "path": "plugins/yoast-duplicate-post.zip"},
|
|
{"id": "wp_mail_smtp", "name": "WP Mail SMTP", "icon": "img/wp_mail_smtp.jpg", "path": "plugins/wp-mail-smtp.zip"},
|
|
{"id": "autoptimize", "name": "Autoptimize", "icon": "img/autoptimize.jpg", "path": "plugins/autoptimize.zip"},
|
|
{"id": "duplicator", "name": "Duplicator", "icon": "img/duplicator.jpg", "path": "plugins/duplicator.zip"},
|
|
{"id": "wp_fastest_cache", "name": "WP Fastest Cache", "icon": "img/wp_fastest_cache.jpg", "path": "plugins/wp-fastest-cache.zip"}
|
|
],
|
|
"themes": [
|
|
{"id": "hello_elementor", "name": "Hello Elementor", "icon": "img/hello.jpg", "path": "themes/hello-elementor.zip"},
|
|
{"id": "astra", "name": "Astra", "icon": "img/astra.jpg", "path": "themes/astra.zip"},
|
|
{"id": "kadence", "name": "Kadence", "icon": "img/kadence.jpg", "path": "themes/kadence.zip"},
|
|
{"id": "generatepress", "name": "GeneratePress", "icon": "img/generatepress.jpg", "path": "themes/generatepress.zip"},
|
|
{"id": "storefront", "name": "Storefront", "icon": "img/storefront.jpg", "path": "themes/storefront.zip"},
|
|
{"id": "hello_biz", "name": "Hello Biz", "icon": "img/hello_biz.jpg", "path": "themes/hello-biz.zip"}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
class Step03(tk.Frame):
|
|
def __init__(self, parent, controller):
|
|
super().__init__(parent)
|
|
self.controller = controller
|
|
self.configure(bg="#f4f4f4")
|
|
|
|
self.canvas = tk.Canvas(self, bg="#f4f4f4")
|
|
self.scrollbar = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
|
|
self.canvas.configure(yscrollcommand=self.scrollbar.set)
|
|
|
|
self.scrollable_frame = tk.Frame(self.canvas, bg="#f4f4f4")
|
|
self.scrollable_frame.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all")))
|
|
self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
|
|
|
|
self.canvas.pack(side="left", fill="both", expand=True)
|
|
self.scrollbar.pack(side="right", fill="y")
|
|
self.canvas.bind_all("<MouseWheel>", lambda e: self.canvas.yview_scroll(-1*(e.delta//120), "units"))
|
|
|
|
self.title_label = tk.Label(self.scrollable_frame, text="Select Plugins and Themes", font=("Arial", 18, "bold"), bg="#f4f4f4")
|
|
self.title_label.pack(pady=(20, 10))
|
|
|
|
# Placeholders for plugin and theme frames, will be populated by populate_items
|
|
self.plugins_group_frame = tk.Frame(self.scrollable_frame, bg="#f4f4f4")
|
|
self.plugins_group_frame.pack(pady=10, fill="x")
|
|
self.themes_group_frame = tk.Frame(self.scrollable_frame, bg="#f4f4f4")
|
|
self.themes_group_frame.pack(pady=10, fill="x")
|
|
|
|
self.plugin_vars = {}
|
|
self.theme_vars = {}
|
|
|
|
# Button frame
|
|
self.button_frame = tk.Frame(self.scrollable_frame, bg="#f4f4f4") # Changed to self.button_frame to allow re-packing
|
|
self.button_frame.pack(pady=20)
|
|
|
|
prev_button = ttk.Button(self.button_frame, text="< Prev", command=self.prev_window)
|
|
prev_button.grid(row=0, column=0, padx=10)
|
|
|
|
next_button = ttk.Button(self.button_frame, text="> Next", command=self.next_window)
|
|
next_button.grid(row=0, column=1, padx=10)
|
|
|
|
# Add an on_show_frame method to be called by the controller
|
|
self.bind("<<ShowFrame>>", self.on_show_frame)
|
|
|
|
|
|
def resource_path(self, relative_path):
|
|
try:
|
|
base_path = sys._MEIPASS
|
|
except Exception:
|
|
base_path = os.path.abspath(".")
|
|
full_path = os.path.join(base_path, relative_path)
|
|
# print(f"Resolving path: {full_path}") # Debug print, can be noisy
|
|
if not os.path.exists(full_path):
|
|
print(f"Warning: Resource path not found: {full_path}")
|
|
return full_path
|
|
|
|
def create_checkbox_with_icon(self, parent, item_id, item_name, var, row, column, icon_path_str):
|
|
frame = tk.Frame(parent, bg="#f4f4f4")
|
|
frame.grid(row=row, column=column, padx=10, pady=5, sticky=tk.W)
|
|
|
|
try:
|
|
icon_path = self.resource_path(icon_path_str)
|
|
if os.path.exists(icon_path):
|
|
img = Image.open(icon_path).resize((30, 30))
|
|
icon = ImageTk.PhotoImage(img)
|
|
img_label = tk.Label(frame, image=icon, bg="#f4f4f4")
|
|
img_label.image = icon
|
|
img_label.pack(side=tk.LEFT, padx=5)
|
|
else:
|
|
# Fallback if image not found
|
|
tk.Label(frame, text="[img]", bg="#f4f4f4").pack(side=tk.LEFT, padx=5)
|
|
|
|
except Exception as e:
|
|
print(f"Error loading image {icon_path_str}: {e}")
|
|
tk.Label(frame, text="[img err]", bg="#f4f4f4").pack(side=tk.LEFT, padx=5)
|
|
|
|
checkbox = tk.Checkbutton(frame, text=item_name, variable=var, bg="#f4f4f4")
|
|
checkbox.pack(side=tk.LEFT)
|
|
|
|
# Simplified tooltip for now, can be expanded later if needed
|
|
# For more complex tooltips, a dedicated tooltip class might be better
|
|
# info_img_path = self.resource_path("img/question.png")
|
|
# if os.path.exists(info_img_path):
|
|
# info_img = Image.open(info_img_path).resize((15, 15))
|
|
# info_icon = ImageTk.PhotoImage(info_img)
|
|
# info_label = tk.Label(frame, image=info_icon, bg="#f4f4f4", cursor="question_arrow")
|
|
# info_label.image = info_icon
|
|
# info_label.pack(side=tk.LEFT, padx=5)
|
|
# Bind tooltip events here if re-adding full tooltip functionality
|
|
|
|
def on_show_frame(self, event=None): # Modified to be event handler if bound
|
|
# Clear previous items
|
|
for widget in self.plugins_group_frame.winfo_children():
|
|
widget.destroy()
|
|
for widget in self.themes_group_frame.winfo_children():
|
|
widget.destroy()
|
|
|
|
self.plugin_vars.clear()
|
|
self.theme_vars.clear()
|
|
|
|
selected_setup_key = self.controller.shared_data.get("selected_setup_key", "all_items")
|
|
setup_data = APP_CONFIG["setups"].get(selected_setup_key)
|
|
|
|
if not setup_data:
|
|
print(f"Error: Setup key '{selected_setup_key}' not found in APP_CONFIG.")
|
|
# Display an error message to the user in the UI
|
|
error_label = tk.Label(self.scrollable_frame, text=f"Error: Setup '{selected_setup_key}' not found.", fg="red", bg="#f4f4f4")
|
|
error_label.pack(pady=10) # Make sure this is packed before buttons
|
|
self.button_frame.pack_forget() # Hide buttons if error
|
|
return
|
|
|
|
# Ensure button frame is visible if it was hidden due to previous error
|
|
if not self.button_frame.winfo_ismapped():
|
|
self.button_frame.pack(pady=20) # Re-pack it
|
|
|
|
# Remove any previous error message
|
|
for widget in self.scrollable_frame.winfo_children():
|
|
if isinstance(widget, tk.Label) and widget.cget("fg") == "red":
|
|
widget.destroy()
|
|
|
|
|
|
# Plugins
|
|
if setup_data["plugins"]:
|
|
subheadline_plugins = tk.Label(self.plugins_group_frame, text="Plugins", font=("Arial", 14, "bold"), bg="#f4f4f4")
|
|
subheadline_plugins.pack(pady=10)
|
|
plugins_frame_inner = tk.Frame(self.plugins_group_frame, bg="#f4f4f4")
|
|
plugins_frame_inner.pack(pady=10)
|
|
|
|
for idx, plugin in enumerate(setup_data["plugins"]):
|
|
var = tk.IntVar()
|
|
self.plugin_vars[plugin["id"]] = {"var": var, "data": plugin}
|
|
self.create_checkbox_with_icon(plugins_frame_inner, plugin["id"], plugin["name"], var, idx // 3, idx % 3, plugin["icon"])
|
|
|
|
# Themes
|
|
if setup_data["themes"]:
|
|
subheadline_themes = tk.Label(self.themes_group_frame, text="Themes", font=("Arial", 14, "bold"), bg="#f4f4f4")
|
|
subheadline_themes.pack(pady=10)
|
|
themes_frame_inner = tk.Frame(self.themes_group_frame, bg="#f4f4f4")
|
|
themes_frame_inner.pack(pady=10)
|
|
|
|
for idx, theme in enumerate(setup_data["themes"]):
|
|
var = tk.IntVar()
|
|
self.theme_vars[theme["id"]] = {"var": var, "data": theme}
|
|
self.create_checkbox_with_icon(themes_frame_inner, theme["id"], theme["name"], var, idx // 2, idx % 2, theme["icon"])
|
|
|
|
self.canvas.yview_moveto(0) # Scroll to top
|
|
|
|
def prev_window(self):
|
|
self.controller.show_frame("Step02_5")
|
|
|
|
def next_window(self):
|
|
selected_plugins_data = []
|
|
for item_id, item_info in self.plugin_vars.items():
|
|
if item_info["var"].get() == 1:
|
|
selected_plugins_data.append(item_info["data"]) # Store the whole plugin dict
|
|
|
|
selected_themes_data = []
|
|
for item_id, item_info in self.theme_vars.items():
|
|
if item_info["var"].get() == 1:
|
|
selected_themes_data.append(item_info["data"]) # Store the whole theme dict
|
|
|
|
selections = {
|
|
"plugins": selected_plugins_data, # Now list of dicts
|
|
"themes": selected_themes_data # Now list of dicts
|
|
}
|
|
with open("selections.json", "w") as file:
|
|
json.dump(selections, file, indent=4) # Added indent for readability
|
|
|
|
self.controller.show_frame("Step04")
|