Changeset 3447337
- Timestamp:
- 01/26/2026 07:44:54 PM (3 weeks ago)
- Location:
- iris-ai/trunk
- Files:
-
- 6 edited
-
assets/css/admin.css (modified) (4 diffs)
-
includes/class-irisai-admin.php (modified) (2 diffs)
-
includes/class-irisai-rest.php (modified) (6 diffs)
-
includes/settings/traits/trait-settings-widgetfields.php (modified) (33 diffs)
-
iris-ai.php (modified) (5 diffs)
-
readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
iris-ai/trunk/assets/css/admin.css
r3424224 r3447337 443 443 display: flex; 444 444 align-items: center; 445 justify-content: flex-start;445 justify-content: flex-start; 446 446 gap: 15px; 447 447 } … … 911 911 line-height: 1.6; 912 912 } 913 913 914 /* ============================================================================ 914 915 Margin Utilities 915 916 ============================================================================ */ 916 917 917 918 .irisai-mb-20 { 918 919 margin-bottom: 20px; … … 934 935 margin-bottom: 15px; 935 936 } 937 936 938 .irisai-textarea-full { 937 939 width: 100%; … … 939 941 box-sizing: border-box; 940 942 } 943 944 /* ============================= */ 945 /* IrisAI Setup Wizard Styles */ 946 /* ============================= */ 947 948 949 .irisai-form-card { 950 background: #fff; 951 border: 2px solid #e2e8f0; 952 border-radius: 12px; 953 padding: 32px; 954 margin-bottom: 24px; 955 display: flex; 956 gap: 20px; 957 align-items: flex-start; 958 } 959 960 .irisai-form-card .form-card-icon { 961 width: 56px; 962 height: 56px; 963 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 964 border-radius: 12px; 965 display: flex; 966 align-items: center; 967 justify-content: center; 968 color: #fff; 969 flex-shrink: 0; 970 } 971 972 .irisai-form-card .form-card-icon.openai { 973 background: linear-gradient(135deg, #10a37f 0%, #0d8a6a 100%); 974 } 975 976 .irisai-form-card .form-card-content { 977 flex: 1; 978 } 979 980 .irisai-form-card .form-card-content label { 981 display: block; 982 font-size: 16px; 983 margin-bottom: 12px; 984 color: #1e293b; 985 } 986 987 .irisai-api-input { 988 width: 100%; 989 padding: 12px 16px; 990 font-size: 14px; 991 border: 2px solid #e2e8f0; 992 border-radius: 8px; 993 transition: all 0.2s ease; 994 font-family: 'Monaco', 'Menlo', 'Courier New', monospace; 995 } 996 997 .irisai-api-input:focus { 998 border-color: #667eea; 999 outline: none; 1000 box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); 1001 } 1002 1003 .irisai-wizard-inner-container .field-description { 1004 margin: 12px 0 0; 1005 font-size: 13px; 1006 color: #64748b; 1007 display: flex; 1008 align-items: center; 1009 gap: 6px; 1010 } 1011 1012 .irisai-wizard-inner-container .field-description .dashicons { 1013 font-size: 16px; 1014 width: 16px; 1015 height: 16px; 1016 } 1017 1018 .irisai-wizard-inner-container .field-description a { 1019 color: #667eea; 1020 text-decoration: none; 1021 font-weight: 500; 1022 display: inline-flex; 1023 align-items: center; 1024 gap: 4px; 1025 } 1026 1027 .irisai-wizard-inner-container .field-description a:hover { 1028 text-decoration: underline; 1029 } 1030 1031 .irisai-wizard-inner-container .field-description a .dashicons { 1032 font-size: 14px; 1033 width: 14px; 1034 height: 14px; 1035 } 1036 1037 .irisai-info-box { 1038 background: #f0f9ff; 1039 border: 1px solid #bae6fd; 1040 border-radius: 8px; 1041 padding: 20px; 1042 display: flex; 1043 gap: 16px; 1044 margin-bottom: 32px; 1045 } 1046 1047 .irisai-info-box.warning { 1048 background: #fffbeb; 1049 border-color: #fde68a; 1050 } 1051 1052 .irisai-wizard-inner-container .info-box-icon { 1053 width: 40px; 1054 height: 40px; 1055 background: #dbeafe; 1056 border-radius: 8px; 1057 display: flex; 1058 align-items: center; 1059 justify-content: center; 1060 color: #0284c7; 1061 flex-shrink: 0; 1062 } 1063 1064 .irisai-info-box.warning .info-box-icon { 1065 background: #fef3c7; 1066 color: #d97706; 1067 } 1068 1069 .irisai-wizard-inner-container .info-box-icon .dashicons { 1070 font-size: 22px; 1071 width: 22px; 1072 height: 22px; 1073 } 1074 1075 .irisai-wizard-inner-container .info-box-content { 1076 flex: 1; 1077 } 1078 1079 .irisai-wizard-inner-container .info-box-content strong { 1080 display: block; 1081 margin-bottom: 8px; 1082 color: #1e293b; 1083 font-size: 14px; 1084 } 1085 1086 .irisai-wizard-inner-container .info-box-content ul { 1087 margin: 0; 1088 padding-left: 20px; 1089 } 1090 1091 .irisai-wizard-inner-container .info-box-content ul li { 1092 font-size: 13px; 1093 color: #475569; 1094 margin-bottom: 4px; 1095 line-height: 1.5; 1096 } 1097 1098 .irisai-wizard-inner-container .info-box-content ul li:last-child { 1099 margin-bottom: 0; 1100 } 1101 1102 .irisai-skip-form { 1103 text-align: center; 1104 } 1105 1106 .irisai-content-selection { 1107 margin-bottom: 32px; 1108 } 1109 1110 .irisai-content-selection .selection-header { 1111 margin-bottom: 24px; 1112 } 1113 1114 .irisai-content-selection .selection-header h3 { 1115 font-size: 18px; 1116 font-weight: 600; 1117 margin: 0 0 8px; 1118 color: #1e293b; 1119 } 1120 1121 .irisai-content-selection .selection-header p { 1122 font-size: 14px; 1123 color: #64748b; 1124 margin: 0; 1125 } 1126 1127 .irisai-content-selection .content-types-grid { 1128 display: grid; 1129 grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); 1130 gap: 16px; 1131 margin-bottom: 24px; 1132 } 1133 1134 .irisai-content-selection .content-type-card { 1135 position: relative; 1136 background: #fff; 1137 border: 2px solid #e2e8f0; 1138 border-radius: 10px; 1139 padding: 20px; 1140 cursor: pointer; 1141 transition: all 0.2s ease; 1142 display: flex; 1143 align-items: center; 1144 gap: 16px; 1145 } 1146 1147 .irisai-content-selection .content-type-card input[type="checkbox"] { 1148 position: absolute; 1149 opacity: 0; 1150 pointer-events: none; 1151 } 1152 1153 .irisai-content-selection .content-type-card:hover { 1154 border-color: #cbd5e1; 1155 transform: translateY(-2px); 1156 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); 1157 } 1158 1159 .irisai-content-selection .content-type-card.selected { 1160 border-color: #667eea; 1161 background: #f8f9ff; 1162 box-shadow: 0 2px 8px rgba(102, 126, 234, 0.1); 1163 } 1164 1165 .irisai-content-selection .card-icon { 1166 width: 48px; 1167 height: 48px; 1168 background: #f1f5f9; 1169 border-radius: 10px; 1170 display: flex; 1171 align-items: center; 1172 justify-content: center; 1173 flex-shrink: 0; 1174 transition: all 0.2s ease; 1175 } 1176 1177 .irisai-content-selection .content-type-card.selected .card-icon { 1178 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1179 color: #fff; 1180 } 1181 1182 .irisai-content-selection .card-icon .dashicons { 1183 font-size: 24px; 1184 width: 24px; 1185 height: 24px; 1186 color: #64748b; 1187 } 1188 1189 .irisai-content-selection .content-type-card.selected .card-icon .dashicons { 1190 color: #fff; 1191 } 1192 1193 .irisai-content-selection .card-content { 1194 flex: 1; 1195 } 1196 1197 .irisai-content-selection .card-content h4 { 1198 font-size: 15px; 1199 font-weight: 600; 1200 margin: 0 0 4px; 1201 color: #1e293b; 1202 } 1203 1204 .irisai-content-selection .post-count { 1205 font-size: 13px; 1206 color: #64748b; 1207 margin: 0; 1208 } 1209 1210 .irisai-content-selection .card-checkmark { 1211 width: 24px; 1212 height: 24px; 1213 border-radius: 50%; 1214 background: #e2e8f0; 1215 display: flex; 1216 align-items: center; 1217 justify-content: center; 1218 opacity: 0; 1219 transition: all 0.2s ease; 1220 } 1221 1222 .irisai-content-selection .content-type-card.selected .card-checkmark { 1223 opacity: 1; 1224 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1225 } 1226 1227 .irisai-content-selection .card-checkmark .dashicons { 1228 color: #fff; 1229 font-size: 16px; 1230 width: 16px; 1231 height: 16px; 1232 } 1233 1234 1235 1236 .irisai-wizard-inner-container.finish-container { 1237 text-align: center; 1238 } 1239 1240 .irisai-wizard-inner-container .finish-celebration { 1241 margin-bottom: 48px; 1242 } 1243 1244 .irisai-wizard-inner-container .celebration-icon { 1245 width: 120px; 1246 height: 120px; 1247 margin: 0 auto 32px; 1248 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1249 border-radius: 50%; 1250 display: flex; 1251 align-items: center; 1252 justify-content: center; 1253 color: #fff; 1254 animation: celebrate 0.6s ease-out; 1255 } 1256 1257 @keyframes celebrate { 1258 0% { 1259 transform: scale(0); 1260 opacity: 0; 1261 } 1262 1263 50% { 1264 transform: scale(1.1); 1265 } 1266 1267 100% { 1268 transform: scale(1); 1269 opacity: 1; 1270 } 1271 } 1272 1273 .irisai-wizard-inner-container .finish-celebration h1 { 1274 font-size: 36px; 1275 font-weight: 700; 1276 margin: 0 0 16px; 1277 color: #1e293b; 1278 } 1279 1280 .irisai-wizard-inner-container .celebration-subtitle { 1281 font-size: 16px; 1282 color: #64748b; 1283 margin: 0 auto; 1284 max-width: 600px; 1285 line-height: 1.6; 1286 } 1287 1288 .irisai-wizard-inner-container .finish-features { 1289 display: grid; 1290 grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); 1291 gap: 24px; 1292 margin-bottom: 48px; 1293 } 1294 1295 .irisai-wizard-inner-container .feature-card { 1296 background: #f8fafc; 1297 border: 1px solid #e2e8f0; 1298 border-radius: 12px; 1299 padding: 32px 24px; 1300 transition: all 0.2s ease; 1301 } 1302 1303 .irisai-wizard-inner-container .feature-card:hover { 1304 transform: translateY(-4px); 1305 box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08); 1306 border-color: #cbd5e1; 1307 } 1308 1309 .irisai-wizard-inner-container .feature-icon { 1310 width: 56px; 1311 height: 56px; 1312 margin: 0 auto 20px; 1313 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1314 border-radius: 14px; 1315 display: flex; 1316 align-items: center; 1317 justify-content: center; 1318 color: #fff; 1319 } 1320 1321 .irisai-wizard-inner-container .feature-icon .dashicons { 1322 font-size: 28px; 1323 width: 28px; 1324 height: 28px; 1325 } 1326 1327 .irisai-wizard-inner-container .feature-card h3 { 1328 font-size: 18px; 1329 font-weight: 600; 1330 margin: 0 0 12px; 1331 color: #1e293b; 1332 } 1333 1334 .irisai-wizard-inner-container .feature-card p { 1335 font-size: 14px; 1336 color: #64748b; 1337 margin: 0; 1338 line-height: 1.5; 1339 } 1340 1341 .irisai-wizard-inner-container .finish-next-steps { 1342 background: #f0f9ff; 1343 border: 1px solid #bae6fd; 1344 border-radius: 12px; 1345 padding: 32px; 1346 margin-bottom: 40px; 1347 text-align: left; 1348 } 1349 1350 .irisai-wizard-inner-container .finish-next-steps h3 { 1351 font-size: 20px; 1352 font-weight: 600; 1353 margin: 0 0 20px; 1354 color: #1e293b; 1355 text-align: center; 1356 } 1357 1358 .irisai-wizard-inner-container .finish-next-steps ul { 1359 list-style: none; 1360 margin: 0; 1361 padding: 0; 1362 max-width: 600px; 1363 margin: 0 auto; 1364 } 1365 1366 .irisai-wizard-inner-container .finish-next-steps li { 1367 display: flex; 1368 align-items: flex-start; 1369 gap: 12px; 1370 font-size: 15px; 1371 color: #475569; 1372 margin-bottom: 16px; 1373 line-height: 1.6; 1374 } 1375 1376 .irisai-wizard-inner-container .finish-next-steps li:last-child { 1377 margin-bottom: 0; 1378 } 1379 1380 .irisai-wizard-inner-container .finish-next-steps .dashicons { 1381 color: #22c55e; 1382 font-size: 24px; 1383 width: 24px; 1384 height: 24px; 1385 flex-shrink: 0; 1386 margin-top: -2px; 1387 } 1388 1389 .irisai-wizard-inner-container .finish-actions { 1390 display: flex; 1391 gap: 16px; 1392 justify-content: center; 1393 flex-wrap: wrap; 1394 } 1395 1396 .irisai-wizard-inner-container .finish-actions .button { 1397 display: inline-flex; 1398 align-items: center; 1399 gap: 8px; 1400 } 1401 1402 .irisai-wizard-inner-container .finish-actions .button .dashicons { 1403 font-size: 18px; 1404 width: 18px; 1405 height: 18px; 1406 } 1407 1408 .irisai-wizard-inner-container .finish-actions .button-hero { 1409 font-size: 16px; 1410 padding: 14px 32px; 1411 height: auto; 1412 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1413 border: none; 1414 box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); 1415 } 1416 1417 .irisai-wizard-inner-container .finish-actions .button-hero:hover { 1418 background: linear-gradient(135deg, #5568d3 0%, #6a3f8f 100%); 1419 transform: translateY(-2px); 1420 box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4); 1421 } 1422 1423 .irisai-wizard-inner-container .finish-actions .button-secondary { 1424 font-size: 16px; 1425 padding: 14px 32px; 1426 height: auto; 1427 border: 2px solid #e2e8f0; 1428 background: #fff; 1429 } 1430 1431 .irisai-wizard-inner-container .finish-actions .button-secondary:hover { 1432 border-color: #cbd5e1; 1433 background: #f8fafc; 1434 } 1435 1436 .irisai-mode-options { 1437 display: grid; 1438 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); 1439 gap: 24px; 1440 margin-bottom: 32px; 1441 } 1442 1443 .irisai-mode-card { 1444 position: relative; 1445 background: #fff; 1446 border: 2px solid #e2e8f0; 1447 border-radius: 12px; 1448 padding: 24px; 1449 cursor: pointer; 1450 transition: all 0.2s ease; 1451 display: block; 1452 } 1453 1454 .irisai-mode-card input[type="radio"] { 1455 position: absolute; 1456 opacity: 0; 1457 pointer-events: none; 1458 } 1459 1460 .irisai-mode-card:hover { 1461 border-color: #cbd5e1; 1462 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); 1463 transform: translateY(-2px); 1464 } 1465 1466 .irisai-mode-card.selected { 1467 border-color: #667eea; 1468 background: #f8f9ff; 1469 box-shadow: 0 4px 16px rgba(102, 126, 234, 0.15); 1470 } 1471 1472 .irisai-mode-options .mode-card-content { 1473 position: relative; 1474 } 1475 1476 .irisai-mode-options .mode-icon { 1477 width: 48px; 1478 height: 48px; 1479 background: #f1f5f9; 1480 border-radius: 10px; 1481 display: flex; 1482 align-items: center; 1483 justify-content: center; 1484 margin-bottom: 16px; 1485 color: #64748b; 1486 } 1487 1488 .irisai-mode-options .mode-icon.recommended { 1489 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1490 color: #fff; 1491 } 1492 1493 .irisai-mode-options .mode-header { 1494 display: flex; 1495 align-items: center; 1496 gap: 12px; 1497 margin-bottom: 12px; 1498 } 1499 1500 .irisai-mode-options .mode-header h3 { 1501 font-size: 18px; 1502 font-weight: 600; 1503 margin: 0; 1504 color: #1e293b; 1505 } 1506 1507 .irisai-mode-options .badge { 1508 font-size: 11px; 1509 font-weight: 600; 1510 text-transform: uppercase; 1511 padding: 4px 10px; 1512 border-radius: 12px; 1513 letter-spacing: 0.5px; 1514 } 1515 1516 .irisai-mode-options .badge.recommended { 1517 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1518 color: #fff; 1519 } 1520 1521 .irisai-mode-options .badge.basic { 1522 background: #f1f5f9; 1523 color: #64748b; 1524 } 1525 1526 .irisai-mode-options .mode-description { 1527 font-size: 14px; 1528 line-height: 1.6; 1529 color: #64748b; 1530 margin: 0 0 16px; 1531 } 1532 1533 .irisai-mode-options .mode-features { 1534 list-style: none; 1535 margin: 0; 1536 padding: 0; 1537 } 1538 1539 .irisai-mode-options .mode-features li { 1540 display: flex; 1541 align-items: center; 1542 gap: 8px; 1543 font-size: 13px; 1544 color: #475569; 1545 margin-bottom: 8px; 1546 } 1547 1548 .irisai-mode-options .mode-features li:last-child { 1549 margin-bottom: 0; 1550 } 1551 1552 .irisai-mode-options .mode-features .dashicons { 1553 width: 18px; 1554 height: 18px; 1555 font-size: 18px; 1556 } 1557 1558 .irisai-mode-options .mode-features .dashicons-yes-alt { 1559 color: #10b981; 1560 } 1561 1562 .irisai-mode-options .mode-features .dashicons-minus { 1563 color: #94a3b8; 1564 } 1565 1566 .irisai-mode-options .mode-checkmark { 1567 position: absolute; 1568 top: 20px; 1569 right: 20px; 1570 width: 28px; 1571 height: 28px; 1572 border-radius: 50%; 1573 background: #e2e8f0; 1574 display: flex; 1575 align-items: center; 1576 justify-content: center; 1577 opacity: 0; 1578 transition: all 0.2s ease; 1579 } 1580 1581 .irisai-mode-card.selected .mode-checkmark { 1582 opacity: 1; 1583 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1584 } 1585 1586 .irisai-mode-options .mode-checkmark .dashicons { 1587 color: #fff; 1588 font-size: 16px; 1589 width: 16px; 1590 height: 16px; 1591 } 1592 1593 .irisai-status-card { 1594 background: #fff; 1595 border: 2px solid #e2e8f0; 1596 border-radius: 12px; 1597 padding: 24px; 1598 display: flex; 1599 gap: 20px; 1600 align-items: flex-start; 1601 margin-bottom: 32px; 1602 } 1603 1604 .irisai-status-card.success { 1605 background: #f0fdf4; 1606 border-color: #86efac; 1607 } 1608 1609 .irisai-status-card.warning { 1610 background: #fffbeb; 1611 border-color: #fde68a; 1612 } 1613 1614 .irisai-wizard-inner-container .status-icon { 1615 width: 48px; 1616 height: 48px; 1617 border-radius: 12px; 1618 display: flex; 1619 align-items: center; 1620 justify-content: center; 1621 flex-shrink: 0; 1622 } 1623 1624 .irisai-status-card.success .status-icon { 1625 background: #22c55e; 1626 color: #fff; 1627 } 1628 1629 .irisai-status-card.warning .status-icon { 1630 background: #f59e0b; 1631 color: #fff; 1632 } 1633 1634 .irisai-wizard-inner-container .status-icon .dashicons { 1635 font-size: 28px; 1636 width: 28px; 1637 height: 28px; 1638 } 1639 1640 .irisai-wizard-inner-container .status-content h3 { 1641 font-size: 16px; 1642 font-weight: 600; 1643 margin: 0 0 8px; 1644 color: #1e293b; 1645 } 1646 1647 .irisai-wizard-inner-container .status-content p { 1648 font-size: 14px; 1649 color: #64748b; 1650 margin: 0; 1651 line-height: 1.5; 1652 } 1653 1654 .irisai-indexing-section { 1655 background: #fff; 1656 border: 2px solid #e2e8f0; 1657 border-radius: 12px; 1658 padding: 32px; 1659 margin-bottom: 32px; 1660 } 1661 1662 .irisai-wizard-inner-container .indexing-controls { 1663 display: flex; 1664 gap: 12px; 1665 margin-bottom: 24px; 1666 } 1667 1668 .irisai-wizard-inner-container .indexing-controls .button-hero { 1669 display: inline-flex; 1670 align-items: center; 1671 height: auto; 1672 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1673 border: none; 1674 box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); 1675 text-shadow: none; 1676 display: inline-flex; 1677 align-items: center; 1678 gap: 8px; 1679 font-size: 14px; 1680 min-height: 46px; 1681 line-height: 3.14285714; 1682 padding: 0 36px; 1683 } 1684 1685 .irisai-wizard-inner-container .indexing-controls .button-hero .dashicons { 1686 font-size: 18px; 1687 width: 18px; 1688 height: 18px; 1689 } 1690 1691 .irisai-wizard-inner-container .indexing-controls .button .dashicons { 1692 font-size: 16px; 1693 width: 16px; 1694 height: 16px; 1695 margin-right: 6px; 1696 } 1697 1698 .irisai-wizard-inner-container .indexing-progress { 1699 background: #f8fafc; 1700 border: 1px solid #e2e8f0; 1701 border-radius: 10px; 1702 padding: 24px; 1703 margin-top: 24px; 1704 } 1705 1706 .irisai-wizard-inner-container .progress-header { 1707 display: flex; 1708 justify-content: space-between; 1709 align-items: center; 1710 margin-bottom: 12px; 1711 } 1712 1713 .irisai-wizard-inner-container .progress-status { 1714 display: flex; 1715 align-items: center; 1716 gap: 10px; 1717 font-size: 14px; 1718 font-weight: 600; 1719 color: #1e293b; 1720 } 1721 1722 .irisai-wizard-inner-container .status-dot { 1723 width: 8px; 1724 height: 8px; 1725 border-radius: 50%; 1726 background: #667eea; 1727 animation: pulse 2s ease-in-out infinite; 1728 } 1729 1730 @keyframes pulse { 1731 1732 0%, 1733 100% { 1734 opacity: 1; 1735 } 1736 1737 50% { 1738 opacity: 0.5; 1739 } 1740 } 1741 1742 .irisai-wizard-inner-container .progress-percentage { 1743 font-size: 14px; 1744 font-weight: 600; 1745 color: #667eea; 1746 } 1747 1748 .irisai-wizard-inner-container .progress-bar-container { 1749 height: 12px; 1750 background: #e2e8f0; 1751 border-radius: 999px; 1752 overflow: hidden; 1753 margin-bottom: 12px; 1754 } 1755 1756 .irisai-wizard-inner-container .progress-bar { 1757 height: 100%; 1758 width: 0%; 1759 background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); 1760 transition: width 0.3s ease; 1761 border-radius: 999px; 1762 } 1763 1764 .irisai-wizard-inner-container .progress-details { 1765 font-size: 13px; 1766 color: #64748b; 1767 margin: 0; 1768 } 1769 1770 .irisai-wizard-inner-container .indexing-message { 1771 margin-top: 20px; 1772 } 1773 1774 .irisai-wizard-inner-container .indexing-message .notice { 1775 margin: 0; 1776 border-radius: 8px; 1777 } 1778 1779 .irisai-wizard-inner-container .finish-form { 1780 background: #f0fdf4; 1781 border: 2px solid #86efac; 1782 border-radius: 12px; 1783 padding: 32px; 1784 text-align: center; 1785 } 1786 1787 .irisai-wizard-inner-container .finish-content { 1788 display: flex; 1789 align-items: center; 1790 justify-content: center; 1791 gap: 20px; 1792 margin-bottom: 24px; 1793 } 1794 1795 .irisai-wizard-inner-container .finish-icon { 1796 width: 64px; 1797 height: 64px; 1798 background: #22c55e; 1799 border-radius: 50%; 1800 display: flex; 1801 align-items: center; 1802 justify-content: center; 1803 color: #fff; 1804 } 1805 1806 .irisai-wizard-inner-container .finish-icon .dashicons { 1807 font-size: 36px; 1808 width: 36px; 1809 height: 36px; 1810 } 1811 1812 .irisai-wizard-inner-container .finish-text { 1813 text-align: left; 1814 } 1815 1816 .irisai-wizard-inner-container .finish-text h3 { 1817 font-size: 20px; 1818 font-weight: 600; 1819 margin: 0 0 6px; 1820 color: #1e293b; 1821 } 1822 1823 .irisai-wizard-inner-container .finish-text p { 1824 font-size: 14px; 1825 color: #64748b; 1826 margin: 0; 1827 } 1828 1829 .irisai-wizard-inner-container .finish-form .button-hero { 1830 display: inline-flex; 1831 align-items: center; 1832 gap: 8px; 1833 } 1834 1835 .irisai-wizard-container { 1836 max-width: 900px; 1837 margin: 40px auto; 1838 background: #fff; 1839 border-radius: 12px; 1840 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); 1841 padding: 48px; 1842 } 1843 1844 .irisai-wizard-header { 1845 text-align: center; 1846 margin-bottom: 48px; 1847 } 1848 1849 .irisai-wizard-icon { 1850 width: 72px; 1851 height: 72px; 1852 margin: 0 auto 24px; 1853 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1854 border-radius: 16px; 1855 display: flex; 1856 align-items: center; 1857 justify-content: center; 1858 color: #fff; 1859 } 1860 1861 .irisai-wizard-header h1 { 1862 font-size: 32px; 1863 font-weight: 600; 1864 margin: 0 0 12px; 1865 color: #1e293b; 1866 } 1867 1868 .irisai-wizard-subtitle { 1869 font-size: 16px; 1870 color: #64748b; 1871 margin: 0; 1872 } 1873 1874 .irisai-wizard-steps-preview { 1875 display: grid; 1876 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); 1877 gap: 20px; 1878 margin-bottom: 40px; 1879 } 1880 1881 .irisai-step-card { 1882 background: #f8fafc; 1883 border: 1px solid #e2e8f0; 1884 border-radius: 8px; 1885 padding: 24px; 1886 text-align: center; 1887 transition: all 0.2s ease; 1888 } 1889 1890 .irisai-step-card:hover { 1891 border-color: #667eea; 1892 transform: translateY(-2px); 1893 box-shadow: 0 4px 12px rgba(102, 126, 234, 0.1); 1894 } 1895 1896 .irisai-wizard-inner-container .step-number { 1897 width: 40px; 1898 height: 40px; 1899 margin: 0 auto 16px; 1900 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1901 color: #fff; 1902 border-radius: 50%; 1903 display: flex; 1904 align-items: center; 1905 justify-content: center; 1906 font-weight: 600; 1907 font-size: 18px; 1908 } 1909 1910 .irisai-wizard-inner-container .irisai-step-card h3 { 1911 font-size: 16px; 1912 font-weight: 600; 1913 margin: 0 0 8px; 1914 color: #1e293b; 1915 } 1916 1917 .irisai-step-card p { 1918 font-size: 13px; 1919 color: #64748b; 1920 margin: 0; 1921 line-height: 1.5; 1922 } 1923 1924 1925 .irisai-wizard-actions .button-hero { 1926 font-size: 16px; 1927 padding: 12px 32px; 1928 height: auto; 1929 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 1930 border: none; 1931 box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); 1932 text-shadow: none; 1933 display: inline-flex; 1934 align-items: center; 1935 } 1936 1937 .irisai-wizard-actions .button-hero:hover { 1938 background: linear-gradient(135deg, #5568d3 0%, #6a3f8f 100%); 1939 transform: translateY(-1px); 1940 box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4); 1941 } 1942 1943 1944 .irisai-wizard-actions .button-link:hover { 1945 color: #1e293b; 1946 } 1947 1948 1949 .irisai-setup-wrap { 1950 margin: 20px 20px 0 0; 1951 } 1952 1953 .irisai-wizard-notice-wrapper { 1954 max-width: 900px; 1955 margin: 20px auto 0; 1956 } 1957 1958 .irisai-wizard-notice-wrapper .notice { 1959 margin: 0 0 20px; 1960 border-radius: 8px; 1961 border-left-width: 4px; 1962 } 1963 1964 .irisai-wizard-container { 1965 max-width: 900px; 1966 margin: 40px auto; 1967 background: #fff; 1968 border-radius: 12px; 1969 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); 1970 padding: 48px; 1971 } 1972 1973 .irisai-wizard-header { 1974 text-align: center; 1975 margin-bottom: 40px; 1976 } 1977 1978 .irisai-wizard-header h1 { 1979 font-size: 28px; 1980 font-weight: 600; 1981 margin: 0 0 12px; 1982 color: #1e293b; 1983 } 1984 1985 .irisai-wizard-subtitle { 1986 font-size: 15px; 1987 color: #64748b; 1988 margin: 0; 1989 line-height: 1.5; 1990 } 1991 1992 .irisai-wizard-actions { 1993 text-align: center; 1994 margin-top: 32px; 1995 padding-top: 24px; 1996 border-top: 1px solid #e2e8f0; 1997 display: flex; 1998 flex-direction: column; 1999 align-items:center; 2000 gap: 5px; 2001 } 2002 2003 2004 .irisai-wizard-actions .button-hero { 2005 font-size: 16px; 2006 padding: 12px 32px; 2007 height: auto; 2008 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 2009 border: none; 2010 box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); 2011 text-shadow: none; 2012 display: inline-flex; 2013 align-items: center; 2014 gap: 8px; 2015 } 2016 2017 .irisai-wizard-actions .button-hero:hover { 2018 background: linear-gradient(135deg, #5568d3 0%, #6a3f8f 100%); 2019 transform: translateY(-1px); 2020 box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4); 2021 } 2022 2023 .irisai-wizard-actions .button-hero .dashicons { 2024 margin: 0; 2025 font-size: 18px; 2026 width: 18px; 2027 height: 18px; 2028 } 2029 2030 .irisai-wizard-actions .button-link,.irisai-skip-form .button-link,.indexing-controls .button-link { 2031 margin-top: 16px; 2032 color: #64748b; 2033 text-decoration: none; 2034 padding: 5px 20px; 2035 border-radius: 5px; 2036 background: #f6f7f7; 2037 } 2038 .indexing-controls .button-link { 2039 margin-top: 0; 2040 display: flex; 2041 align-items: center; 2042 } 2043 .irisai-wizard-actions .button-link:hover , .irisai-skip-form .button-link:hover, .indexing-controls .button-link:hover { 2044 color: #1e293b; 2045 } 2046 2047 .irisai-progress-bar-wrapper { 2048 margin: 20px 0 24px; 2049 padding: 0 20px; 2050 } 2051 2052 .irisai-progress-info { 2053 display: flex; 2054 justify-content: space-between; 2055 align-items: center; 2056 margin-bottom: 8px; 2057 } 2058 2059 .irisai-progress-step { 2060 font-size: 13px; 2061 font-weight: 600; 2062 color: #1e293b; 2063 } 2064 2065 .irisai-progress-percent { 2066 font-size: 13px; 2067 font-weight: 600; 2068 color: #667eea; 2069 } 2070 2071 .irisai-progress-bar-container { 2072 height: 8px; 2073 background: #e5e7eb; 2074 border-radius: 999px; 2075 overflow: hidden; 2076 box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05); 2077 } 2078 2079 .irisai-progress-bar-fill { 2080 height: 100%; 2081 background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); 2082 border-radius: 999px; 2083 transition: width 0.3s ease; 2084 box-shadow: 0 1px 3px rgba(102, 126, 234, 0.3); 2085 } 2086 2087 @media (max-width: 768px) { 2088 .irisai-wizard-container { 2089 padding: 32px 24px; 2090 margin: 20px; 2091 } 2092 2093 .irisai-wizard-header h1 { 2094 font-size: 24px; 2095 } 2096 } 2097 /* Shortcode Reference Section */ 2098 .irisai-wizard-shortcode-ref { 2099 background: #f8fafc; 2100 border: 2px solid #e2e8f0; 2101 border-radius: 12px; 2102 padding: 32px; 2103 margin-bottom: 32px; 2104 } 2105 2106 .irisai-wizard-shortcode-ref h3 { 2107 font-size: 18px; 2108 font-weight: 600; 2109 margin: 0 0 12px; 2110 color: #1e293b; 2111 } 2112 2113 .irisai-wizard-shortcode-ref > p { 2114 font-size: 14px; 2115 color: #64748b; 2116 margin: 0 0 24px; 2117 line-height: 1.6; 2118 } 2119 2120 .irisai-wizard-shortcode-ref h4 { 2121 font-size: 15px; 2122 font-weight: 600; 2123 margin: 0 0 12px; 2124 color: #1e293b; 2125 } 2126 2127 .irisai-wizard-shortcode-ref ul { 2128 list-style: none; 2129 margin: 0 0 24px; 2130 padding: 0; 2131 } 2132 2133 .irisai-wizard-shortcode-ref ul:last-child { 2134 margin-bottom: 0; 2135 } 2136 2137 .irisai-wizard-shortcode-ref li { 2138 display: flex; 2139 align-items: center; 2140 gap: 12px; 2141 font-size: 14px; 2142 color: #475569; 2143 margin-bottom: 12px; 2144 padding: 12px; 2145 background: #fff; 2146 border: 1px solid #e2e8f0; 2147 border-radius: 8px; 2148 transition: all 0.2s ease; 2149 } 2150 2151 .irisai-wizard-shortcode-ref li:last-child { 2152 margin-bottom: 0; 2153 } 2154 2155 .irisai-wizard-shortcode-ref li:hover { 2156 border-color: #cbd5e1; 2157 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); 2158 } 2159 2160 .irisai-wizard-shortcode-ref code { 2161 font-family: 'Monaco', 'Menlo', 'Courier New', monospace; 2162 font-size: 13px; 2163 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 2164 color: #fff; 2165 padding: 6px 12px; 2166 border-radius: 6px; 2167 font-weight: 500; 2168 white-space: nowrap; 2169 flex-shrink: 0; 2170 } 2171 2172 .irisai-wizard-shortcode-ref .shortcode-description { 2173 flex: 1; 2174 } 2175 2176 .irisai-wizard-shortcode-ref .copy-shortcode { 2177 display: inline-flex; 2178 align-items: center; 2179 gap: 6px; 2180 padding: 8px 14px; 2181 font-size: 13px; 2182 height: auto; 2183 min-height: 0; 2184 line-height: 1; 2185 flex-shrink: 0; 2186 } 2187 2188 .irisai-wizard-shortcode-ref .copy-shortcode .dashicons { 2189 font-size: 16px; 2190 width: 16px; 2191 height: 16px; 2192 } -
iris-ai/trunk/includes/class-irisai-admin.php
r3424224 r3447337 70 70 { 71 71 72 $allowed = array('post.php', 'post-new.php', 'toplevel_page_irisai'); 73 74 if (! in_array($hook, $allowed, true)) { 72 if ( 73 strpos($hook, 'irisai') === false && 74 ! in_array($hook, ['post.php', 'post-new.php'], true) 75 ) { 75 76 return; 76 77 } 78 77 79 78 80 $base_path = IRISAI_PATH . 'assets/js/'; … … 101 103 'vector-index' => 'admin-vector-index.js', 102 104 'usage-guide' => 'admin-usage-guide.js', 105 'setup-wizard' => 'admin-wizard.js', 103 106 ); 104 107 -
iris-ai/trunk/includes/class-irisai-rest.php
r3424224 r3447337 485 485 public static function start_indexing($request) 486 486 { 487 488 if (! self::check_admin_permissions($request)) { 489 return new \WP_Error('rest_forbidden', 'Unauthorized', ['status' => 401]); 490 } 491 return self::run_indexing(); 492 } 493 494 /** 495 * Run indexing process (internal engine) 496 * 497 * This method contains the core indexing logic and is safe to be called 498 * internally by the plugin (e.g., from the Setup Wizard) without requiring 499 * REST authentication context. 500 * 501 * @since 1.1.0 502 * @return WP_REST_Response Response object. 503 */ 504 public static function run_indexing() 505 { 506 507 delete_transient('irisai_has_index'); 487 508 $site_id = self::get_site_id(); 488 509 … … 575 596 $state['error'] = 'cancelled'; 576 597 update_option("irisai_index_job_$job_id", $state, false); 598 delete_transient('irisai_has_index'); 577 599 578 600 return new WP_REST_Response(array('ok' => true), 200); … … 689 711 error_log('[IrisAI Worker] All posts processed! Marking job as complete'); 690 712 $state['done'] = true; 713 $state['completed_at'] = time(); 714 delete_transient('irisai_has_index'); 691 715 } 692 716 … … 830 854 } catch (\Exception $e) { 831 855 error_log('[IrisAI Worker] Error storing chunks for post ' . $post->ID . ': ' . $e->getMessage()); 856 857 858 /** 859 * @since 2.0.0 860 * On embedding/storage failure, mark the entire indexing job as failed 861 * and stop further processing. 862 */ 863 // CRITICAL: mark job as failed 864 $state['error'] = $e->getMessage(); 865 $state['error_details'] = sprintf( 866 'Post %d: %s', 867 $post->ID, 868 $e->getMessage() 869 ); 870 $state['done'] = true; 871 872 update_option("irisai_index_job_$job_id", $state, false); 873 874 // Stop further processing 875 return; 832 876 } 833 877 } else { … … 1019 1063 // Clear dimension mismatch warning after successful full reindex 1020 1064 delete_transient('irisai_embedding_mismatch_detected'); 1021 1065 delete_transient('irisai_has_index'); 1022 1066 return true; 1023 1067 } else { … … 1137 1181 1138 1182 $deleted = IrisAI_Vector_DB::clear_site_data($site_id); 1139 1183 delete_transient('irisai_has_index'); 1140 1184 // Clear any local indexing job states 1141 1185 global $wpdb; -
iris-ai/trunk/includes/settings/traits/trait-settings-widgetfields.php
r3424224 r3447337 1 1 <?php 2 2 3 /** 3 4 * Widget Settings Fields Trait … … 11 12 namespace IrisAI; 12 13 13 if ( ! defined( 'ABSPATH' )) {14 if (! defined('ABSPATH')) { 14 15 exit; 15 16 } … … 20 21 * Provides widget-related settings fields and sections. 21 22 */ 22 trait Settings_WidgetFields { 23 trait Settings_WidgetFields 24 { 23 25 24 26 /** … … 28 30 * @return void 29 31 */ 30 private static function register_widget_settings() { 32 private static function register_widget_settings() 33 { 31 34 // Auto-inject widget 32 35 register_setting( … … 46 49 array( 47 50 'type' => 'string', 48 'sanitize_callback' => array( __CLASS__, 'sanitize_widget_position'),51 'sanitize_callback' => array(__CLASS__, 'sanitize_widget_position'), 49 52 'default' => 'bottom-right', 50 53 ) … … 58 61 'type' => 'string', 59 62 'sanitize_callback' => 'wp_kses_post', 60 'default' => __( 'Hi! How can I help you today?', 'iris-ai'),63 'default' => __('Hi! How can I help you today?', 'iris-ai'), 61 64 ) 62 65 ); … … 79 82 array( 80 83 'type' => 'integer', 81 'sanitize_callback' => array( __CLASS__, 'sanitize_max_history'),84 'sanitize_callback' => array(__CLASS__, 'sanitize_max_history'), 82 85 'default' => 50, 83 86 ) … … 113 116 'type' => 'string', 114 117 'sanitize_callback' => 'sanitize_text_field', 115 'default' => __( 'Chat with us', 'iris-ai'),118 'default' => __('Chat with us', 'iris-ai'), 116 119 ) 117 120 ); … … 135 138 * @return void 136 139 */ 137 private static function add_widget_sections() { 140 private static function add_widget_sections() 141 { 138 142 add_settings_section( 139 143 'irisai_widget_section', 140 __( 'Widget Configuration', 'iris-ai'),141 array( __CLASS__, 'render_widget_section'),144 __('Widget Configuration', 'iris-ai'), 145 array(__CLASS__, 'render_widget_section'), 142 146 'irisai' 143 147 ); … … 145 149 add_settings_section( 146 150 'irisai_widget_behavior_section', 147 __( 'Widget Behavior', 'iris-ai'),148 array( __CLASS__, 'render_widget_behavior_section'),151 __('Widget Behavior', 'iris-ai'), 152 array(__CLASS__, 'render_widget_behavior_section'), 149 153 'irisai' 150 154 ); … … 157 161 * @return void 158 162 */ 159 private static function add_widget_fields() { 163 private static function add_widget_fields() 164 { 160 165 // Auto-inject widget 161 166 add_settings_field( 162 167 'irisai_auto_inject_widget', 163 __( 'Auto-inject Widget', 'iris-ai'),164 array( __CLASS__, 'field_auto_inject_widget'),168 __('Auto-inject Widget', 'iris-ai'), 169 array(__CLASS__, 'field_auto_inject_widget'), 165 170 'irisai', 166 171 'irisai_widget_section' … … 170 175 add_settings_field( 171 176 'irisai_widget_position', 172 __( 'Widget Position', 'iris-ai'),173 array( __CLASS__, 'field_widget_position'),177 __('Widget Position', 'iris-ai'), 178 array(__CLASS__, 'field_widget_position'), 174 179 'irisai', 175 180 'irisai_widget_section' … … 179 184 add_settings_field( 180 185 'irisai_widget_label', 181 __( 'Widget Button Label', 'iris-ai'),182 array( __CLASS__, 'field_widget_label'),186 __('Widget Button Label', 'iris-ai'), 187 array(__CLASS__, 'field_widget_label'), 183 188 'irisai', 184 189 'irisai_widget_section' … … 188 193 add_settings_field( 189 194 'irisai_welcome_message', 190 __( 'Welcome Message', 'iris-ai'),191 array( __CLASS__, 'field_welcome_message'),195 __('Welcome Message', 'iris-ai'), 196 array(__CLASS__, 'field_welcome_message'), 192 197 'irisai', 193 198 'irisai_widget_behavior_section' … … 197 202 add_settings_field( 198 203 'irisai_show_welcome', 199 __( 'Show Welcome Message', 'iris-ai'),200 array( __CLASS__, 'field_show_welcome'),204 __('Show Welcome Message', 'iris-ai'), 205 array(__CLASS__, 'field_show_welcome'), 201 206 'irisai', 202 207 'irisai_widget_behavior_section' … … 206 211 add_settings_field( 207 212 'irisai_show_suggestions_widget', 208 __( 'Show Suggestion Chips', 'iris-ai'),209 array( __CLASS__, 'field_show_suggestions_widget'),213 __('Show Suggestion Chips', 'iris-ai'), 214 array(__CLASS__, 'field_show_suggestions_widget'), 210 215 'irisai', 211 216 'irisai_widget_behavior_section' … … 215 220 add_settings_field( 216 221 'irisai_enable_history', 217 __( 'Enable Chat History', 'iris-ai'),218 array( __CLASS__, 'field_enable_history'),222 __('Enable Chat History', 'iris-ai'), 223 array(__CLASS__, 'field_enable_history'), 219 224 'irisai', 220 225 'irisai_widget_behavior_section' … … 224 229 add_settings_field( 225 230 'irisai_max_history', 226 __( 'Max History Messages', 'iris-ai'),227 array( __CLASS__, 'field_max_history'),231 __('Max History Messages', 'iris-ai'), 232 array(__CLASS__, 'field_max_history'), 228 233 'irisai', 229 234 'irisai_widget_behavior_section' … … 233 238 add_settings_field( 234 239 'irisai_enable_sources', 235 __( 'Show Sources', 'iris-ai'),236 array( __CLASS__, 'field_enable_sources'),240 __('Show Sources', 'iris-ai'), 241 array(__CLASS__, 'field_enable_sources'), 237 242 'irisai', 238 243 'irisai_widget_behavior_section' … … 246 251 * @return void 247 252 */ 248 public static function render_widget_section() { 249 ?> 250 <p><?php esc_html_e( 'Configure the floating chat widget that appears on your website. You can place it manually using the [irisai_widget] shortcode or enable auto-injection to show it on all pages.', 'iris-ai' ); ?></p> 253 public static function render_widget_section() 254 { 255 ?> 256 <p><?php esc_html_e('Configure the floating chat widget that appears on your website. You can place it manually using the [irisai_widget] shortcode or enable auto-injection to show it on all pages.', 'iris-ai'); ?></p> 251 257 <div class="notice notice-info inline"> 252 258 <p> 253 <strong><?php esc_html_e( 'Shortcode Usage:', 'iris-ai'); ?></strong>254 <code>[irisai_widget]</code> - <?php esc_html_e( 'Default position', 'iris-ai'); ?><br>255 <code>[irisai_widget position="bottom-left"]</code> - <?php esc_html_e( 'Custom position', 'iris-ai'); ?>259 <strong><?php esc_html_e('Shortcode Usage:', 'iris-ai'); ?></strong> 260 <code>[irisai_widget]</code> - <?php esc_html_e('Default position', 'iris-ai'); ?><br> 261 <code>[irisai_widget position="bottom-left"]</code> - <?php esc_html_e('Custom position', 'iris-ai'); ?> 256 262 </p> 257 263 </div> 258 <?php264 <?php 259 265 } 260 266 … … 265 271 * @return void 266 272 */ 267 public static function render_widget_behavior_section() { 268 ?> 269 <p><?php esc_html_e( 'Customize how the widget behaves and what information it displays to users.', 'iris-ai' ); ?></p> 270 <?php 273 public static function render_widget_behavior_section() 274 { 275 ?> 276 <p><?php esc_html_e('Customize how the widget behaves and what information it displays to users.', 'iris-ai'); ?></p> 277 <?php 271 278 } 272 279 … … 277 284 * @return void 278 285 */ 279 public static function field_auto_inject_widget() { 280 $value = get_option( 'irisai_auto_inject_widget', false ); 281 ?> 286 public static function field_auto_inject_widget() 287 { 288 $value = get_option('irisai_auto_inject_widget', false); 289 ?> 282 290 <label> 283 <input 284 type="checkbox" 285 name="irisai_auto_inject_widget" 286 value="1" 287 <?php checked( $value, true); ?> />288 <?php esc_html_e( 'Automatically add the chat widget to all pages', 'iris-ai'); ?>291 <input 292 type="checkbox" 293 name="irisai_auto_inject_widget" 294 value="1" 295 <?php checked($value, true); ?> /> 296 <?php esc_html_e('Automatically add the chat widget to all pages', 'iris-ai'); ?> 289 297 </label> 290 298 <p class="description"> 291 <?php esc_html_e( 'When enabled, the widget will appear on all pages. When disabled, use the shortcode to place it manually.', 'iris-ai'); ?>292 </p> 293 <?php299 <?php esc_html_e('When enabled, the widget will appear on all pages. When disabled, use the shortcode to place it manually.', 'iris-ai'); ?> 300 </p> 301 <?php 294 302 } 295 303 … … 300 308 * @return void 301 309 */ 302 public static function field_widget_position() { 303 $value = get_option( 'irisai_widget_position', 'bottom-right' ); 310 public static function field_widget_position() 311 { 312 $value = get_option('irisai_widget_position', 'bottom-right'); 304 313 $positions = array( 305 'bottom-right' => __( 'Bottom Right', 'iris-ai'),306 'bottom-left' => __( 'Bottom Left', 'iris-ai'),307 'top-right' => __( 'Top Right', 'iris-ai'),308 'top-left' => __( 'Top Left', 'iris-ai'),309 ); 310 ?>314 'bottom-right' => __('Bottom Right', 'iris-ai'), 315 'bottom-left' => __('Bottom Left', 'iris-ai'), 316 'top-right' => __('Top Right', 'iris-ai'), 317 'top-left' => __('Top Left', 'iris-ai'), 318 ); 319 ?> 311 320 <select name="irisai_widget_position" id="irisai_widget_position"> 312 <?php foreach ( $positions as $key => $label) : ?>313 <option value="<?php echo esc_attr( $key ); ?>" <?php selected( $value, $key); ?>>314 <?php echo esc_html( $label); ?>321 <?php foreach ($positions as $key => $label) : ?> 322 <option value="<?php echo esc_attr($key); ?>" <?php selected($value, $key); ?>> 323 <?php echo esc_html($label); ?> 315 324 </option> 316 325 <?php endforeach; ?> 317 326 </select> 318 327 <p class="description"> 319 <?php esc_html_e( 'Choose where the chat widget button appears on the screen.', 'iris-ai'); ?>320 </p> 321 <?php328 <?php esc_html_e('Choose where the chat widget button appears on the screen.', 'iris-ai'); ?> 329 </p> 330 <?php 322 331 } 323 332 … … 328 337 * @return void 329 338 */ 330 public static function field_widget_label() { 331 $value = get_option( 'irisai_widget_label', __( 'Chat with us', 'iris-ai' ) ); 332 ?> 333 <input 334 type="text" 335 name="irisai_widget_label" 339 public static function field_widget_label() 340 { 341 $value = get_option('irisai_widget_label', __('Chat with us', 'iris-ai')); 342 ?> 343 <input 344 type="text" 345 name="irisai_widget_label" 336 346 id="irisai_widget_label" 337 value="<?php echo esc_attr( $value ); ?>"347 value="<?php echo esc_attr($value); ?>" 338 348 class="regular-text" /> 339 349 <p class="description"> 340 <?php esc_html_e( 'The accessible label for the widget button (used for screen readers and tooltips).', 'iris-ai'); ?>341 </p> 342 <?php350 <?php esc_html_e('The accessible label for the widget button (used for screen readers and tooltips).', 'iris-ai'); ?> 351 </p> 352 <?php 343 353 } 344 354 … … 349 359 * @return void 350 360 */ 351 public static function field_welcome_message() { 352 $value = get_option( 'irisai_welcome_message', __( 'Hi! How can I help you today?', 'iris-ai' ) ); 353 ?> 354 <textarea 355 name="irisai_welcome_message" 361 public static function field_welcome_message() 362 { 363 $value = get_option('irisai_welcome_message', __('Hi! How can I help you today?', 'iris-ai')); 364 ?> 365 <textarea 366 name="irisai_welcome_message" 356 367 id="irisai_welcome_message" 357 rows="3" 358 class="large-text"><?php echo esc_textarea( $value); ?></textarea>359 <p class="description"> 360 <?php esc_html_e( 'The welcome message shown when users first open the chat widget. HTML is allowed.', 'iris-ai'); ?>361 </p> 362 <?php368 rows="3" 369 class="large-text"><?php echo esc_textarea($value); ?></textarea> 370 <p class="description"> 371 <?php esc_html_e('The welcome message shown when users first open the chat widget. HTML is allowed.', 'iris-ai'); ?> 372 </p> 373 <?php 363 374 } 364 375 … … 369 380 * @return void 370 381 */ 371 public static function field_show_welcome() { 372 $value = get_option( 'irisai_show_welcome', true ); 373 ?> 382 public static function field_show_welcome() 383 { 384 $value = get_option('irisai_show_welcome', true); 385 ?> 374 386 <label> 375 <input 376 type="checkbox" 377 name="irisai_show_welcome" 378 value="1" 379 <?php checked( $value, true); ?> />380 <?php esc_html_e( 'Show welcome message when widget opens', 'iris-ai'); ?>387 <input 388 type="checkbox" 389 name="irisai_show_welcome" 390 value="1" 391 <?php checked($value, true); ?> /> 392 <?php esc_html_e('Show welcome message when widget opens', 'iris-ai'); ?> 381 393 </label> 382 394 <p class="description"> 383 <?php esc_html_e( 'Display a friendly welcome message when users first open the chat.', 'iris-ai'); ?>384 </p> 385 <?php395 <?php esc_html_e('Display a friendly welcome message when users first open the chat.', 'iris-ai'); ?> 396 </p> 397 <?php 386 398 } 387 399 … … 392 404 * @return void 393 405 */ 394 public static function field_show_suggestions_widget() { 395 $value = get_option( 'irisai_show_suggestions_widget', true ); 396 ?> 406 public static function field_show_suggestions_widget() 407 { 408 $value = get_option('irisai_show_suggestions_widget', true); 409 ?> 397 410 <label> 398 <input 399 type="checkbox" 400 name="irisai_show_suggestions_widget" 401 value="1" 402 <?php checked( $value, true); ?> />403 <?php esc_html_e( 'Display suggestion chips in the chat widget', 'iris-ai'); ?>411 <input 412 type="checkbox" 413 name="irisai_show_suggestions_widget" 414 value="1" 415 <?php checked($value, true); ?> /> 416 <?php esc_html_e('Display suggestion chips in the chat widget', 'iris-ai'); ?> 404 417 </label> 405 418 <p class="description"> … … 407 420 printf( 408 421 /* translators: %s: link to general settings */ 409 esc_html__( 'Show clickable suggestion prompts to help users get started. Configure the suggestions in the %s.', 'iris-ai'),410 '<a href="' . esc_url( add_query_arg( 'tab', 'general', admin_url( 'admin.php?page=irisai' ) ) ) . '">' . esc_html__( 'General tab', 'iris-ai') . '</a>'422 esc_html__('Show clickable suggestion prompts to help users get started. Configure the suggestions in the %s.', 'iris-ai'), 423 '<a href="' . esc_url(add_query_arg('tab', 'general', admin_url('admin.php?page=irisai'))) . '">' . esc_html__('General tab', 'iris-ai') . '</a>' 411 424 ); 412 425 ?> 413 426 </p> 414 <?php427 <?php 415 428 } 416 429 … … 421 434 * @return void 422 435 */ 423 public static function field_enable_history() { 424 $value = get_option( 'irisai_enable_history', true ); 425 ?> 436 public static function field_enable_history() 437 { 438 $value = get_option('irisai_enable_history', true); 439 ?> 426 440 <label> 427 <input 428 type="checkbox" 429 name="irisai_enable_history" 430 value="1" 431 <?php checked( $value, true); ?> />432 <?php esc_html_e( 'Store chat history in browser localStorage', 'iris-ai'); ?>441 <input 442 type="checkbox" 443 name="irisai_enable_history" 444 value="1" 445 <?php checked($value, true); ?> /> 446 <?php esc_html_e('Store chat history in browser localStorage', 'iris-ai'); ?> 433 447 </label> 434 448 <p class="description"> 435 <?php esc_html_e( 'When enabled, chat messages persist across page reloads. Users can clear their history with the "New Chat" button.', 'iris-ai'); ?>436 </p> 437 <?php449 <?php esc_html_e('When enabled, chat messages persist across page reloads. Users can clear their history with the "New Chat" button.', 'iris-ai'); ?> 450 </p> 451 <?php 438 452 } 439 453 … … 444 458 * @return void 445 459 */ 446 public static function field_max_history() { 447 $value = get_option( 'irisai_max_history', 50 ); 448 ?> 449 <input 450 type="number" 451 name="irisai_max_history" 460 public static function field_max_history() 461 { 462 $value = get_option('irisai_max_history', 50); 463 ?> 464 <input 465 type="number" 466 name="irisai_max_history" 452 467 id="irisai_max_history" 453 value="<?php echo esc_attr( $value ); ?>"454 min="10" 455 max="100" 468 value="<?php echo esc_attr($value); ?>" 469 min="10" 470 max="100" 456 471 step="10" 457 472 class="small-text" /> 458 473 <p class="description"> 459 <?php esc_html_e( 'Maximum number of messages to store in chat history (10-100). Older messages are automatically removed.', 'iris-ai'); ?>460 </p> 461 <?php474 <?php esc_html_e('Maximum number of messages to store in chat history (10-100). Older messages are automatically removed.', 'iris-ai'); ?> 475 </p> 476 <?php 462 477 } 463 478 … … 468 483 * @return void 469 484 */ 470 public static function field_enable_sources() { 471 $value = get_option( 'irisai_enable_sources', false ); 472 ?> 485 public static function field_enable_sources() 486 { 487 $value = get_option('irisai_enable_sources', false); 488 ?> 473 489 <label> 474 <input 475 type="checkbox" 476 name="irisai_enable_sources" 477 value="1" 478 <?php checked( $value, true); ?> />479 <?php esc_html_e( 'Display source links with AI responses', 'iris-ai'); ?>490 <input 491 type="checkbox" 492 name="irisai_enable_sources" 493 value="1" 494 <?php checked($value, true); ?> /> 495 <?php esc_html_e('Display source links with AI responses', 'iris-ai'); ?> 480 496 </label> 481 497 <p class="description"> 482 <?php esc_html_e( 'Show clickable source cards below AI answers, linking to the pages where information was found.', 'iris-ai'); ?>483 </p> 484 <?php498 <?php esc_html_e('Show clickable source cards below AI answers, linking to the pages where information was found.', 'iris-ai'); ?> 499 </p> 500 <?php 485 501 } 486 502 … … 492 508 * @return string Sanitized position. 493 509 */ 494 public static function sanitize_widget_position( $value ) { 495 $allowed = array( 'bottom-right', 'bottom-left', 'top-right', 'top-left' ); 496 return in_array( $value, $allowed, true ) ? $value : 'bottom-right'; 510 public static function sanitize_widget_position($value) 511 { 512 $allowed = array('bottom-right', 'bottom-left', 'top-right', 'top-left'); 513 return in_array($value, $allowed, true) ? $value : 'bottom-right'; 497 514 } 498 515 … … 504 521 * @return int Sanitized value. 505 522 */ 506 public static function sanitize_max_history( $value ) { 507 $value = absint( $value ); 508 return max( 10, min( 100, $value ) ); 523 public static function sanitize_max_history($value) 524 { 525 $value = absint($value); 526 return max(10, min(100, $value)); 509 527 } 510 528 } -
iris-ai/trunk/iris-ai.php
r3428373 r3447337 4 4 * Plugin Name: Iris AI – AI Homepage, Chatbot & Site Assistant 5 5 * Description: AI assistant for WordPress with BYO-key or Proxy mode, chat UI, and content tools. 6 * Version: 1.0.56 * Version: 2.0.0 7 7 * Author: Irisai 8 8 * Author URI: https://irisai.cloud … … 23 23 24 24 // Plugin constants. 25 define('IRISAI_VERSION', ' 1.0.5');25 define('IRISAI_VERSION', '2.0.0'); 26 26 define('IRISAI_PATH', plugin_dir_path(__FILE__)); 27 27 define('IRISAI_URL', plugin_dir_url(__FILE__)); … … 38 38 require_once IRISAI_PATH . 'includes/class-irisai-vector-db.php'; 39 39 require_once IRISAI_PATH . 'includes/class-irisai-vector-integration.php'; 40 require_once IRISAI_PATH . '/setup-wizard/logic-config-checks.php'; 41 require_once IRISAI_PATH . '/setup-wizard/class-irisai-setup-wizard.php'; 40 42 41 43 /** … … 397 399 }); 398 400 399 add_filter( 'render_block', 'irisai_override_theme_hero', 10, 2);401 add_filter('render_block', 'irisai_override_theme_hero', 10, 2); 400 402 401 403 /** … … 411 413 * @return string 412 414 */ 413 function irisai_override_theme_hero( $block_content, $block ) { 415 function irisai_override_theme_hero($block_content, $block) 416 { 414 417 415 418 // Only modify front-end output (not editor, REST, AJAX, feeds, etc). 416 if ( is_admin() || wp_doing_ajax() || wp_is_json_request()) {419 if (is_admin() || wp_doing_ajax() || wp_is_json_request()) { 417 420 return $block_content; 418 421 } 419 422 420 423 // Validate expected block structure. 421 if ( empty( $block['attrs']['metadata']['name'] )) {424 if (empty($block['attrs']['metadata']['name'])) { 422 425 return $block_content; 423 426 } 424 427 425 428 // Only target the specific theme block. 426 if ( 'irisaitheme/hero' !== $block['attrs']['metadata']['name']) {429 if ('irisaitheme/hero' !== $block['attrs']['metadata']['name']) { 427 430 return $block_content; 428 431 } 429 432 430 433 // Only render if the shortcode is available. 431 if ( ! shortcode_exists( 'irisai_chat' )) {434 if (! shortcode_exists('irisai_chat')) { 432 435 return $block_content; 433 436 } 434 437 435 438 // Prevent potential recursive rendering. 436 remove_filter( 'render_block', 'irisai_override_theme_hero', 10);437 438 $replacement = do_shortcode( '[irisai_chat]');439 remove_filter('render_block', 'irisai_override_theme_hero', 10); 440 441 $replacement = do_shortcode('[irisai_chat]'); 439 442 440 443 // Restore filter after rendering. 441 add_filter( 'render_block', 'irisai_override_theme_hero', 10, 2);444 add_filter('render_block', 'irisai_override_theme_hero', 10, 2); 442 445 443 446 return $replacement; 444 447 } 448 449 /** 450 * @since 2.0.0 451 * Setup Wizard Initialization 452 */ 453 454 new \IrisAI\Admin\Setup_Wizard(); 455 456 457 register_activation_hook(__FILE__, function () { 458 459 if (! get_option('irisai_installed_version')) { 460 add_option('irisai_do_setup_wizard', 1); 461 } 462 463 update_option('irisai_installed_version', IRISAI_VERSION); 464 }); 465 466 add_action('admin_init', function () { 467 468 if (! current_user_can('manage_options')) { 469 return; 470 } 471 472 // Respect user skip or completion 473 if (get_option('irisai_setup_completed') || get_option('irisai_setup_dismissed')) { 474 return; 475 } 476 477 // If fully configured, mark as done and stop 478 if (function_exists('irisai_is_fully_configured') && irisai_is_fully_configured()) { 479 update_option('irisai_setup_completed', 1); 480 return; 481 } 482 483 // ONLY redirect when user is on THIS PAGE 484 if (isset($_GET['page']) && $_GET['page'] === 'irisai') { 485 486 // But don't redirect if already in wizard 487 if (isset($_GET['page']) && $_GET['page'] === 'irisai-setup') { 488 return; 489 } 490 491 wp_safe_redirect(admin_url('admin.php?page=irisai-setup')); 492 exit; 493 } 494 }); -
iris-ai/trunk/readme.txt
r3428373 r3447337 2 2 Contributors: zephyrwp 3 3 Donate link: https://irisai.cloud 4 Tags: ai, chatbot, openai, assistant, gpt, vector search, semantic search, rag4 Tags: ai, chatbot, openai, assistant, gpt, semantic search 5 5 Requires at least: 5.0 6 6 Tested up to: 6.9 7 Stable tag: 1.0.57 Stable tag: 2.0.0 8 8 Requires PHP: 7.4 9 9 License: GPLv2 or later … … 246 246 247 247 == Changelog == 248 = 2.0.0 = 249 Introduces the new Setup Wizard. 248 250 = 1.0.5 = 249 251 * Responsive style fixes … … 274 276 == Upgrade Notice == 275 277 278 = 2.0.0 = 279 Introduces the new Setup Wizard, improved background indexing system, clearer Proxy/BYO configuration flow, and multiple performance and stability improvements. 280 276 281 = 1.0.5 = 277 282 * Fixed issues in responsive mode
Note: See TracChangeset
for help on using the changeset viewer.