Changeset 3323103
- Timestamp:
- 07/06/2025 06:29:42 PM (8 months ago)
- Location:
- advanced-settings
- Files:
-
- 2 added
- 2 deleted
- 24 edited
- 1 copied
-
tags/3.1.0 (copied) (copied from advanced-settings/trunk)
-
tags/3.1.0/admin-ui/admin-ui.css (modified) (1 diff)
-
tags/3.1.0/admin-ui/react/app.css (modified) (3 diffs)
-
tags/3.1.0/admin-ui/react/app.js (modified) (16 diffs)
-
tags/3.1.0/advanced-settings.php (modified) (1 diff)
-
tags/3.1.0/feature-setup/categories.php (modified) (3 diffs)
-
tags/3.1.0/feature-setup/features/adminarea.php (added)
-
tags/3.1.0/feature-setup/features/advset.php (modified) (1 diff)
-
tags/3.1.0/feature-setup/features/dashboard.php (deleted)
-
tags/3.1.0/feature-setup/features/developer.php (modified) (5 diffs)
-
tags/3.1.0/feature-setup/features/editing.php (modified) (2 diffs)
-
tags/3.1.0/feature-setup/features/frontend.php (modified) (33 diffs)
-
tags/3.1.0/feature-setup/features/system.php (modified) (11 diffs)
-
tags/3.1.0/migrations/3.x.x.php (modified) (1 diff)
-
tags/3.1.0/readme.txt (modified) (6 diffs)
-
trunk/admin-ui/admin-ui.css (modified) (1 diff)
-
trunk/admin-ui/react/app.css (modified) (3 diffs)
-
trunk/admin-ui/react/app.js (modified) (16 diffs)
-
trunk/advanced-settings.php (modified) (1 diff)
-
trunk/feature-setup/categories.php (modified) (3 diffs)
-
trunk/feature-setup/features/adminarea.php (added)
-
trunk/feature-setup/features/advset.php (modified) (1 diff)
-
trunk/feature-setup/features/dashboard.php (deleted)
-
trunk/feature-setup/features/developer.php (modified) (5 diffs)
-
trunk/feature-setup/features/editing.php (modified) (2 diffs)
-
trunk/feature-setup/features/frontend.php (modified) (33 diffs)
-
trunk/feature-setup/features/system.php (modified) (11 diffs)
-
trunk/migrations/3.x.x.php (modified) (1 diff)
-
trunk/readme.txt (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
advanced-settings/tags/3.1.0/admin-ui/admin-ui.css
r3281733 r3323103 125 125 padding: 0; 126 126 max-width: 90%; 127 width: 6 0em;127 width: 65em; 128 128 height: 80vh; 129 129 background-color: #fff; -
advanced-settings/tags/3.1.0/admin-ui/react/app.css
r3281733 r3323103 18 18 .advset-category-sidebar { 19 19 min-width: 10em; 20 max-width: 18em; 20 21 flex-shrink: 0; 21 22 background-color: var(--advset-color-base-95); 22 23 border-right: 1px solid var(--advset-color-border); 23 24 position: sticky; 25 display: flex; 26 flex-direction: column; 27 } 28 29 /* Tab Navigation */ 30 .advset-tab-navigation { 31 display: flex; 32 border-bottom: 1px solid var(--advset-color-border); 33 background-color: var(--advset-color-base-97); 34 } 35 36 .advset-tab-button { 37 flex: 1; 38 background: none; 39 border: none; 40 padding: .75em 1em; 41 font-size: var(--advset-font-size-small); 42 font-weight: 600; 43 text-transform: uppercase; 44 letter-spacing: .03em; 45 color: var(--advset-color-base-70); 46 cursor: pointer; 47 transition: all .3s; 48 border-bottom: 2px solid transparent; 49 } 50 51 .advset-tab-button:hover:not(:disabled), 52 .advset-tab-button:focus-visible:not(:disabled) { 53 color: var(--advset-color-base); 54 background-color: var(--advset-color-base-90); 55 } 56 57 .advset-tab-button.is-active { 58 color: var(--advset-color-base); 59 border-bottom-color: var(--advset-color-base); 60 background-color: var(--advset-color-base-95); 61 font-weight: 700; 62 } 63 64 .advset-tab-button:disabled { 65 opacity: 0.5; 66 cursor: not-allowed; 67 } 68 69 /* Tab Content */ 70 .advset-tab-content { 71 flex: 1; 72 overflow-y: auto; 24 73 } 25 74 … … 69 118 font-weight: 600; 70 119 text-transform: uppercase; 120 } 121 122 123 124 .advset-tags-list { 125 display: flex; 126 flex-wrap: wrap; 127 gap: .5em; 128 padding: 1em; 129 } 130 131 .advset-tag { 132 background: none; 133 border: 1px solid var(--advset-color-base-70); 134 border-radius: 1em; 135 padding: .25em .75em; 136 font-size: var(--advset-font-size-tiny); 137 color: var(--advset-color-base-70); 138 cursor: pointer; 139 transition: all .3s; 140 font-family: inherit; 141 line-height: inherit; 142 } 143 144 .advset-tag:hover, 145 .advset-tag:focus-visible { 146 border-color: var(--advset-color-primary); 147 color: var(--advset-color-primary); 148 outline: var(--advset-color-primary) 1px solid; 149 } 150 151 .advset-tag.is-active { 152 background-color: var(--advset-color-primary); 153 border-color: var(--advset-color-primary); 154 color: var(--advset-color-background); 155 } 156 157 .advset-tag.is-disabled { 158 opacity: 0.5; 159 cursor: not-allowed; 160 color: var(--advset-color-base); 161 border-color: var(--advset-color-base-70); 162 background-color: var(--advset-color-base-70); 163 } 164 165 .advset-tag.is-disabled:hover, 166 .advset-tag.is-disabled:focus-visible { 167 border-color: var(--advset-color-base-50); 168 color: var(--advset-color-base-50); 169 outline: none; 71 170 } 72 171 … … 260 359 } 261 360 361 362 363 /* ===== Item Tags ===== */ 364 .advset-item-tags { 365 display: flex; 366 flex-wrap: wrap; 367 justify-content: flex-end; 368 gap: .5em; 369 margin-top: .5em; 370 } 371 372 .advset-item-tag { 373 background: none; 374 border: 1px solid var(--advset-color-base-70); 375 border-radius: 1em; 376 padding: .25em .75em; 377 font-size: var(--advset-font-size-tiny); 378 color: var(--advset-color-base-70); 379 cursor: pointer; 380 transition: all .3s; 381 font-family: inherit; 382 line-height: inherit; 383 } 384 385 .advset-item-tag:hover, 386 .advset-item-tag:focus-visible { 387 border-color: var(--advset-color-primary); 388 color: var(--advset-color-primary); 389 outline: var(--advset-color-primary) 1px solid; 390 } 391 392 .advset-item-tag.is-active { 393 background-color: var(--advset-color-primary); 394 border-color: var(--advset-color-primary); 395 color: var(--advset-color-background); 396 } 397 398 399 -
advanced-settings/tags/3.1.0/admin-ui/react/app.js
r3286786 r3323103 17 17 */ 18 18 function App(props) { 19 const { items, categories, onSettingChange, onCategoryClick, settings, searchQuery, activeCategory} = props;19 const { items, categories, onSettingChange, onCategoryClick, onTagClick, onTabChange, settings, searchQuery, parsedSearchQuery, activeCategory, hiddenItems, activeTab } = props; 20 20 21 21 // Group items by category … … 37 37 ); 38 38 39 // Extract all unique tags from all items (both visible and hidden) 40 const allTags = new Set(); 41 const visibleTagCounts = new Map(); 42 const hiddenTagCounts = new Map(); 43 44 // Count tags from visible items 45 items.forEach(item => { 46 if (item.ui_config?.tags) { 47 item.ui_config.tags.forEach(tag => { 48 allTags.add(tag); 49 visibleTagCounts.set(tag, (visibleTagCounts.get(tag) || 0) + 1); 50 }); 51 } 52 }); 53 54 // Count tags from hidden items 55 hiddenItems.forEach(item => { 56 if (item.ui_config?.tags) { 57 item.ui_config.tags.forEach(tag => { 58 allTags.add(tag); 59 hiddenTagCounts.set(tag, (hiddenTagCounts.get(tag) || 0) + 1); 60 }); 61 } 62 }); 63 64 const sortedTags = Array.from(allTags).sort(); 65 39 66 40 67 return React.createElement('div', { className: 'advset-react-app' }, … … 42 69 React.createElement('div', { className: 'advset-notifications' }), 43 70 44 // Category sidebar 45 visibleCategories.length > 0 && React.createElement('div', { className: 'advset-category-sidebar' }, 46 React.createElement('ul', { className: 'advset-category-menu' }, 47 visibleCategoriesIncludingSeparator.map(category => 48 React.createElement('li', { 49 key: category.id, 50 className: 'advset-category-menu-item' 51 }, 52 category.title ? 53 React.createElement('a', { 54 href: `#category-${category.id}`, 55 onClick: (e) => { 56 e.preventDefault(); 57 onCategoryClick(category.id); 58 }, 59 className: activeCategory === category.id ? 'is-active' : '' 60 }, 61 React.createElement('span', { 62 className: 'advset-category-icon', 63 dangerouslySetInnerHTML: { __html: category.icon || '' } 64 }), 65 React.createElement('span', { 66 className: 'advset-category-text' 67 }, category.title || category.id) 68 ) : React.createElement('div', { 69 className: 'advset-category-separator', 70 style: { 71 borderTop: '1px solid #ccc', 72 } 73 }) 71 // Sidebar with tab navigation 72 React.createElement('div', { className: 'advset-category-sidebar' }, 73 // Tab navigation 74 React.createElement('div', { className: 'advset-tab-navigation' }, 75 React.createElement('button', { 76 className: `advset-tab-button ${activeTab === 'categories' ? 'is-active' : ''}`, 77 onClick: () => onTabChange('categories'), 78 disabled: visibleCategories.length === 0 79 }, 'Categories'), 80 React.createElement('button', { 81 className: `advset-tab-button ${activeTab === 'tags' ? 'is-active' : ''}`, 82 onClick: () => onTabChange('tags'), 83 disabled: sortedTags.length === 0 84 }, 'Tags') 85 ), 86 87 // Categories tab content 88 activeTab === 'categories' && visibleCategories.length > 0 && React.createElement('div', { className: 'advset-tab-content' }, 89 React.createElement('ul', { className: 'advset-category-menu' }, 90 visibleCategoriesIncludingSeparator.map(category => 91 React.createElement('li', { 92 key: category.id, 93 className: 'advset-category-menu-item' 94 }, 95 category.title ? 96 React.createElement('a', { 97 href: `#category-${category.id}`, 98 onClick: (e) => { 99 e.preventDefault(); 100 onCategoryClick(category.id); 101 }, 102 className: activeCategory === category.id ? 'is-active' : '' 103 }, 104 React.createElement('span', { 105 className: 'advset-category-icon', 106 dangerouslySetInnerHTML: { __html: category.icon || '' } 107 }), 108 React.createElement('span', { 109 className: 'advset-category-text' 110 }, category.title || category.id) 111 ) : React.createElement('div', { 112 className: 'advset-category-separator', 113 style: { 114 borderTop: '1px solid #ccc', 115 } 116 }) 117 ) 74 118 ) 119 ) 120 ), 121 122 // Tags tab content 123 activeTab === 'tags' && sortedTags.length > 0 && React.createElement('div', { className: 'advset-tab-content' }, 124 React.createElement('div', { className: 'advset-tags-list' }, 125 sortedTags.map(tag => { 126 const isActive = parsedSearchQuery?.included?.tags?.includes(tag.toLowerCase()); 127 const hasVisibleItems = visibleTagCounts.has(tag); 128 const hasHiddenItems = hiddenTagCounts.has(tag); 129 130 let className = 'advset-tag'; 131 if (isActive) className += ' is-active'; 132 if (!hasVisibleItems && hasHiddenItems) className += ' is-disabled'; 133 134 return React.createElement('button', { 135 key: tag, 136 className: className, 137 onClick: () => onTagClick(tag), 138 disabled: !hasVisibleItems && hasHiddenItems 139 }, tag); 140 }) 75 141 ) 76 142 ) … … 102 168 item: item, 103 169 onSettingChange: onSettingChange, 104 settingValue: settings[item.id] || {} 170 onTagClick: onTagClick, 171 settingValue: settings[item.id] || {}, 172 parsedSearchQuery: parsedSearchQuery 105 173 }) 106 174 ) … … 138 206 */ 139 207 function ItemCard(props) { 140 const { item, onSettingChange, settingValue} = props;208 const { item, onSettingChange, onTagClick, settingValue, parsedSearchQuery } = props; 141 209 142 210 // Get the component from the registry … … 197 265 config: item.ui_config || {} 198 266 }) 267 ), 268 // Show tags if item has tags 269 item.ui_config?.tags && item.ui_config.tags.length > 0 && React.createElement('div', { 270 className: 'advset-item-tags' 271 }, 272 item.ui_config.tags.map(tag => 273 React.createElement('button', { 274 key: tag, 275 className: `advset-item-tag ${parsedSearchQuery?.included?.tags?.includes(tag.toLowerCase()) ? 'is-active' : ''}`, 276 onClick: () => onTagClick(tag) 277 }, tag) 278 ) 199 279 ) 200 280 ); … … 212 292 items: [], 213 293 allItems: [], // Cache for all items 294 hiddenItems: [], // Items that are hidden by current filter 214 295 isLoading: false, 215 296 categories: [], 216 297 settings: {}, // Store for settings values 217 298 activeCategory: null, // Track active category for scrolling 218 parsedSearchQuery: null // Cache for parsed search query 299 parsedSearchQuery: null, // Cache for parsed search query 300 activeTab: 'categories' // Track active tab: 'categories' or 'tags' 219 301 }, 220 302 … … 304 386 performLocalSearch(query) { 305 387 const parsedSearchQuery = query ? parseSearchQuery(query) : null; 388 const { filteredItems, hiddenItems } = this.filterItems(this.state.allItems, parsedSearchQuery); 306 389 307 390 this.setState({ 308 391 searchQuery: query, 309 392 parsedSearchQuery, 310 items: this.filterItems(this.state.allItems, parsedSearchQuery) 393 items: filteredItems, 394 hiddenItems: hiddenItems 311 395 }); 312 396 }, … … 317 401 * @param {Array} items - The items to filter 318 402 * @param {Object} parsedSearchQuery - The parsed search query 319 * @returns { Array} - Filtereditems403 * @returns {Object} - Object containing filtered and hidden items 320 404 */ 321 405 filterItems(items, parsedSearchQuery) { … … 323 407 const showExperimental = this.state.settings['advset.features.show_experimental']?.enable; 324 408 325 return items.filter(item => { 326 // Filter by feature flags 409 const filteredItems = []; 410 const hiddenItems = []; 411 412 items.forEach(item => { 413 // Check feature flags first 414 let isHiddenByFlags = false; 327 415 if (item.deprecated && !showDeprecated && typeof this.state.settings[item.id] === 'undefined') { 328 return false; 329 } 330 416 isHiddenByFlags = true; 417 } 331 418 if (item.experimental && !showExperimental && typeof this.state.settings[item.id] === 'undefined') { 332 return false;333 } 334 335 // If no search query, include the item 419 isHiddenByFlags = true; 420 } 421 422 // If no search query, include the item based on flags only 336 423 if (!parsedSearchQuery) { 337 return true; 338 } 339 340 // Search in ui_config fields 424 if (isHiddenByFlags) { 425 hiddenItems.push(item); 426 } else { 427 filteredItems.push(item); 428 } 429 return; 430 } 431 432 // Search in ui_config fields and tags 341 433 const searchTexts = []; 342 434 … … 354 446 } 355 447 356 const searchText = searchTexts.join(' ').toLowerCase(); 448 // Add tags to searchable text 449 if (item.ui_config?.tags) { 450 searchTexts.push(...item.ui_config.tags); 451 } 452 453 const searchText = searchTexts.join(Math.random()).toLowerCase(); 357 454 358 455 // Check if item matches all required terms 359 const matches Terms = parsedSearchQuery.terms.every(term =>456 const matchesIncludedTerms = parsedSearchQuery.included.terms.length === 0 || parsedSearchQuery.included.terms.every(term => 360 457 searchText.includes(term) 361 458 ); 362 459 363 460 // Check if item doesn't contain any excluded terms 364 const matchesExclu sions = !parsedSearchQuery.exclusions.some(exclusion =>461 const matchesExcludedTerms = !parsedSearchQuery.excluded.terms.some(exclusion => 365 462 searchText.includes(exclusion) 366 463 ); 367 464 368 // Item must match all terms and no exclusions 369 return matchesTerms && matchesExclusions; 465 // Check tag requirements (now using labels) 466 const itemTags = (item.ui_config?.tags || []).map(tag => tag.toLowerCase()); 467 468 // Item must have ALL required tags 469 const matchesIncludedTags = parsedSearchQuery.included.tags.length === 0 || parsedSearchQuery.included.tags.every(tag => 470 itemTags.includes(tag) 471 ); 472 473 // Item must NOT have ANY excluded tags 474 const matchesExcludedTags = !parsedSearchQuery.excluded.tags.some(tag => 475 itemTags.includes(tag) 476 ); 477 478 // Item must match all terms, no exclusions, required tags, and no excluded tags 479 const matchesSearch = matchesIncludedTerms && matchesExcludedTerms && matchesIncludedTags && matchesExcludedTags; 480 481 if (isHiddenByFlags || !matchesSearch) { 482 hiddenItems.push(item); 483 } else { 484 filteredItems.push(item); 485 } 370 486 }); 487 488 return { filteredItems, hiddenItems }; 371 489 }, 372 490 … … 399 517 400 518 // Apply initial filtering 519 const { filteredItems, hiddenItems } = this.filterItems(data.features); 401 520 this.setState({ 402 items: this.filterItems(data.features), 521 items: filteredItems, 522 hiddenItems: hiddenItems 403 523 }); 404 524 … … 433 553 }, 434 554 555 556 557 /** 558 * Handle tab change 559 * 560 * @param {string} tab - The tab to switch to 561 */ 562 handleTabChange(tab) { 563 this.setState({ activeTab: tab }); 564 }, 565 566 /** 567 * Handle tag click 568 * 569 * @param {string} tag - The tag that was clicked 570 */ 571 handleTagClick(tag) { 572 const searchInput = document.querySelector('.advset-modal-search input'); 573 if (!searchInput) return; 574 575 let currentQuery = searchInput.value.trim(); 576 577 // Handle tags with spaces by adding quotes 578 const tagPrefix = tag.includes(' ') ? `tag:"${tag}"` : `tag:${tag}`; 579 580 // Check if tag is already in query (handle both quoted and unquoted versions) 581 const tagRegex = new RegExp(`\\btag:("${tag.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"|${tag.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})\\b`, 'g'); 582 const hasTag = tagRegex.test(currentQuery); 583 584 if (hasTag) { 585 // Remove tag from query 586 currentQuery = currentQuery.replace(tagRegex, '').replace(/\s+/g, ' ').trim(); 587 } else { 588 // Add tag to query 589 currentQuery = currentQuery ? `${currentQuery} ${tagPrefix}` : tagPrefix; 590 } 591 592 // Update search input 593 searchInput.value = currentQuery; 594 595 // Trigger search 596 document.dispatchEvent(new CustomEvent('advset-search', { 597 detail: { query: currentQuery } 598 })); 599 }, 600 435 601 /** 436 602 * Render the application 437 603 */ 438 604 render() { 439 const { searchQuery, items, isLoading, categories} = this.state;605 const { searchQuery, parsedSearchQuery, items, hiddenItems, isLoading, categories, activeTab } = this.state; 440 606 441 607 // Render the React app … … 446 612 onSettingChange: this.handleSettingChange.bind(this), 447 613 onCategoryClick: this.scrollToCategory.bind(this), 614 onTagClick: this.handleTagClick.bind(this), 615 onTabChange: this.handleTabChange.bind(this), 448 616 settings: this.state.settings, 449 617 searchQuery: searchQuery, 450 activeCategory: this.state.activeCategory 618 parsedSearchQuery: parsedSearchQuery, 619 activeCategory: this.state.activeCategory, 620 hiddenItems: hiddenItems, 621 activeTab: activeTab 451 622 }); 452 623 … … 588 759 function parseSearchQuery(query) { 589 760 const result = { 590 terms: [], 591 exclusions: [] 761 excluded: { 762 tags: [], 763 terms: [], 764 }, 765 included: { 766 tags: [], 767 terms: [], 768 }, 592 769 }; 593 770 … … 596 773 597 774 // Extract terms and phrases (with optional minus) 598 const matches = query.match(/-?"[^"]+"|-[^\s]+|[^\s]+/g) || []; 599 600 matches.forEach(match => { 601 if (match.startsWith('-')) { 602 // Handle exclusions 603 const exclusion = match.startsWith('-"') 604 ? match.slice(2, -1) // Remove -" and " 605 : match.slice(1); // Remove - 606 if (exclusion) { 607 result.exclusions.push(exclusion.toLowerCase()); 608 } 609 } else { 610 // Handle regular terms 611 const term = match.startsWith('"') 612 ? match.slice(1, -1) // Remove quotes 613 : match; 614 if (term) { 615 result.terms.push(term.toLowerCase()); 616 } 617 } 775 query.matchAll(/(\-)?(tag:)?(?:("[^"]+")|([^"\s]+))/g).forEach(match => { 776 const isExclusion = match[1] === '-'; 777 const isTag = match[2] === 'tag:'; 778 const term = (match[3] ? match[3].slice(1, -1) : match[4]).toLowerCase(); 779 780 const targetList = result[isExclusion ? 'excluded' : 'included'][isTag ? 'tags' : 'terms']; 781 targetList.push(term); 618 782 }); 619 783 -
advanced-settings/tags/3.1.0/advanced-settings.php
r3306579 r3323103 6 6 Author: Helmut Wandl 7 7 Author URI: https://ehtmlu.com/ 8 Version: 3. 0.28 Version: 3.1.0 9 9 Requires at least: 5.0.0 10 10 Requires PHP: 7.4 -
advanced-settings/tags/3.1.0/feature-setup/categories.php
r3281733 r3323103 13 13 14 14 advset_register_category([ 15 'id' => ' dashboard',15 'id' => 'adminarea', 16 16 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>gauge</title><path d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,4A8,8 0 0,1 20,12C20,14.4 19,16.5 17.3,18C15.9,16.7 14,16 12,16C10,16 8.2,16.7 6.7,18C5,16.5 4,14.4 4,12A8,8 0 0,1 12,4M14,5.89C13.62,5.9 13.26,6.15 13.1,6.54L11.81,9.77L11.71,10C11,10.13 10.41,10.6 10.14,11.26C9.73,12.29 10.23,13.45 11.26,13.86C12.29,14.27 13.45,13.77 13.86,12.74C14.12,12.08 14,11.32 13.57,10.76L13.67,10.5L14.96,7.29L14.97,7.26C15.17,6.75 14.92,6.17 14.41,5.96C14.28,5.91 14.15,5.89 14,5.89M10,6A1,1 0 0,0 9,7A1,1 0 0,0 10,8A1,1 0 0,0 11,7A1,1 0 0,0 10,6M7,9A1,1 0 0,0 6,10A1,1 0 0,0 7,11A1,1 0 0,0 8,10A1,1 0 0,0 7,9M17,9A1,1 0 0,0 16,10A1,1 0 0,0 17,11A1,1 0 0,0 18,10A1,1 0 0,0 17,9Z" /></svg>', 17 'title' => __(' Dashboard', 'advanced-settings'),17 'title' => __('Admin Area', 'advanced-settings'), 18 18 'priority' => 10, 19 ]); 20 21 advset_register_category([ 22 'id' => 'frontend', 23 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>monitor</title><path d="M21,16H3V4H21M21,2H3C1.89,2 1,2.89 1,4V16A2,2 0 0,0 3,18H10V20H8V22H16V20H14V18H21A2,2 0 0,0 23,16V4C23,2.89 22.1,2 21,2Z" /></svg>', 24 'title' => __('Frontend', 'advanced-settings'), 25 'priority' => 20, 26 ]); 27 28 advset_register_category([ 29 'id' => 'editing', 30 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>pencil</title><path d="M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z" /></svg>', 31 'title' => __('Editing', 'advanced-settings'), 32 'priority' => 30, 19 33 ]); 20 34 … … 23 37 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>application-cog-outline</title><path d="M21.7 18.6V17.6L22.8 16.8C22.9 16.7 23 16.6 22.9 16.5L21.9 14.8C21.9 14.7 21.7 14.7 21.6 14.7L20.4 15.2C20.1 15 19.8 14.8 19.5 14.7L19.3 13.4C19.3 13.3 19.2 13.2 19.1 13.2H17.1C16.9 13.2 16.8 13.3 16.8 13.4L16.6 14.7C16.3 14.9 16.1 15 15.8 15.2L14.6 14.7C14.5 14.7 14.4 14.7 14.3 14.8L13.3 16.5C13.3 16.6 13.3 16.7 13.4 16.8L14.5 17.6V18.6L13.4 19.4C13.3 19.5 13.2 19.6 13.3 19.7L14.3 21.4C14.4 21.5 14.5 21.5 14.6 21.5L15.8 21C16 21.2 16.3 21.4 16.6 21.5L16.8 22.8C16.9 22.9 17 23 17.1 23H19.1C19.2 23 19.3 22.9 19.3 22.8L19.5 21.5C19.8 21.3 20 21.2 20.3 21L21.5 21.4C21.6 21.4 21.7 21.4 21.8 21.3L22.8 19.6C22.9 19.5 22.9 19.4 22.8 19.4L21.7 18.6M18 19.5C17.2 19.5 16.5 18.8 16.5 18S17.2 16.5 18 16.5 19.5 17.2 19.5 18 18.8 19.5 18 19.5M12.3 22H3C1.9 22 1 21.1 1 20V4C1 2.9 1.9 2 3 2H21C22.1 2 23 2.9 23 4V13.1C22.4 12.5 21.7 12 21 11.7V6H3V20H11.3C11.5 20.7 11.8 21.4 12.3 22Z" /></svg>', 24 38 'title' => __('System', 'advanced-settings'), 25 'priority' => 20,26 ]);27 28 advset_register_category([29 'id' => 'advset',30 'icon' => file_get_contents(ADVSET_DIR . '/admin-ui/images/admin-bar-icon.svg'),31 'title' => __('About & Options', 'advanced-settings'),32 'priority' => 100,33 ]);34 35 advset_register_category([36 'id' => 'advset-separator',37 'priority' => 99,38 ]);39 40 advset_register_category([41 'id' => 'frontend',42 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>monitor</title><path d="M21,16H3V4H21M21,2H3C1.89,2 1,2.89 1,4V16A2,2 0 0,0 3,18H10V20H8V22H16V20H14V18H21A2,2 0 0,0 23,16V4C23,2.89 22.1,2 21,2Z" /></svg>',43 'title' => __('Frontend', 'advanced-settings'),44 'priority' => 30,45 ]);46 47 advset_register_category([48 'id' => 'editing',49 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>pencil</title><path d="M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z" /></svg>',50 'title' => __('Editing', 'advanced-settings'),51 39 'priority' => 40, 52 40 ]); … … 58 46 'priority' => 50, 59 47 ]); 48 49 advset_register_category([ 50 'id' => 'advset-separator', 51 'priority' => 99, 52 ]); 53 54 advset_register_category([ 55 'id' => 'advset', 56 'icon' => file_get_contents(ADVSET_DIR . '/admin-ui/images/admin-bar-icon.svg'), 57 'title' => __('About & Options', 'advanced-settings'), 58 'priority' => 100, 59 ]); 60 60 }); -
advanced-settings/tags/3.1.0/feature-setup/features/advset.php
r3281733 r3323103 65 65 ], 66 66 'default' => '', 67 'description' => __('By default, we do not track plugin usage. If you agree to share your plugin usage with the developers, we will collect anonymous data about your usage. This data will be used to improve the plugin and to provide you with a better experience.', 'advanced-settings'), 67 68 ], 68 69 ] -
advanced-settings/tags/3.1.0/feature-setup/features/developer.php
r3306579 r3323103 15 15 'category' => 'developer', 16 16 'ui_config' => fn() => [ 17 'tags' => [ 18 __('Developer', 'advanced-settings'), 19 __('Debug', 'advanced-settings'), 20 __('Performance', 'advanced-settings'), 21 ], 17 22 'fields' => [ 18 23 'enable' => [ … … 44 49 'experimental' => true, 45 50 'ui_config' => fn() => [ 51 'tags' => [ 52 __('Developer', 'advanced-settings'), 53 __('Frontend', 'advanced-settings'), 54 __('Performance', 'advanced-settings'), 55 ], 46 56 'fields' => [ 47 57 'enable' => [ … … 83 93 'experimental' => true, 84 94 'ui_config' => fn() => [ 95 'tags' => [ 96 __('Developer', 'advanced-settings'), 97 __('Frontend', 'advanced-settings'), 98 __('Performance', 'advanced-settings'), 99 ], 85 100 'fields' => [ 86 101 'enable' => [ … … 122 137 'experimental' => true, 123 138 'ui_config' => fn() => [ 139 'tags' => [ 140 __('Developer', 'advanced-settings'), 141 __('Admin', 'advanced-settings'), 142 __('Posts', 'advanced-settings'), 143 ], 124 144 'fields' => [ 125 145 'enable' => [ … … 221 241 'experimental' => true, 222 242 'ui_config' => fn() => [ 243 'tags' => [ 244 __('Developer', 'advanced-settings'), 245 __('Admin', 'advanced-settings'), 246 __('Frontend', 'advanced-settings'), 247 __('Performance', 'advanced-settings'), 248 ], 223 249 'fields' => [ 224 250 'enable' => [ -
advanced-settings/tags/3.1.0/feature-setup/features/editing.php
r3281733 r3323103 12 12 13 13 advset_register_feature([ 14 'id' => 'editing.posts.disable_autosave', 15 'category' => 'editing', 16 'ui_config' => fn() => [ 17 'tags' => [ 18 __('Editing', 'advanced-settings'), 19 __('Posts', 'advanced-settings'), 20 __('Performance', 'advanced-settings'), 21 __('Database', 'advanced-settings'), 22 __('Admin', 'advanced-settings'), 23 ], 24 'fields' => [ 25 'enable' => [ 26 'type' => 'toggle', 27 'label' => __('Disable auto save', 'advanced-settings'), 28 ], 29 ] 30 ], 31 'execution_handler' => function() { 32 define('AUTOSAVE_INTERVAL', 60 * 60 * 24 * 365 * 100); // save interval => 100 years 33 }, 34 'priority' => 10, 35 ]); 36 37 38 39 advset_register_feature([ 40 'id' => 'editing.posts.limit_revisions', 41 'category' => 'editing', 42 'ui_config' => fn() => [ 43 'tags' => [ 44 __('Editing', 'advanced-settings'), 45 __('Posts', 'advanced-settings'), 46 __('Performance', 'advanced-settings'), 47 __('Database', 'advanced-settings'), 48 __('Admin', 'advanced-settings'), 49 ], 50 'fields' => [ 51 'enable' => [ 52 'type' => 'toggle', 53 'label' => __('Limit post revisions', 'advanced-settings'), 54 'description' => __('Reduce database size by limiting the number of saved revisions', 'advanced-settings'), 55 ], 56 'limit' => [ 57 'type' => 'number', 58 'label' => __('Revisions to keep', 'advanced-settings'), 59 'description' => __('0 means revisions are disabled.', 'advanced-settings'), 60 'min' => 0, 61 'default' => 5, 62 'visible' => ['enable' => true], 63 ], 64 'type' => [ 65 'type' => 'radio', 66 'label' => __('Post types', 'advanced-settings'), 67 'description' => __('Select the post types that should be affected by the revision limit.', 'advanced-settings'), 68 'options' => [ 69 'post' => ['label' => 'Posts only'], 70 'page' => ['label' => 'Pages only'], 71 'post_and_page' => ['label' => 'Posts and Pages'], 72 'all' => ['label' => 'All post types (includes custom post types)'], 73 ], 74 'default' => 'post', 75 'visible' => ['enable' => true], 76 ], 77 ] 78 ], 79 'handler_cleanup' => function($settings) { 80 return empty($settings['enable']) ? null : $settings; 81 }, 82 'execution_handler' => function($settings) { 83 if ($settings['type'] === 'all') { 84 add_filter('wp_revisions_to_keep', function($num) use($settings) { 85 return $settings['limit']; 86 }); 87 return; 88 } 89 foreach (explode('_and_', $settings['type']) as $type) { 90 add_filter('wp_' . $type . '_revisions_to_keep', function($num) use($settings) { 91 return $settings['limit']; 92 }); 93 } 94 }, 95 'priority' => 20, 96 ]); 97 98 99 100 advset_register_feature([ 101 'id' => 'editing.media.enable_svg', 102 'category' => 'editing', 103 'ui_config' => fn() => [ 104 'tags' => [ 105 __('Editing', 'advanced-settings'), 106 __('Media', 'advanced-settings'), 107 __('Images', 'advanced-settings'), 108 __('Frontend', 'advanced-settings'), 109 __('Performance', 'advanced-settings'), 110 ], 111 'fields' => [ 112 'enable' => [ 113 'type' => 'toggle', 114 'label' => __('Allow SVG upload for admins', 'advanced-settings'), 115 'description' => __('To keep the plugin lightweight, the SVG security checks in this feature are very limited. Therefore, this feature is only available to administrators.', 'advanced-settings'), 116 ], 117 ] 118 ], 119 'execution_handler' => function() { 120 if (!current_user_can('administrator')) { 121 return; 122 } 123 124 add_filter('upload_mimes', function($mimes) { 125 $mimes['svg'] = 'image/svg+xml'; 126 $mimes['svgz'] = 'image/svg+xml'; 127 return $mimes; 128 }); 129 130 add_filter('wp_handle_upload_prefilter', function($file) { 131 if ($file['type'] !== 'image/svg+xml') { 132 return $file; 133 } 134 135 $file_content = file_get_contents($file['tmp_name']); 136 137 // 1. Check if the file is empty 138 if (empty($file_content)) { 139 $file['error'] = __('Empty SVG file', 'advanced-settings'); 140 return $file; 141 } 142 143 // 2. Remove XML declaration and Doctype for better compatibility 144 $clean_content = preg_replace('/<\?xml\b[^>]*>\s*/i', '', $file_content); 145 $clean_content = preg_replace('/<!DOCTYPE[^>[]*(\[[^]]*\])?[^>]*>\s*/is', '', $clean_content); 146 147 // 3. XXE-Protection (critical!) 148 $entity_loader_state = libxml_disable_entity_loader(true); 149 libxml_use_internal_errors(true); 150 libxml_clear_errors(); 151 152 $svg = @simplexml_load_string($clean_content); 153 154 if ($svg === false) { 155 $errors = libxml_get_errors(); 156 $first_error = !empty($errors[0]) ? $errors[0]->message : __('Unknown error', 'advanced-settings'); 157 libxml_clear_errors(); 158 /* translators: %s is the first error message from libxml */ 159 $file['error'] = sprintf(__('Invalid SVG: %s', 'advanced-settings'), esc_html($first_error)); 160 return $file; 161 } 162 163 // 4. Simple, but effective security checks 164 $unsafe_patterns = [ 165 '/<script/i', 166 '/\bon\w+\s*=/i', 167 '/javascript:\s*[a-z]+/i', 168 '/<!ENTITY/i', 169 '/<object/i', 170 '/<iframe/i', 171 '/<embed/i', 172 '/href\s*=\s*["\']\s*javascript:/i', 173 '/xlink:href\s*=\s*["\']\s*javascript:/i', 174 '/style\s*=\s*["\'][^"]*expression\s*\(/i', 175 '/style\s*=\s*["\'][^"]*url\s*\(\s*javascript:/i', 176 '/<!--\[if[^\]]*?\]>.*?<!\[endif\]-->/is', 177 ]; 178 179 foreach ($unsafe_patterns as $pattern) { 180 if (preg_match($pattern, $file_content)) { 181 $file['error'] = __('SVG security check failed: Potential dangerous element detected.', 'advanced-settings') . ' ' . $pattern; 182 return $file; 183 } 184 } 185 186 // 5. Additional protection against Base64-Encoded malicious code 187 if (preg_match('/base64\s*[,;]/i', $file_content)) { 188 $file['error'] = __('SVG security check failed: Base64 encoding not allowed.', 'advanced-settings'); 189 return $file; 190 } 191 192 // Reset libxml state 193 libxml_disable_entity_loader($entity_loader_state); 194 libxml_clear_errors(); 195 196 return $file; 197 }); 198 }, 199 'priority' => 30, 200 ]); 201 202 203 204 advset_register_feature([ 205 'id' => 'editing.image.downsize_on_upload', 206 'category' => 'editing', 207 'ui_config' => fn() => [ 208 'tags' => [ 209 __('Editing', 'advanced-settings'), 210 __('Media', 'advanced-settings'), 211 __('Images', 'advanced-settings'), 212 __('Frontend', 'advanced-settings'), 213 __('Performance', 'advanced-settings'), 214 ], 215 'fields' => [ 216 'enable' => [ 217 'type' => 'toggle', 218 'label' => __('Downsize images on upload', 'advanced-settings'), 219 ], 220 'max_width' => [ 221 'type' => 'number', 222 'label' => __('Max width', 'advanced-settings'), 223 'description' => __('Empty or 0 means no limit.', 'advanced-settings'), 224 'min' => 0, 225 'visible' => ['enable' => true], 226 ], 227 'max_height' => [ 228 'type' => 'number', 229 'label' => __('Max height', 'advanced-settings'), 230 'description' => __('Empty or 0 means no limit.', 'advanced-settings'), 231 'min' => 0, 232 'visible' => ['enable' => true], 233 ], 234 ] 235 ], 236 'handler_cleanup' => function($settings) { 237 return empty($settings['enable']) ? null : $settings; 238 }, 239 'execution_handler' => function($settings) { 240 add_action('wp_handle_upload', function($upload) use($settings) { 241 $file_path = $upload['file']; 242 $image_info = getimagesize($file_path); 243 244 if (!$image_info) return $upload; 245 246 list($width, $height, $type) = $image_info; 247 248 $max_width = ((int) $settings['max_width']) ?? null; 249 $max_height = ((int) $settings['max_height']) ?? null; 250 251 if (($max_width === null || $width <= $max_width) && ($max_height === null || $height <= $max_height)) { 252 return $upload; // nothig to do 253 } 254 255 $editor = wp_get_image_editor($file_path); 256 if (is_wp_error($editor)) return $upload; 257 258 $editor->resize($max_width, $max_height, false); 259 $editor->save($file_path); // overwrites original 260 261 return $upload; 262 }); 263 }, 264 'priority' => 40, 265 ]); 266 267 268 269 advset_register_feature([ 14 270 'id' => 'editing.image.jpeg_quality', 15 271 'category' => 'editing', 16 272 'ui_config' => fn() => [ 273 'tags' => [ 274 __('Editing', 'advanced-settings'), 275 __('Media', 'advanced-settings'), 276 __('Images', 'advanced-settings'), 277 __('Frontend', 'advanced-settings'), 278 __('Performance', 'advanced-settings'), 279 ], 17 280 'fields' => [ 18 281 'jpeg_quality' => [ … … 33 296 }); 34 297 }, 35 'priority' => 20, 36 ]); 37 38 39 40 advset_register_feature([ 41 'id' => 'editing.image.downsize_on_upload', 42 'category' => 'editing', 43 'ui_config' => fn() => [ 44 'fields' => [ 45 'enable' => [ 46 'type' => 'toggle', 47 'label' => __('Downsize images on upload', 'advanced-settings'), 48 ], 49 'max_width' => [ 50 'type' => 'number', 51 'label' => __('Max width', 'advanced-settings'), 52 'description' => __('Empty or 0 means no limit.', 'advanced-settings'), 53 'min' => 0, 54 'visible' => ['enable' => true], 55 ], 56 'max_height' => [ 57 'type' => 'number', 58 'label' => __('Max height', 'advanced-settings'), 59 'description' => __('Empty or 0 means no limit.', 'advanced-settings'), 60 'min' => 0, 61 'visible' => ['enable' => true], 62 ], 63 ] 64 ], 65 'handler_cleanup' => function($settings) { 66 return empty($settings['enable']) ? null : $settings; 67 }, 68 'execution_handler' => function($settings) { 69 add_action('wp_handle_upload', function($upload) use($settings) { 70 $file_path = $upload['file']; 71 $image_info = getimagesize($file_path); 72 73 if (!$image_info) return $upload; 74 75 list($width, $height, $type) = $image_info; 76 77 $max_width = ((int) $settings['max_width']) ?? null; 78 $max_height = ((int) $settings['max_height']) ?? null; 79 80 if (($max_width === null || $width <= $max_width) && ($max_height === null || $height <= $max_height)) { 81 return $upload; // nothig to do 82 } 83 84 $editor = wp_get_image_editor($file_path); 85 if (is_wp_error($editor)) return $upload; 86 87 $editor->resize($max_width, $max_height, false); 88 $editor->save($file_path); // overwrites original 89 90 return $upload; 91 }); 92 }, 93 'priority' => 20, 94 ]); 95 96 298 'priority' => 50, 299 ]); 300 301 302 303 advset_register_feature([ 304 'id' => 'editing.thumbnails.enable_support', 305 'category' => 'editing', 306 'ui_config' => fn() => [ 307 'tags' => [ 308 __('Editing', 'advanced-settings'), 309 __('Frontend', 'advanced-settings'), 310 __('Content', 'advanced-settings'), 311 __('Images', 'advanced-settings'), 312 __('Media', 'advanced-settings'), 313 ], 314 'fields' => [ 315 'enable' => [ 316 'type' => 'toggle', 317 'label' => __('Add thumbnail support', 'advanced-settings'), 318 'disabled' => !ADVSET_THUMBS, 319 'description' => ADVSET_THUMBS 320 ? '' 321 : __('Already supported by current theme', 'advanced-settings'), 322 ], 323 ] 324 ], 325 'execution_handler' => function() { 326 add_action('after_setup_theme', function (){ 327 add_theme_support( 'post-thumbnails' ); 328 }); 329 }, 330 'priority' => 60, 331 ]); 332 define( 'ADVSET_THUMBS', !current_theme_supports('post-thumbnails') ); 333 334 335 336 advset_register_feature([ 337 'id' => 'editing.thumbnails.auto_from_first_image', 338 'category' => 'editing', 339 'ui_config' => fn() => [ 340 'tags' => [ 341 __('Editing', 'advanced-settings'), 342 __('Frontend', 'advanced-settings'), 343 __('Content', 'advanced-settings'), 344 __('Images', 'advanced-settings'), 345 __('Media', 'advanced-settings'), 346 __('Automations', 'advanced-settings'), 347 ], 348 'fields' => [ 349 'enable' => [ 350 'type' => 'toggle', 351 'label' => __('Automatically generate the Post Thumbnail', 'advanced-settings'), 352 'description' => __('from the first image in post', 'advanced-settings'), 353 ], 354 ] 355 ], 356 'execution_handler' => function() { 357 require_once ADVSET_DIR . '/feature-setup/features/includes/frontend.auto_thumbs.php'; 358 add_action('transition_post_status', 'advset__feature__auto_thumbs', 10, 3); 359 }, 360 'priority' => 70, 361 ]); 362 363 -
advanced-settings/tags/3.1.0/feature-setup/features/frontend.php
r3281733 r3323103 12 12 13 13 advset_register_feature([ 14 'id' => 'frontend.meta.facebook_og_metas', 15 'category' => 'frontend', 16 'ui_config' => fn() => [ 17 'fields' => [ 18 'enable' => [ 19 'type' => 'toggle', 20 'label' => __('Enable Facebook Open Graph Meta Tags', 'advanced-settings'), 14 'id' => 'frontend.http_headers.remove_php_version', 15 'category' => 'frontend', 16 'ui_config' => fn() => [ 17 'tags' => [ 18 __('Frontend', 'advanced-settings'), 19 __('HTTP', 'advanced-settings'), 20 __('Security', 'advanced-settings'), 21 __('Cleanup', 'advanced-settings'), 22 ], 23 'fields' => [ 24 'enable' => [ 25 'type' => 'toggle', 26 'label' => __('Remove PHP version from HTTP headers', 'advanced-settings'), 27 'description' => __('Removes the PHP version from the HTTP headers of the website', 'advanced-settings'), 28 ], 29 ] 30 ], 31 'execution_handler' => function() { 32 header_remove('X-Powered-By'); 33 }, 34 'priority' => 10, 35 ]); 36 37 38 39 advset_register_feature([ 40 'id' => 'frontend.http_headers.add_security_headers', 41 'category' => 'frontend', 42 'ui_config' => fn() => [ 43 'tags' => [ 44 __('Frontend', 'advanced-settings'), 45 __('HTTP', 'advanced-settings'), 46 __('Security', 'advanced-settings'), 47 ], 48 'fields' => [ 49 'enable' => [ 50 'type' => 'toggle', 51 'label' => __('Add security headers', 'advanced-settings'), 52 /* translators: %s is a link to securityheaders.com */ 53 'descriptionHtml' => sprintf(__('Adds various security headers to HTTP responses. You can check your website\'s security headers with %s.', 'advanced-settings'), '<a href="https://securityheaders.com/?q=' . rawurlencode(get_home_url()) . '&hide=on&followRedirects=on" target="_blank">securityheaders.com</a>'), 54 ], 55 'info' => [ 56 'type' => 'info', 57 'label' => __('Caution:', 'advanced-settings'), 58 'description' => __('If you integrate external services into your website or your website requires access to browser features like camera, microphone, geolocation, or other device sensors, the security headers may be set too strictly. In this case, simply disable this feature. You can implement customized headers via code if necessary.', 'advanced-settings'), 59 'visible' => ['enable' => true] 21 60 ], 22 61 ] … … 24 63 'execution_handler' => function() { 25 64 if ( advset_is_admin_area() ) return; 26 27 add_action('wp_head', function() { 28 global $post; 29 if (is_single() || is_page()) { ?> 30 <meta property="og:title" content="<?php single_post_title(''); ?>" /> 31 <meta property="og:description" content="<?php echo strip_tags(get_the_excerpt($post->ID)); ?>" /> 32 <meta property="og:type" content="article" /> 33 <meta property="og:image" content="<?php if (function_exists('wp_get_attachment_thumb_url')) {echo wp_get_attachment_url(get_post_thumbnail_id($post->ID)); }?>" /> 34 <?php } 35 }); 36 }, 37 'priority' => 10, 65 add_action('send_headers', function() { 66 header('X-Content-Type-Options: nosniff'); 67 header('X-Frame-Options: SAMEORIGIN'); 68 header('X-XSS-Protection: 1; mode=block'); 69 header('Referrer-Policy: strict-origin-when-cross-origin'); 70 header('Content-Security-Policy: object-src \'none\';'); 71 header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload'); 72 header('Permissions-Policy: accelerometer=(),camera=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),payment=(),usb=(),interest-cohort=()'); 73 }); 74 }, 75 'priority' => 20, 38 76 ]); 39 77 … … 44 82 'category' => 'frontend', 45 83 'ui_config' => fn() => [ 84 'tags' => [ 85 __('Frontend', 'advanced-settings'), 86 __('Meta', 'advanced-settings'), 87 __('Favicon', 'advanced-settings'), 88 __('SEO', 'advanced-settings'), 89 ], 46 90 'fields' => [ 47 91 'enable' => [ … … 66 110 }); 67 111 }, 68 'priority' => 10, 112 'priority' => 30, 113 ]); 114 115 116 117 advset_register_feature([ 118 'id' => 'frontend.meta.facebook_og_metas', 119 'category' => 'frontend', 120 'ui_config' => fn() => [ 121 'tags' => [ 122 __('Frontend', 'advanced-settings'), 123 __('Meta', 'advanced-settings'), 124 __('SEO', 'advanced-settings'), 125 ], 126 'fields' => [ 127 'enable' => [ 128 'type' => 'toggle', 129 'label' => __('Enable Facebook Open Graph Meta Tags', 'advanced-settings'), 130 ], 131 ] 132 ], 133 'execution_handler' => function() { 134 if ( advset_is_admin_area() ) return; 135 136 add_action('wp_head', function() { 137 global $post; 138 if (is_single() || is_page()) { ?> 139 <meta property="og:title" content="<?php single_post_title(''); ?>" /> 140 <meta property="og:description" content="<?php echo strip_tags(get_the_excerpt($post->ID)); ?>" /> 141 <meta property="og:type" content="article" /> 142 <meta property="og:image" content="<?php if (function_exists('wp_get_attachment_thumb_url')) {echo wp_get_attachment_url(get_post_thumbnail_id($post->ID)); }?>" /> 143 <?php } 144 }); 145 }, 146 'priority' => 40, 69 147 ]); 70 148 … … 75 153 'category' => 'frontend', 76 154 'ui_config' => fn() => [ 155 'tags' => [ 156 __('Frontend', 'advanced-settings'), 157 __('Meta', 'advanced-settings'), 158 __('Cleanup', 'advanced-settings'), 159 ], 77 160 'fields' => [ 78 161 'enable' => [ … … 86 169 remove_action( 'wp_head', 'wp_shortlink_wp_head'); 87 170 }, 88 'priority' => 10,171 'priority' => 50, 89 172 ]); 90 173 … … 95 178 'category' => 'frontend', 96 179 'ui_config' => fn() => [ 180 'tags' => [ 181 __('Frontend', 'advanced-settings'), 182 __('Meta', 'advanced-settings'), 183 __('Cleanup', 'advanced-settings'), 184 ], 97 185 'fields' => [ 98 186 'enable' => [ … … 107 195 remove_action( 'wp_head', 'rsd_link'); 108 196 }, 109 'priority' => 10,197 'priority' => 60, 110 198 ]); 111 199 … … 116 204 'category' => 'frontend', 117 205 'ui_config' => fn() => [ 206 'tags' => [ 207 __('Frontend', 'advanced-settings'), 208 __('Meta', 'advanced-settings'), 209 __('Security', 'advanced-settings'), 210 __('Cleanup', 'advanced-settings'), 211 ], 118 212 'fields' => [ 119 213 'enable' => [ 120 214 'type' => 'toggle', 121 215 'label' => __('Remove generator meta tag', 'advanced-settings'), 216 'description' => __('Removes the WordPress version from the head section of the website', 'advanced-settings'), 122 217 ], 123 218 ] … … 127 222 remove_action( 'wp_head', 'wp_generator'); 128 223 }, 129 'priority' => 10,224 'priority' => 70, 130 225 ]); 131 226 … … 136 231 'category' => 'frontend', 137 232 'ui_config' => fn() => [ 233 'tags' => [ 234 __('Frontend', 'advanced-settings'), 235 __('Meta', 'advanced-settings'), 236 __('SEO', 'advanced-settings'), 237 ], 138 238 'fields' => [ 139 239 'enable' => [ … … 178 278 }); 179 279 }, 180 'priority' => 10,280 'priority' => 80, 181 281 ]); 182 282 … … 187 287 'category' => 'frontend', 188 288 'ui_config' => fn() => [ 289 'tags' => [ 290 __('Frontend', 'advanced-settings'), 291 __('Content', 'advanced-settings'), 292 __('Security', 'advanced-settings'), 293 __('Cleanup', 'advanced-settings'), 294 ], 189 295 'fields' => [ 190 296 'enable' => [ … … 210 316 }, 10, 2 ); 211 317 }, 212 'priority' => 20, 318 'priority' => 90, 319 ]); 320 321 322 323 advset_register_feature([ 324 'id' => 'frontend.title.improve_format', 325 'category' => 'frontend', 326 'deprecated' => true, 327 'ui_config' => fn() => [ 328 'tags' => [ 329 __('Developer', 'advanced-settings'), 330 __('Frontend', 'advanced-settings'), 331 __('Content', 'advanced-settings'), 332 __('Automations', 'advanced-settings'), 333 ], 334 'fields' => [ 335 'enable' => [ 336 'type' => 'toggle', 337 'label' => __('Adjust the wp_title function', 'advanced-settings'), 338 ], 339 ] 340 ], 341 'execution_handler' => function() { 342 add_filter('wp_title', function($title, $sep) { 343 global $paged, $page; 344 345 if ( is_feed() ) 346 return $title; 347 348 // Add the site name. 349 $title .= get_bloginfo( 'name' ); 350 351 // Add the site description for the home/front page. 352 $site_description = get_bloginfo( 'description', 'display' ); 353 if ( $site_description && ( is_home() || is_front_page() ) ) 354 $title = "$title $sep $site_description"; 355 356 // Add a page number if necessary. 357 if ( $paged >= 2 || $page >= 2 ) 358 $title = "$title $sep " . sprintf( __( 'Page %s', 'responsive' ), max( $paged, $page ) ); 359 360 return $title; 361 }, 10, 2); 362 }, 363 'priority' => 100, 213 364 ]); 214 365 … … 219 370 'category' => 'frontend', 220 371 'ui_config' => fn() => [ 372 'tags' => [ 373 __('Editing', 'advanced-settings'), 374 __('Frontend', 'advanced-settings'), 375 __('Content', 'advanced-settings'), 376 __('Cleanup', 'advanced-settings'), 377 __('Automations', 'advanced-settings'), 378 ], 221 379 'fields' => [ 222 380 'enable' => [ … … 230 388 add_filter( 'run_wptexturize', '__return_false' ); 231 389 }, 232 'priority' => 10, 233 ]); 234 235 236 237 advset_register_feature([ 238 'id' => 'frontend.thumbnails.enable_support', 239 'category' => 'frontend', 240 'ui_config' => fn() => [ 241 'fields' => [ 242 'enable' => [ 243 'type' => 'toggle', 244 'label' => __('Add thumbnail support', 'advanced-settings'), 245 'disabled' => !ADVSET_THUMBS, 246 'description' => ADVSET_THUMBS 247 ? '' 248 : __('Already supported by current theme', 'advanced-settings'), 249 ], 250 ] 251 ], 252 'execution_handler' => function() { 253 add_action('after_setup_theme', function (){ 254 add_theme_support( 'post-thumbnails' ); 255 }); 256 }, 257 'priority' => 30, 258 ]); 259 define( 'ADVSET_THUMBS', !current_theme_supports('post-thumbnails') ); 260 261 262 263 advset_register_feature([ 264 'id' => 'frontend.thumbnails.auto_from_first_image', 265 'category' => 'frontend', 266 'ui_config' => fn() => [ 267 'fields' => [ 268 'enable' => [ 269 'type' => 'toggle', 270 'label' => __('Automatically generate the Post Thumbnail', 'advanced-settings'), 271 'description' => __('from the first image in post', 'advanced-settings'), 272 ], 273 ] 274 ], 275 'execution_handler' => function() { 276 require_once ADVSET_DIR . '/feature-setup/features/includes/frontend.auto_thumbs.php'; 277 add_action('transition_post_status', 'advset__feature__auto_thumbs', 10, 3); 278 }, 390 'priority' => 110, 391 ]); 392 393 394 395 advset_register_feature([ 396 'id' => 'frontend.oembed.disable', 397 'category' => 'frontend', 398 'ui_config' => fn() => [ 399 'tags' => [ 400 __('Editing', 'advanced-settings'), 401 __('Frontend', 'advanced-settings'), 402 __('Content', 'advanced-settings'), 403 __('Security', 'advanced-settings'), 404 __('Cleanup', 'advanced-settings'), 405 __('GDPR', 'advanced-settings'), 406 __('Performance', 'advanced-settings'), 407 __('Automations', 'advanced-settings'), 408 ], 409 'fields' => [ 410 'enable' => [ 411 'type' => 'toggle', 412 'label' => __('Disable auto-embed of external content', 'advanced-settings'), 413 'description' => __('Disables WordPress oEmbed, which automatically converts URLs into embedded content.', 'advanced-settings'), 414 ], 415 ] 416 ], 417 'execution_handler' => function() { 418 remove_action('wp_head', 'wp_oembed_add_discovery_links'); 419 remove_action('wp_head', 'wp_oembed_add_host_js'); 420 remove_action('wp_head', 'rest_output_link_wp_head'); 421 remove_action('rest_api_init', 'wp_oembed_register_route'); 422 remove_filter('the_content', [$GLOBALS['wp_embed'], 'autoembed'], 8); 423 remove_filter('oembed_dataparse', 'wp_filter_oembed_result', 10); 424 add_filter('embed_oembed_discover', '__return_false'); 425 }, 426 'priority' => 120, 279 427 ]); 280 428 … … 285 433 'category' => 'frontend', 286 434 'ui_config' => fn() => [ 435 'tags' => [ 436 __('Editing', 'advanced-settings'), 437 __('Frontend', 'advanced-settings'), 438 __('Content', 'advanced-settings'), 439 __('Cleanup', 'advanced-settings'), 440 __('Automations', 'advanced-settings'), 441 ], 287 442 'fields' => [ 288 443 'enable' => [ … … 308 463 }); 309 464 }, 465 'priority' => 130, 310 466 ]); 311 467 … … 316 472 'category' => 'frontend', 317 473 'ui_config' => fn() => [ 474 'tags' => [ 475 __('Frontend', 'advanced-settings'), 476 __('Content', 'advanced-settings'), 477 __('SEO', 'advanced-settings'), 478 __('Cleanup', 'advanced-settings'), 479 __('Automations', 'advanced-settings'), 480 ], 318 481 'fields' => [ 319 482 'enable' => [ … … 339 502 }); 340 503 }, 504 'priority' => 140, 341 505 ]); 342 506 … … 347 511 'category' => 'frontend', 348 512 'ui_config' => fn() => [ 513 'tags' => [ 514 __('Frontend', 'advanced-settings'), 515 __('Content', 'advanced-settings'), 516 __('Comments', 'advanced-settings'), 517 __('Automations', 'advanced-settings'), 518 __('Cleanup', 'advanced-settings'), 519 ], 349 520 'fields' => [ 350 521 'enable' => [ … … 367 538 }, 10); 368 539 }, 369 'priority' => 40, 540 'priority' => 150, 541 ]); 542 543 544 545 advset_register_feature([ 546 'id' => 'frontend.post.show_author_bio', 547 'category' => 'frontend', 548 'deprecated' => true, 549 'ui_config' => fn() => [ 550 'tags' => [ 551 __('Frontend', 'advanced-settings'), 552 __('Content', 'advanced-settings'), 553 __('Automations', 'advanced-settings'), 554 ], 555 'fields' => [ 556 'enable' => [ 557 'type' => 'toggle', 558 'label' => __('Insert author bio in each post', 'advanced-settings'), 559 ], 560 ] 561 ], 562 'execution_handler' => function() { 563 add_filter('the_content', function($content='') { 564 return $content.' <div id="entry-author-info"> 565 <div id="author-avatar"> 566 '. get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'author_bio_avatar_size', 100 ) ) .' 567 </div> 568 <div id="author-description"> 569 <h2>'. sprintf( __( 'About %s' ), get_the_author() ) .'</h2> 570 '. get_the_author_meta( 'description' ) .' 571 <div id="author-link"> 572 <a href="'. get_author_posts_url( get_the_author_meta( 'ID' ) ) .'"> 573 '. sprintf( __( 'View all posts by %s <span class="meta-nav">→</span>' ), get_the_author() ) .' 574 </a> 575 </div> 576 </div> 577 </div>'; 578 }); 579 }, 580 'priority' => 160, 581 ]); 582 583 584 585 advset_register_feature([ 586 'id' => 'frontend.user.allow_html_bio', 587 'category' => 'frontend', 588 'deprecated' => true, 589 'ui_config' => fn() => [ 590 'tags' => [ 591 __('Admin', 'advanced-settings'), 592 __('Frontend', 'advanced-settings'), 593 __('Content', 'advanced-settings'), 594 ], 595 'fields' => [ 596 'enable' => [ 597 'type' => 'toggle', 598 'label' => __('Allow complex HTML in user profile description', 'advanced-settings'), 599 ], 600 ] 601 ], 602 'execution_handler' => function() { 603 remove_filter('pre_user_description', 'wp_filter_kses'); 604 }, 605 'priority' => 170, 370 606 ]); 371 607 … … 376 612 'category' => 'frontend', 377 613 'ui_config' => fn() => [ 614 'tags' => [ 615 __('Frontend', 'advanced-settings'), 616 __('Content', 'advanced-settings'), 617 __('Security', 'advanced-settings'), 618 __('Automations', 'advanced-settings'), 619 ], 378 620 'fields' => [ 379 621 'enable' => [ … … 480 722 }); 481 723 }, 482 'priority' => 1 0,483 ]); 484 485 486 487 advset_register_feature([ 488 'id' => 'frontend. title.improve_format',724 'priority' => 180, 725 ]); 726 727 728 729 advset_register_feature([ 730 'id' => 'frontend.analytics.google', 489 731 'category' => 'frontend', 490 732 'deprecated' => true, 491 733 'ui_config' => fn() => [ 492 'fields' => [ 493 'enable' => [ 494 'type' => 'toggle', 495 'label' => __('Adjust the wp_title function', 'advanced-settings'), 496 ], 497 ] 498 ], 499 'execution_handler' => function() { 500 add_filter('wp_title', function($title, $sep) { 501 global $paged, $page; 502 503 if ( is_feed() ) 504 return $title; 505 506 // Add the site name. 507 $title .= get_bloginfo( 'name' ); 508 509 // Add the site description for the home/front page. 510 $site_description = get_bloginfo( 'description', 'display' ); 511 if ( $site_description && ( is_home() || is_front_page() ) ) 512 $title = "$title $sep $site_description"; 513 514 // Add a page number if necessary. 515 if ( $paged >= 2 || $page >= 2 ) 516 $title = "$title $sep " . sprintf( __( 'Page %s', 'responsive' ), max( $paged, $page ) ); 517 518 return $title; 519 }, 10, 2); 520 }, 521 'priority' => 10, 522 ]); 523 524 525 526 advset_register_feature([ 527 'id' => 'frontend.post.show_author_bio', 528 'category' => 'frontend', 529 'deprecated' => true, 530 'ui_config' => fn() => [ 531 'fields' => [ 532 'enable' => [ 533 'type' => 'toggle', 534 'label' => __('Insert author bio in each post', 'advanced-settings'), 535 ], 536 ] 537 ], 538 'execution_handler' => function() { 539 add_filter('the_content', function($content='') { 540 return $content.' <div id="entry-author-info"> 541 <div id="author-avatar"> 542 '. get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'author_bio_avatar_size', 100 ) ) .' 543 </div> 544 <div id="author-description"> 545 <h2>'. sprintf( __( 'About %s' ), get_the_author() ) .'</h2> 546 '. get_the_author_meta( 'description' ) .' 547 <div id="author-link"> 548 <a href="'. get_author_posts_url( get_the_author_meta( 'ID' ) ) .'"> 549 '. sprintf( __( 'View all posts by %s <span class="meta-nav">→</span>' ), get_the_author() ) .' 550 </a> 551 </div> 552 </div> 553 </div>'; 554 }); 555 }, 556 'priority' => 10, 557 ]); 558 559 560 561 advset_register_feature([ 562 'id' => 'frontend.user.allow_html_bio', 563 'category' => 'frontend', 564 'deprecated' => true, 565 'ui_config' => fn() => [ 566 'fields' => [ 567 'enable' => [ 568 'type' => 'toggle', 569 'label' => __('Allow complex HTML in user profile description', 'advanced-settings'), 570 ], 571 ] 572 ], 573 'execution_handler' => function() { 574 remove_filter('pre_user_description', 'wp_filter_kses'); 575 }, 576 'priority' => 10, 577 ]); 578 579 580 581 advset_register_feature([ 582 'id' => 'frontend.analytics.google', 583 'category' => 'frontend', 584 'deprecated' => true, 585 'ui_config' => fn() => [ 734 'tags' => [ 735 __('Frontend', 'advanced-settings'), 736 __('Meta', 'advanced-settings'), 737 __('GDPR', 'advanced-settings'), 738 ], 586 739 'fields' => [ 587 740 'enable' => [ … … 614 767 }); 615 768 }, 616 'priority' => 1 0,769 'priority' => 190, 617 770 ]); 618 771 … … 624 777 'deprecated' => true, 625 778 'ui_config' => fn() => [ 779 'tags' => [ 780 __('Frontend', 'advanced-settings'), 781 __('Meta', 'advanced-settings'), 782 ], 626 783 'fields' => [ 627 784 'enable' => [ … … 655 812 }, 10, 2 ); 656 813 }, 657 'priority' => 10,814 'priority' => 200, 658 815 ]); 659 816 … … 664 821 'category' => 'frontend', 665 822 'ui_config' => fn() => [ 823 'tags' => [ 824 __('Frontend', 'advanced-settings'), 825 __('HTML', 'advanced-settings'), 826 __('Performance', 'advanced-settings'), 827 __('Automations', 'advanced-settings'), 828 ], 666 829 'fields' => [ 667 830 'enable' => [ … … 678 841 }); 679 842 }, 680 'priority' => 10,843 'priority' => 210, 681 844 ]); 682 845 … … 687 850 'category' => 'frontend', 688 851 'ui_config' => fn() => [ 852 'tags' => [ 853 __('Frontend', 'advanced-settings'), 854 __('HTML', 'advanced-settings'), 855 __('Performance', 'advanced-settings'), 856 __('Cleanup', 'advanced-settings'), 857 __('Automations', 'advanced-settings'), 858 ], 689 859 'fields' => [ 690 860 'enable' => [ … … 701 871 }); 702 872 }, 703 'priority' => 10,873 'priority' => 220, 704 874 ]); 705 875 … … 710 880 'category' => 'frontend', 711 881 'ui_config' => fn() => [ 882 'tags' => [ 883 __('Frontend', 'advanced-settings'), 884 __('Content', 'advanced-settings'), 885 __('Emojis', 'advanced-settings'), 886 __('Automations', 'advanced-settings'), 887 __('Cleanup', 'advanced-settings'), 888 __('GDPR', 'advanced-settings'), 889 ], 712 890 'fields' => [ 713 891 'enable' => [ … … 728 906 add_filter('emoji_svg_url', '__return_false'); 729 907 }, 730 'priority' => 10,731 ]); 732 733 908 'priority' => 230, 909 ]); 910 911 -
advanced-settings/tags/3.1.0/feature-setup/features/system.php
r3306579 r3323103 15 15 'category' => 'system', 16 16 'ui_config' => fn() => [ 17 'tags' => [ 18 __('Admin', 'advanced-settings'), 19 __('Frontend', 'advanced-settings'), 20 __('Meta', 'advanced-settings'), 21 __('Favicon', 'advanced-settings'), 22 __('Cleanup', 'advanced-settings'), 23 __('Branding', 'advanced-settings'), 24 ], 17 25 'fields' => [ 18 26 'enable' => [ … … 40 48 'category' => 'system', 41 49 'ui_config' => fn() => [ 50 'tags' => [ 51 __('System', 'advanced-settings'), 52 __('Admin', 'advanced-settings'), 53 __('Frontend', 'advanced-settings'), 54 __('Cleanup', 'advanced-settings'), 55 __('Security', 'advanced-settings'), 56 __('Comments', 'advanced-settings'), 57 ], 42 58 'fields' => [ 43 59 'enable' => [ … … 60 76 } ); 61 77 }, 62 'priority' => 10,63 ]);64 65 66 67 advset_register_feature([68 'id' => 'system.posts.disable_autosave',69 'category' => 'system',70 'ui_config' => fn() => [71 'fields' => [72 'enable' => [73 'type' => 'toggle',74 'label' => __('Disable auto save', 'advanced-settings'),75 ],76 ]77 ],78 'execution_handler' => function() {79 define('AUTOSAVE_INTERVAL', 60 * 60 * 24 * 365 * 100); // save interval => 100 years80 },81 78 'priority' => 20, 82 79 ]); … … 85 82 86 83 advset_register_feature([ 84 'id' => 'system.xmlrpc.disable', 85 'category' => 'system', 86 'ui_config' => fn() => [ 87 'tags' => [ 88 __('System', 'advanced-settings'), 89 __('Security', 'advanced-settings'), 90 __('Performance', 'advanced-settings'), 91 __('Cleanup', 'advanced-settings'), 92 ], 93 'fields' => [ 94 'enable' => [ 95 'type' => 'toggle', 96 'label' => __('Disable XML-RPC', 'advanced-settings'), 97 'description' => __('Disables XML-RPC functionality for security', 'advanced-settings'), 98 ], 99 ] 100 ], 101 'execution_handler' => function() { 102 add_filter('xmlrpc_enabled', '__return_false'); 103 }, 104 'priority' => 30, 105 ]); 106 107 108 109 advset_register_feature([ 110 'id' => 'system.rest.disable_public', 111 'category' => 'system', 112 'ui_config' => fn() => [ 113 'tags' => [ 114 __('System', 'advanced-settings'), 115 __('Security', 'advanced-settings'), 116 __('Performance', 'advanced-settings'), 117 __('Cleanup', 'advanced-settings'), 118 ], 119 'fields' => [ 120 'enable' => [ 121 'type' => 'toggle', 122 'label' => __('Disable public REST API', 'advanced-settings'), 123 'description' => __('Disables REST API access for non-authenticated users', 'advanced-settings'), 124 ], 125 ] 126 ], 127 'execution_handler' => function() { 128 add_filter('rest_authentication_errors', function($result) { 129 if (!empty($result)) { 130 return $result; 131 } 132 if (!is_user_logged_in()) { 133 return new WP_Error('rest_forbidden', 'REST API restricted to authenticated users.', ['status' => 401]); 134 } 135 return $result; 136 }); 137 }, 138 'priority' => 40, 139 ]); 140 141 142 143 advset_register_feature([ 87 144 'id' => 'system.updates.skip_bundled_themes', 88 145 'category' => 'system', 89 146 'ui_config' => fn() => [ 147 'tags' => [ 148 __('System', 'advanced-settings'), 149 __('Updates', 'advanced-settings'), 150 __('Cleanup', 'advanced-settings'), 151 ], 90 152 'fields' => [ 91 153 'enable' => [ … … 130 192 } 131 193 }, 132 'priority' => 20,194 'priority' => 50, 133 195 ]); 134 196 … … 139 201 'category' => 'system', 140 202 'ui_config' => fn() => [ 203 'tags' => [ 204 __('System', 'advanced-settings'), 205 __('Updates', 'advanced-settings'), 206 __('Notifications', 'advanced-settings'), 207 __('Emails', 'advanced-settings'), 208 ], 141 209 'fields' => [ 142 210 'enable' => [ … … 150 218 add_filter('auto_core_update_send_email', '__return_false'); 151 219 }, 152 'priority' => 20,220 'priority' => 60, 153 221 ]); 154 222 … … 159 227 'category' => 'system', 160 228 'ui_config' => fn() => [ 229 'tags' => [ 230 __('System', 'advanced-settings'), 231 __('Updates', 'advanced-settings'), 232 __('Notifications', 'advanced-settings'), 233 __('Emails', 'advanced-settings'), 234 ], 161 235 'fields' => [ 162 236 'enable' => [ … … 170 244 add_filter('auto_plugin_update_send_email', '__return_false'); 171 245 }, 172 'priority' => 30,246 'priority' => 70, 173 247 ]); 174 248 … … 179 253 'category' => 'system', 180 254 'ui_config' => fn() => [ 255 'tags' => [ 256 __('System', 'advanced-settings'), 257 __('Updates', 'advanced-settings'), 258 __('Notifications', 'advanced-settings'), 259 __('Emails', 'advanced-settings'), 260 ], 181 261 'fields' => [ 182 262 'enable' => [ … … 190 270 add_filter('auto_theme_update_send_email', '__return_false'); 191 271 }, 192 'priority' => 40,193 ]); 194 195 272 'priority' => 80, 273 ]); 274 275 -
advanced-settings/tags/3.1.0/migrations/3.x.x.php
r3281733 r3323103 152 152 }, 153 153 154 '3.1.0' => function() { 155 $settings = get_option('advanced_settings_settings', []); 156 157 // Add admin bar logo to branding feature 158 if ( !empty($settings['dashboard.adminbar.custom_logo']['url']) ) { 159 $settings['dashboard.branding.customize'] = [ 160 'enable' => true, 161 'admin_bar_logo' => $settings['dashboard.adminbar.custom_logo']['url'], 162 ]; 163 } 164 165 // Remove old admin bar logo option 166 unset($settings['dashboard.adminbar.custom_logo']); 167 168 // Move old auto save setting to editing category 169 if ( !empty($settings['system.posts.disable_autosave']) ) { 170 $settings['editing.posts.disable_autosave'] = $settings['system.posts.disable_autosave']; 171 unset($settings['system.posts.disable_autosave']); 172 } 173 174 // Move old auto thumbs setting to editing category 175 if ( !empty($settings['frontend.thumbnails.auto_from_first_image']) ) { 176 $settings['editing.thumbnails.auto_from_first_image'] = $settings['frontend.thumbnails.auto_from_first_image']; 177 unset($settings['frontend.thumbnails.auto_from_first_image']); 178 } 179 180 // Move old thumbs setting to editing category 181 if ( !empty($settings['frontend.thumbnails.enable_support']) ) { 182 $settings['editing.thumbnails.enable_support'] = $settings['frontend.thumbnails.enable_support']; 183 unset($settings['frontend.thumbnails.enable_support']); 184 } 185 186 // Rename dashboard features to adminarea features 187 foreach ($settings as $feature_id => $feature_settings) { 188 if ( strpos($feature_id, 'dashboard.') === 0 ) { 189 $settings['adminarea.' . substr($feature_id, 10)] = $feature_settings; 190 unset($settings[$feature_id]); 191 } 192 } 193 194 // Update settings 195 update_option('advanced_settings_settings', $settings); 196 }, 197 154 198 ]; -
advanced-settings/tags/3.1.0/readme.txt
r3308393 r3323103 8 8 Requires at least: 5.0.0 9 9 Tested up to: 6.8 10 Stable tag: 3. 0.210 Stable tag: 3.1.0 11 11 License: GPLv3 or later 12 12 License URI: http://www.gnu.org/licenses/gpl-3.0.html … … 26 26 [→ details in FAQ](https://wordpress.org/plugins/advanced-settings#how%20is%20the%20security%20of%20the%20plugin%20ensured%3F) 27 27 28 **✳️ INFO ABOUT BAD REVIEWS**29 2 bad r eviews occurred in 2017 because outdated PHP versions were used, but can't happen again.28 **✳️ INFO ABOUT THE 2 BAD RATINGS** 29 2 bad ratings occurred in 2017 because outdated PHP versions were used, but can't happen again. 30 30 [→ details in FAQ](https://wordpress.org/plugins/advanced-settings#what%20caused%20the%20two%20bad%20ratings%3F) 31 31 … … 37 37 Advanced Settings 3 was developed to help as many users as possible. If you'd like to see a feature added to this plugin, please let us know. Don't worry, we'll keep the plugin fast and lean; this is a high priority for us. We'll only implement features that don't conflict with this. 38 38 39 = Dashboard=40 41 * Customize dashboard logo39 = Admin Area = 40 41 * Hide the top admin bar for all users in the frontend 42 42 * Hide WordPress update message in dashboard 43 * Hide the top admin bar for all users in the frontend44 43 * Hide the welcome panel in the dashboard 44 * Hide the default widgets in the dashboard 💥 new 45 * Customize the admin area branding 💥 new 46 47 = Frontend = 48 49 * Remove PHP version from HTTP headers 💥 new 50 * Add security HTTP headers 💥 new 51 * Automatically add FavIcon (when favicon.ico, favicon.png or favicon.svg exists in template folder) 52 * Add Facebook Open Graph meta tags 53 * Remove shortlink meta tag 54 * Remove RSD (Weblog Client Link) meta tag 55 * Remove WordPress generator meta tag 56 * Automatically add description meta tag using blog description and post excerpt (SEO) 57 * Disable author pages 58 * Remove wptexturize filter 59 * Disable auto embed of external content 💥 new 60 * Limit excerpt length 61 * Add "Read more" link after excerpt 62 * Remove trackbacks and pingbacks from comment count 63 * Protect email addresses from spam bots 64 * Compress HTML code 65 * Remove HTML comments (except conditional IE comments) 66 * Disable emoji image replacement 67 68 = Editing = 69 70 * Disable posts auto saving 71 * Limit post revisions 💥 new 72 * Allow SVG uploads for admins 💥 new 73 * Downsize images on upload to max size 74 * Set JPEG quality 75 * Add thumbnail support 76 * Automatically generate post thumbnail (from first image in post) 45 77 46 78 = System = … … 48 80 * Hide default WordPress favicon 49 81 * Disable comment system 50 * Disable posts auto saving 82 * Disable XML-RPC 💥 new 83 * Disable public REST API 💥 new 51 84 * Prevent installation of new default WordPress themes during core updates 52 85 * Disable email notifications for core updates 53 86 * Disable email notifications for plugin updates 54 87 * Disable email notifications for theme updates 55 56 = Frontend =57 58 * Disable author pages59 * Automatically add FavIcon (when favicon.ico, favicon.png or favicon.svg exists in template folder)60 * Automatically add description meta tag using blog description and post excerpt (SEO)61 * Remove WordPress generator meta tag62 * Remove RSD (Weblog Client Link) meta tag63 * Remove shortlink meta tag64 * Limit excerpt length65 * Add "Read more" link after excerpt66 * Remove wptexturize filter67 * Remove trackbacks and pingbacks from comment count68 * Compress HTML code69 * Remove HTML comments (except conditional IE comments)70 * Disable author pages71 * Add thumbnail support72 * Automatically generate post thumbnail (from first image in post)73 * Protect email addresses from spam bots74 * Add Facebook Open Graph meta tags75 * Disable emoji image replacement76 77 = Editing =78 79 * Set JPEG quality80 * Downsize images on upload to max size81 88 82 89 = Developer = … … 131 138 132 139 **Detailed answer:** 133 The plugin developer at the time had decided in 2017 to use PHP features that were introduced with PHP 5.4. Support for the previous version, PHP 5.3, had already been officially discontinued by The PHP Group 3 years earlier. It was therefore natural to assume that all websites actually in use had already been converted to PHP 5.4 or newer. Unfortunately, this was not the case for a few of them.134 135 Nowadays, you canspecify in the plugin metadata which PHP version is required as a minimum for the plugin, so that users can only update the plugin if they are using the correct PHP version. While this WordPress feature came too late to prevent the problems and the negative reviews, this problem can fortunately be prevented in the future.136 137 It would be great if you could contribute with your own review to ensure that the ratings reflect the current stateof the plugin.140 The plugin developer at the time had decided in 2017 to use PHP features that were introduced with PHP 5.4. Support for the previous version, PHP 5.3, had already been officially discontinued by The PHP Group 3 years earlier. It was therefore natural to assume that all websites actually in use had already been converted to PHP 5.4 or newer. Unfortunately, this was not the case for a few users. 141 142 Nowadays, WordPress allowes to specify in the plugin metadata which PHP version is required as a minimum for the plugin, so that users can only update the plugin if they are using the correct PHP version. While this WordPress feature came too late to prevent the problems and the negative reviews, this problem can fortunately be prevented in the future. 143 144 It would be great if you could contribute with your own review to ensure that the ratings reflect the quality of the plugin. 138 145 139 146 == Screenshots == … … 144 151 145 152 == Changelog == 153 154 = 3.1.0 - 2025-07-06 = 155 * Added 9 new features (see feature list) 156 * Added tags and tag navigation 146 157 147 158 = 3.0.2 - 2025-06-04 = -
advanced-settings/trunk/admin-ui/admin-ui.css
r3281733 r3323103 125 125 padding: 0; 126 126 max-width: 90%; 127 width: 6 0em;127 width: 65em; 128 128 height: 80vh; 129 129 background-color: #fff; -
advanced-settings/trunk/admin-ui/react/app.css
r3281733 r3323103 18 18 .advset-category-sidebar { 19 19 min-width: 10em; 20 max-width: 18em; 20 21 flex-shrink: 0; 21 22 background-color: var(--advset-color-base-95); 22 23 border-right: 1px solid var(--advset-color-border); 23 24 position: sticky; 25 display: flex; 26 flex-direction: column; 27 } 28 29 /* Tab Navigation */ 30 .advset-tab-navigation { 31 display: flex; 32 border-bottom: 1px solid var(--advset-color-border); 33 background-color: var(--advset-color-base-97); 34 } 35 36 .advset-tab-button { 37 flex: 1; 38 background: none; 39 border: none; 40 padding: .75em 1em; 41 font-size: var(--advset-font-size-small); 42 font-weight: 600; 43 text-transform: uppercase; 44 letter-spacing: .03em; 45 color: var(--advset-color-base-70); 46 cursor: pointer; 47 transition: all .3s; 48 border-bottom: 2px solid transparent; 49 } 50 51 .advset-tab-button:hover:not(:disabled), 52 .advset-tab-button:focus-visible:not(:disabled) { 53 color: var(--advset-color-base); 54 background-color: var(--advset-color-base-90); 55 } 56 57 .advset-tab-button.is-active { 58 color: var(--advset-color-base); 59 border-bottom-color: var(--advset-color-base); 60 background-color: var(--advset-color-base-95); 61 font-weight: 700; 62 } 63 64 .advset-tab-button:disabled { 65 opacity: 0.5; 66 cursor: not-allowed; 67 } 68 69 /* Tab Content */ 70 .advset-tab-content { 71 flex: 1; 72 overflow-y: auto; 24 73 } 25 74 … … 69 118 font-weight: 600; 70 119 text-transform: uppercase; 120 } 121 122 123 124 .advset-tags-list { 125 display: flex; 126 flex-wrap: wrap; 127 gap: .5em; 128 padding: 1em; 129 } 130 131 .advset-tag { 132 background: none; 133 border: 1px solid var(--advset-color-base-70); 134 border-radius: 1em; 135 padding: .25em .75em; 136 font-size: var(--advset-font-size-tiny); 137 color: var(--advset-color-base-70); 138 cursor: pointer; 139 transition: all .3s; 140 font-family: inherit; 141 line-height: inherit; 142 } 143 144 .advset-tag:hover, 145 .advset-tag:focus-visible { 146 border-color: var(--advset-color-primary); 147 color: var(--advset-color-primary); 148 outline: var(--advset-color-primary) 1px solid; 149 } 150 151 .advset-tag.is-active { 152 background-color: var(--advset-color-primary); 153 border-color: var(--advset-color-primary); 154 color: var(--advset-color-background); 155 } 156 157 .advset-tag.is-disabled { 158 opacity: 0.5; 159 cursor: not-allowed; 160 color: var(--advset-color-base); 161 border-color: var(--advset-color-base-70); 162 background-color: var(--advset-color-base-70); 163 } 164 165 .advset-tag.is-disabled:hover, 166 .advset-tag.is-disabled:focus-visible { 167 border-color: var(--advset-color-base-50); 168 color: var(--advset-color-base-50); 169 outline: none; 71 170 } 72 171 … … 260 359 } 261 360 361 362 363 /* ===== Item Tags ===== */ 364 .advset-item-tags { 365 display: flex; 366 flex-wrap: wrap; 367 justify-content: flex-end; 368 gap: .5em; 369 margin-top: .5em; 370 } 371 372 .advset-item-tag { 373 background: none; 374 border: 1px solid var(--advset-color-base-70); 375 border-radius: 1em; 376 padding: .25em .75em; 377 font-size: var(--advset-font-size-tiny); 378 color: var(--advset-color-base-70); 379 cursor: pointer; 380 transition: all .3s; 381 font-family: inherit; 382 line-height: inherit; 383 } 384 385 .advset-item-tag:hover, 386 .advset-item-tag:focus-visible { 387 border-color: var(--advset-color-primary); 388 color: var(--advset-color-primary); 389 outline: var(--advset-color-primary) 1px solid; 390 } 391 392 .advset-item-tag.is-active { 393 background-color: var(--advset-color-primary); 394 border-color: var(--advset-color-primary); 395 color: var(--advset-color-background); 396 } 397 398 399 -
advanced-settings/trunk/admin-ui/react/app.js
r3286786 r3323103 17 17 */ 18 18 function App(props) { 19 const { items, categories, onSettingChange, onCategoryClick, settings, searchQuery, activeCategory} = props;19 const { items, categories, onSettingChange, onCategoryClick, onTagClick, onTabChange, settings, searchQuery, parsedSearchQuery, activeCategory, hiddenItems, activeTab } = props; 20 20 21 21 // Group items by category … … 37 37 ); 38 38 39 // Extract all unique tags from all items (both visible and hidden) 40 const allTags = new Set(); 41 const visibleTagCounts = new Map(); 42 const hiddenTagCounts = new Map(); 43 44 // Count tags from visible items 45 items.forEach(item => { 46 if (item.ui_config?.tags) { 47 item.ui_config.tags.forEach(tag => { 48 allTags.add(tag); 49 visibleTagCounts.set(tag, (visibleTagCounts.get(tag) || 0) + 1); 50 }); 51 } 52 }); 53 54 // Count tags from hidden items 55 hiddenItems.forEach(item => { 56 if (item.ui_config?.tags) { 57 item.ui_config.tags.forEach(tag => { 58 allTags.add(tag); 59 hiddenTagCounts.set(tag, (hiddenTagCounts.get(tag) || 0) + 1); 60 }); 61 } 62 }); 63 64 const sortedTags = Array.from(allTags).sort(); 65 39 66 40 67 return React.createElement('div', { className: 'advset-react-app' }, … … 42 69 React.createElement('div', { className: 'advset-notifications' }), 43 70 44 // Category sidebar 45 visibleCategories.length > 0 && React.createElement('div', { className: 'advset-category-sidebar' }, 46 React.createElement('ul', { className: 'advset-category-menu' }, 47 visibleCategoriesIncludingSeparator.map(category => 48 React.createElement('li', { 49 key: category.id, 50 className: 'advset-category-menu-item' 51 }, 52 category.title ? 53 React.createElement('a', { 54 href: `#category-${category.id}`, 55 onClick: (e) => { 56 e.preventDefault(); 57 onCategoryClick(category.id); 58 }, 59 className: activeCategory === category.id ? 'is-active' : '' 60 }, 61 React.createElement('span', { 62 className: 'advset-category-icon', 63 dangerouslySetInnerHTML: { __html: category.icon || '' } 64 }), 65 React.createElement('span', { 66 className: 'advset-category-text' 67 }, category.title || category.id) 68 ) : React.createElement('div', { 69 className: 'advset-category-separator', 70 style: { 71 borderTop: '1px solid #ccc', 72 } 73 }) 71 // Sidebar with tab navigation 72 React.createElement('div', { className: 'advset-category-sidebar' }, 73 // Tab navigation 74 React.createElement('div', { className: 'advset-tab-navigation' }, 75 React.createElement('button', { 76 className: `advset-tab-button ${activeTab === 'categories' ? 'is-active' : ''}`, 77 onClick: () => onTabChange('categories'), 78 disabled: visibleCategories.length === 0 79 }, 'Categories'), 80 React.createElement('button', { 81 className: `advset-tab-button ${activeTab === 'tags' ? 'is-active' : ''}`, 82 onClick: () => onTabChange('tags'), 83 disabled: sortedTags.length === 0 84 }, 'Tags') 85 ), 86 87 // Categories tab content 88 activeTab === 'categories' && visibleCategories.length > 0 && React.createElement('div', { className: 'advset-tab-content' }, 89 React.createElement('ul', { className: 'advset-category-menu' }, 90 visibleCategoriesIncludingSeparator.map(category => 91 React.createElement('li', { 92 key: category.id, 93 className: 'advset-category-menu-item' 94 }, 95 category.title ? 96 React.createElement('a', { 97 href: `#category-${category.id}`, 98 onClick: (e) => { 99 e.preventDefault(); 100 onCategoryClick(category.id); 101 }, 102 className: activeCategory === category.id ? 'is-active' : '' 103 }, 104 React.createElement('span', { 105 className: 'advset-category-icon', 106 dangerouslySetInnerHTML: { __html: category.icon || '' } 107 }), 108 React.createElement('span', { 109 className: 'advset-category-text' 110 }, category.title || category.id) 111 ) : React.createElement('div', { 112 className: 'advset-category-separator', 113 style: { 114 borderTop: '1px solid #ccc', 115 } 116 }) 117 ) 74 118 ) 119 ) 120 ), 121 122 // Tags tab content 123 activeTab === 'tags' && sortedTags.length > 0 && React.createElement('div', { className: 'advset-tab-content' }, 124 React.createElement('div', { className: 'advset-tags-list' }, 125 sortedTags.map(tag => { 126 const isActive = parsedSearchQuery?.included?.tags?.includes(tag.toLowerCase()); 127 const hasVisibleItems = visibleTagCounts.has(tag); 128 const hasHiddenItems = hiddenTagCounts.has(tag); 129 130 let className = 'advset-tag'; 131 if (isActive) className += ' is-active'; 132 if (!hasVisibleItems && hasHiddenItems) className += ' is-disabled'; 133 134 return React.createElement('button', { 135 key: tag, 136 className: className, 137 onClick: () => onTagClick(tag), 138 disabled: !hasVisibleItems && hasHiddenItems 139 }, tag); 140 }) 75 141 ) 76 142 ) … … 102 168 item: item, 103 169 onSettingChange: onSettingChange, 104 settingValue: settings[item.id] || {} 170 onTagClick: onTagClick, 171 settingValue: settings[item.id] || {}, 172 parsedSearchQuery: parsedSearchQuery 105 173 }) 106 174 ) … … 138 206 */ 139 207 function ItemCard(props) { 140 const { item, onSettingChange, settingValue} = props;208 const { item, onSettingChange, onTagClick, settingValue, parsedSearchQuery } = props; 141 209 142 210 // Get the component from the registry … … 197 265 config: item.ui_config || {} 198 266 }) 267 ), 268 // Show tags if item has tags 269 item.ui_config?.tags && item.ui_config.tags.length > 0 && React.createElement('div', { 270 className: 'advset-item-tags' 271 }, 272 item.ui_config.tags.map(tag => 273 React.createElement('button', { 274 key: tag, 275 className: `advset-item-tag ${parsedSearchQuery?.included?.tags?.includes(tag.toLowerCase()) ? 'is-active' : ''}`, 276 onClick: () => onTagClick(tag) 277 }, tag) 278 ) 199 279 ) 200 280 ); … … 212 292 items: [], 213 293 allItems: [], // Cache for all items 294 hiddenItems: [], // Items that are hidden by current filter 214 295 isLoading: false, 215 296 categories: [], 216 297 settings: {}, // Store for settings values 217 298 activeCategory: null, // Track active category for scrolling 218 parsedSearchQuery: null // Cache for parsed search query 299 parsedSearchQuery: null, // Cache for parsed search query 300 activeTab: 'categories' // Track active tab: 'categories' or 'tags' 219 301 }, 220 302 … … 304 386 performLocalSearch(query) { 305 387 const parsedSearchQuery = query ? parseSearchQuery(query) : null; 388 const { filteredItems, hiddenItems } = this.filterItems(this.state.allItems, parsedSearchQuery); 306 389 307 390 this.setState({ 308 391 searchQuery: query, 309 392 parsedSearchQuery, 310 items: this.filterItems(this.state.allItems, parsedSearchQuery) 393 items: filteredItems, 394 hiddenItems: hiddenItems 311 395 }); 312 396 }, … … 317 401 * @param {Array} items - The items to filter 318 402 * @param {Object} parsedSearchQuery - The parsed search query 319 * @returns { Array} - Filtereditems403 * @returns {Object} - Object containing filtered and hidden items 320 404 */ 321 405 filterItems(items, parsedSearchQuery) { … … 323 407 const showExperimental = this.state.settings['advset.features.show_experimental']?.enable; 324 408 325 return items.filter(item => { 326 // Filter by feature flags 409 const filteredItems = []; 410 const hiddenItems = []; 411 412 items.forEach(item => { 413 // Check feature flags first 414 let isHiddenByFlags = false; 327 415 if (item.deprecated && !showDeprecated && typeof this.state.settings[item.id] === 'undefined') { 328 return false; 329 } 330 416 isHiddenByFlags = true; 417 } 331 418 if (item.experimental && !showExperimental && typeof this.state.settings[item.id] === 'undefined') { 332 return false;333 } 334 335 // If no search query, include the item 419 isHiddenByFlags = true; 420 } 421 422 // If no search query, include the item based on flags only 336 423 if (!parsedSearchQuery) { 337 return true; 338 } 339 340 // Search in ui_config fields 424 if (isHiddenByFlags) { 425 hiddenItems.push(item); 426 } else { 427 filteredItems.push(item); 428 } 429 return; 430 } 431 432 // Search in ui_config fields and tags 341 433 const searchTexts = []; 342 434 … … 354 446 } 355 447 356 const searchText = searchTexts.join(' ').toLowerCase(); 448 // Add tags to searchable text 449 if (item.ui_config?.tags) { 450 searchTexts.push(...item.ui_config.tags); 451 } 452 453 const searchText = searchTexts.join(Math.random()).toLowerCase(); 357 454 358 455 // Check if item matches all required terms 359 const matches Terms = parsedSearchQuery.terms.every(term =>456 const matchesIncludedTerms = parsedSearchQuery.included.terms.length === 0 || parsedSearchQuery.included.terms.every(term => 360 457 searchText.includes(term) 361 458 ); 362 459 363 460 // Check if item doesn't contain any excluded terms 364 const matchesExclu sions = !parsedSearchQuery.exclusions.some(exclusion =>461 const matchesExcludedTerms = !parsedSearchQuery.excluded.terms.some(exclusion => 365 462 searchText.includes(exclusion) 366 463 ); 367 464 368 // Item must match all terms and no exclusions 369 return matchesTerms && matchesExclusions; 465 // Check tag requirements (now using labels) 466 const itemTags = (item.ui_config?.tags || []).map(tag => tag.toLowerCase()); 467 468 // Item must have ALL required tags 469 const matchesIncludedTags = parsedSearchQuery.included.tags.length === 0 || parsedSearchQuery.included.tags.every(tag => 470 itemTags.includes(tag) 471 ); 472 473 // Item must NOT have ANY excluded tags 474 const matchesExcludedTags = !parsedSearchQuery.excluded.tags.some(tag => 475 itemTags.includes(tag) 476 ); 477 478 // Item must match all terms, no exclusions, required tags, and no excluded tags 479 const matchesSearch = matchesIncludedTerms && matchesExcludedTerms && matchesIncludedTags && matchesExcludedTags; 480 481 if (isHiddenByFlags || !matchesSearch) { 482 hiddenItems.push(item); 483 } else { 484 filteredItems.push(item); 485 } 370 486 }); 487 488 return { filteredItems, hiddenItems }; 371 489 }, 372 490 … … 399 517 400 518 // Apply initial filtering 519 const { filteredItems, hiddenItems } = this.filterItems(data.features); 401 520 this.setState({ 402 items: this.filterItems(data.features), 521 items: filteredItems, 522 hiddenItems: hiddenItems 403 523 }); 404 524 … … 433 553 }, 434 554 555 556 557 /** 558 * Handle tab change 559 * 560 * @param {string} tab - The tab to switch to 561 */ 562 handleTabChange(tab) { 563 this.setState({ activeTab: tab }); 564 }, 565 566 /** 567 * Handle tag click 568 * 569 * @param {string} tag - The tag that was clicked 570 */ 571 handleTagClick(tag) { 572 const searchInput = document.querySelector('.advset-modal-search input'); 573 if (!searchInput) return; 574 575 let currentQuery = searchInput.value.trim(); 576 577 // Handle tags with spaces by adding quotes 578 const tagPrefix = tag.includes(' ') ? `tag:"${tag}"` : `tag:${tag}`; 579 580 // Check if tag is already in query (handle both quoted and unquoted versions) 581 const tagRegex = new RegExp(`\\btag:("${tag.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"|${tag.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})\\b`, 'g'); 582 const hasTag = tagRegex.test(currentQuery); 583 584 if (hasTag) { 585 // Remove tag from query 586 currentQuery = currentQuery.replace(tagRegex, '').replace(/\s+/g, ' ').trim(); 587 } else { 588 // Add tag to query 589 currentQuery = currentQuery ? `${currentQuery} ${tagPrefix}` : tagPrefix; 590 } 591 592 // Update search input 593 searchInput.value = currentQuery; 594 595 // Trigger search 596 document.dispatchEvent(new CustomEvent('advset-search', { 597 detail: { query: currentQuery } 598 })); 599 }, 600 435 601 /** 436 602 * Render the application 437 603 */ 438 604 render() { 439 const { searchQuery, items, isLoading, categories} = this.state;605 const { searchQuery, parsedSearchQuery, items, hiddenItems, isLoading, categories, activeTab } = this.state; 440 606 441 607 // Render the React app … … 446 612 onSettingChange: this.handleSettingChange.bind(this), 447 613 onCategoryClick: this.scrollToCategory.bind(this), 614 onTagClick: this.handleTagClick.bind(this), 615 onTabChange: this.handleTabChange.bind(this), 448 616 settings: this.state.settings, 449 617 searchQuery: searchQuery, 450 activeCategory: this.state.activeCategory 618 parsedSearchQuery: parsedSearchQuery, 619 activeCategory: this.state.activeCategory, 620 hiddenItems: hiddenItems, 621 activeTab: activeTab 451 622 }); 452 623 … … 588 759 function parseSearchQuery(query) { 589 760 const result = { 590 terms: [], 591 exclusions: [] 761 excluded: { 762 tags: [], 763 terms: [], 764 }, 765 included: { 766 tags: [], 767 terms: [], 768 }, 592 769 }; 593 770 … … 596 773 597 774 // Extract terms and phrases (with optional minus) 598 const matches = query.match(/-?"[^"]+"|-[^\s]+|[^\s]+/g) || []; 599 600 matches.forEach(match => { 601 if (match.startsWith('-')) { 602 // Handle exclusions 603 const exclusion = match.startsWith('-"') 604 ? match.slice(2, -1) // Remove -" and " 605 : match.slice(1); // Remove - 606 if (exclusion) { 607 result.exclusions.push(exclusion.toLowerCase()); 608 } 609 } else { 610 // Handle regular terms 611 const term = match.startsWith('"') 612 ? match.slice(1, -1) // Remove quotes 613 : match; 614 if (term) { 615 result.terms.push(term.toLowerCase()); 616 } 617 } 775 query.matchAll(/(\-)?(tag:)?(?:("[^"]+")|([^"\s]+))/g).forEach(match => { 776 const isExclusion = match[1] === '-'; 777 const isTag = match[2] === 'tag:'; 778 const term = (match[3] ? match[3].slice(1, -1) : match[4]).toLowerCase(); 779 780 const targetList = result[isExclusion ? 'excluded' : 'included'][isTag ? 'tags' : 'terms']; 781 targetList.push(term); 618 782 }); 619 783 -
advanced-settings/trunk/advanced-settings.php
r3306579 r3323103 6 6 Author: Helmut Wandl 7 7 Author URI: https://ehtmlu.com/ 8 Version: 3. 0.28 Version: 3.1.0 9 9 Requires at least: 5.0.0 10 10 Requires PHP: 7.4 -
advanced-settings/trunk/feature-setup/categories.php
r3281733 r3323103 13 13 14 14 advset_register_category([ 15 'id' => ' dashboard',15 'id' => 'adminarea', 16 16 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>gauge</title><path d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,4A8,8 0 0,1 20,12C20,14.4 19,16.5 17.3,18C15.9,16.7 14,16 12,16C10,16 8.2,16.7 6.7,18C5,16.5 4,14.4 4,12A8,8 0 0,1 12,4M14,5.89C13.62,5.9 13.26,6.15 13.1,6.54L11.81,9.77L11.71,10C11,10.13 10.41,10.6 10.14,11.26C9.73,12.29 10.23,13.45 11.26,13.86C12.29,14.27 13.45,13.77 13.86,12.74C14.12,12.08 14,11.32 13.57,10.76L13.67,10.5L14.96,7.29L14.97,7.26C15.17,6.75 14.92,6.17 14.41,5.96C14.28,5.91 14.15,5.89 14,5.89M10,6A1,1 0 0,0 9,7A1,1 0 0,0 10,8A1,1 0 0,0 11,7A1,1 0 0,0 10,6M7,9A1,1 0 0,0 6,10A1,1 0 0,0 7,11A1,1 0 0,0 8,10A1,1 0 0,0 7,9M17,9A1,1 0 0,0 16,10A1,1 0 0,0 17,11A1,1 0 0,0 18,10A1,1 0 0,0 17,9Z" /></svg>', 17 'title' => __(' Dashboard', 'advanced-settings'),17 'title' => __('Admin Area', 'advanced-settings'), 18 18 'priority' => 10, 19 ]); 20 21 advset_register_category([ 22 'id' => 'frontend', 23 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>monitor</title><path d="M21,16H3V4H21M21,2H3C1.89,2 1,2.89 1,4V16A2,2 0 0,0 3,18H10V20H8V22H16V20H14V18H21A2,2 0 0,0 23,16V4C23,2.89 22.1,2 21,2Z" /></svg>', 24 'title' => __('Frontend', 'advanced-settings'), 25 'priority' => 20, 26 ]); 27 28 advset_register_category([ 29 'id' => 'editing', 30 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>pencil</title><path d="M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z" /></svg>', 31 'title' => __('Editing', 'advanced-settings'), 32 'priority' => 30, 19 33 ]); 20 34 … … 23 37 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>application-cog-outline</title><path d="M21.7 18.6V17.6L22.8 16.8C22.9 16.7 23 16.6 22.9 16.5L21.9 14.8C21.9 14.7 21.7 14.7 21.6 14.7L20.4 15.2C20.1 15 19.8 14.8 19.5 14.7L19.3 13.4C19.3 13.3 19.2 13.2 19.1 13.2H17.1C16.9 13.2 16.8 13.3 16.8 13.4L16.6 14.7C16.3 14.9 16.1 15 15.8 15.2L14.6 14.7C14.5 14.7 14.4 14.7 14.3 14.8L13.3 16.5C13.3 16.6 13.3 16.7 13.4 16.8L14.5 17.6V18.6L13.4 19.4C13.3 19.5 13.2 19.6 13.3 19.7L14.3 21.4C14.4 21.5 14.5 21.5 14.6 21.5L15.8 21C16 21.2 16.3 21.4 16.6 21.5L16.8 22.8C16.9 22.9 17 23 17.1 23H19.1C19.2 23 19.3 22.9 19.3 22.8L19.5 21.5C19.8 21.3 20 21.2 20.3 21L21.5 21.4C21.6 21.4 21.7 21.4 21.8 21.3L22.8 19.6C22.9 19.5 22.9 19.4 22.8 19.4L21.7 18.6M18 19.5C17.2 19.5 16.5 18.8 16.5 18S17.2 16.5 18 16.5 19.5 17.2 19.5 18 18.8 19.5 18 19.5M12.3 22H3C1.9 22 1 21.1 1 20V4C1 2.9 1.9 2 3 2H21C22.1 2 23 2.9 23 4V13.1C22.4 12.5 21.7 12 21 11.7V6H3V20H11.3C11.5 20.7 11.8 21.4 12.3 22Z" /></svg>', 24 38 'title' => __('System', 'advanced-settings'), 25 'priority' => 20,26 ]);27 28 advset_register_category([29 'id' => 'advset',30 'icon' => file_get_contents(ADVSET_DIR . '/admin-ui/images/admin-bar-icon.svg'),31 'title' => __('About & Options', 'advanced-settings'),32 'priority' => 100,33 ]);34 35 advset_register_category([36 'id' => 'advset-separator',37 'priority' => 99,38 ]);39 40 advset_register_category([41 'id' => 'frontend',42 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>monitor</title><path d="M21,16H3V4H21M21,2H3C1.89,2 1,2.89 1,4V16A2,2 0 0,0 3,18H10V20H8V22H16V20H14V18H21A2,2 0 0,0 23,16V4C23,2.89 22.1,2 21,2Z" /></svg>',43 'title' => __('Frontend', 'advanced-settings'),44 'priority' => 30,45 ]);46 47 advset_register_category([48 'id' => 'editing',49 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>pencil</title><path d="M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z" /></svg>',50 'title' => __('Editing', 'advanced-settings'),51 39 'priority' => 40, 52 40 ]); … … 58 46 'priority' => 50, 59 47 ]); 48 49 advset_register_category([ 50 'id' => 'advset-separator', 51 'priority' => 99, 52 ]); 53 54 advset_register_category([ 55 'id' => 'advset', 56 'icon' => file_get_contents(ADVSET_DIR . '/admin-ui/images/admin-bar-icon.svg'), 57 'title' => __('About & Options', 'advanced-settings'), 58 'priority' => 100, 59 ]); 60 60 }); -
advanced-settings/trunk/feature-setup/features/advset.php
r3281733 r3323103 65 65 ], 66 66 'default' => '', 67 'description' => __('By default, we do not track plugin usage. If you agree to share your plugin usage with the developers, we will collect anonymous data about your usage. This data will be used to improve the plugin and to provide you with a better experience.', 'advanced-settings'), 67 68 ], 68 69 ] -
advanced-settings/trunk/feature-setup/features/developer.php
r3306579 r3323103 15 15 'category' => 'developer', 16 16 'ui_config' => fn() => [ 17 'tags' => [ 18 __('Developer', 'advanced-settings'), 19 __('Debug', 'advanced-settings'), 20 __('Performance', 'advanced-settings'), 21 ], 17 22 'fields' => [ 18 23 'enable' => [ … … 44 49 'experimental' => true, 45 50 'ui_config' => fn() => [ 51 'tags' => [ 52 __('Developer', 'advanced-settings'), 53 __('Frontend', 'advanced-settings'), 54 __('Performance', 'advanced-settings'), 55 ], 46 56 'fields' => [ 47 57 'enable' => [ … … 83 93 'experimental' => true, 84 94 'ui_config' => fn() => [ 95 'tags' => [ 96 __('Developer', 'advanced-settings'), 97 __('Frontend', 'advanced-settings'), 98 __('Performance', 'advanced-settings'), 99 ], 85 100 'fields' => [ 86 101 'enable' => [ … … 122 137 'experimental' => true, 123 138 'ui_config' => fn() => [ 139 'tags' => [ 140 __('Developer', 'advanced-settings'), 141 __('Admin', 'advanced-settings'), 142 __('Posts', 'advanced-settings'), 143 ], 124 144 'fields' => [ 125 145 'enable' => [ … … 221 241 'experimental' => true, 222 242 'ui_config' => fn() => [ 243 'tags' => [ 244 __('Developer', 'advanced-settings'), 245 __('Admin', 'advanced-settings'), 246 __('Frontend', 'advanced-settings'), 247 __('Performance', 'advanced-settings'), 248 ], 223 249 'fields' => [ 224 250 'enable' => [ -
advanced-settings/trunk/feature-setup/features/editing.php
r3281733 r3323103 12 12 13 13 advset_register_feature([ 14 'id' => 'editing.posts.disable_autosave', 15 'category' => 'editing', 16 'ui_config' => fn() => [ 17 'tags' => [ 18 __('Editing', 'advanced-settings'), 19 __('Posts', 'advanced-settings'), 20 __('Performance', 'advanced-settings'), 21 __('Database', 'advanced-settings'), 22 __('Admin', 'advanced-settings'), 23 ], 24 'fields' => [ 25 'enable' => [ 26 'type' => 'toggle', 27 'label' => __('Disable auto save', 'advanced-settings'), 28 ], 29 ] 30 ], 31 'execution_handler' => function() { 32 define('AUTOSAVE_INTERVAL', 60 * 60 * 24 * 365 * 100); // save interval => 100 years 33 }, 34 'priority' => 10, 35 ]); 36 37 38 39 advset_register_feature([ 40 'id' => 'editing.posts.limit_revisions', 41 'category' => 'editing', 42 'ui_config' => fn() => [ 43 'tags' => [ 44 __('Editing', 'advanced-settings'), 45 __('Posts', 'advanced-settings'), 46 __('Performance', 'advanced-settings'), 47 __('Database', 'advanced-settings'), 48 __('Admin', 'advanced-settings'), 49 ], 50 'fields' => [ 51 'enable' => [ 52 'type' => 'toggle', 53 'label' => __('Limit post revisions', 'advanced-settings'), 54 'description' => __('Reduce database size by limiting the number of saved revisions', 'advanced-settings'), 55 ], 56 'limit' => [ 57 'type' => 'number', 58 'label' => __('Revisions to keep', 'advanced-settings'), 59 'description' => __('0 means revisions are disabled.', 'advanced-settings'), 60 'min' => 0, 61 'default' => 5, 62 'visible' => ['enable' => true], 63 ], 64 'type' => [ 65 'type' => 'radio', 66 'label' => __('Post types', 'advanced-settings'), 67 'description' => __('Select the post types that should be affected by the revision limit.', 'advanced-settings'), 68 'options' => [ 69 'post' => ['label' => 'Posts only'], 70 'page' => ['label' => 'Pages only'], 71 'post_and_page' => ['label' => 'Posts and Pages'], 72 'all' => ['label' => 'All post types (includes custom post types)'], 73 ], 74 'default' => 'post', 75 'visible' => ['enable' => true], 76 ], 77 ] 78 ], 79 'handler_cleanup' => function($settings) { 80 return empty($settings['enable']) ? null : $settings; 81 }, 82 'execution_handler' => function($settings) { 83 if ($settings['type'] === 'all') { 84 add_filter('wp_revisions_to_keep', function($num) use($settings) { 85 return $settings['limit']; 86 }); 87 return; 88 } 89 foreach (explode('_and_', $settings['type']) as $type) { 90 add_filter('wp_' . $type . '_revisions_to_keep', function($num) use($settings) { 91 return $settings['limit']; 92 }); 93 } 94 }, 95 'priority' => 20, 96 ]); 97 98 99 100 advset_register_feature([ 101 'id' => 'editing.media.enable_svg', 102 'category' => 'editing', 103 'ui_config' => fn() => [ 104 'tags' => [ 105 __('Editing', 'advanced-settings'), 106 __('Media', 'advanced-settings'), 107 __('Images', 'advanced-settings'), 108 __('Frontend', 'advanced-settings'), 109 __('Performance', 'advanced-settings'), 110 ], 111 'fields' => [ 112 'enable' => [ 113 'type' => 'toggle', 114 'label' => __('Allow SVG upload for admins', 'advanced-settings'), 115 'description' => __('To keep the plugin lightweight, the SVG security checks in this feature are very limited. Therefore, this feature is only available to administrators.', 'advanced-settings'), 116 ], 117 ] 118 ], 119 'execution_handler' => function() { 120 if (!current_user_can('administrator')) { 121 return; 122 } 123 124 add_filter('upload_mimes', function($mimes) { 125 $mimes['svg'] = 'image/svg+xml'; 126 $mimes['svgz'] = 'image/svg+xml'; 127 return $mimes; 128 }); 129 130 add_filter('wp_handle_upload_prefilter', function($file) { 131 if ($file['type'] !== 'image/svg+xml') { 132 return $file; 133 } 134 135 $file_content = file_get_contents($file['tmp_name']); 136 137 // 1. Check if the file is empty 138 if (empty($file_content)) { 139 $file['error'] = __('Empty SVG file', 'advanced-settings'); 140 return $file; 141 } 142 143 // 2. Remove XML declaration and Doctype for better compatibility 144 $clean_content = preg_replace('/<\?xml\b[^>]*>\s*/i', '', $file_content); 145 $clean_content = preg_replace('/<!DOCTYPE[^>[]*(\[[^]]*\])?[^>]*>\s*/is', '', $clean_content); 146 147 // 3. XXE-Protection (critical!) 148 $entity_loader_state = libxml_disable_entity_loader(true); 149 libxml_use_internal_errors(true); 150 libxml_clear_errors(); 151 152 $svg = @simplexml_load_string($clean_content); 153 154 if ($svg === false) { 155 $errors = libxml_get_errors(); 156 $first_error = !empty($errors[0]) ? $errors[0]->message : __('Unknown error', 'advanced-settings'); 157 libxml_clear_errors(); 158 /* translators: %s is the first error message from libxml */ 159 $file['error'] = sprintf(__('Invalid SVG: %s', 'advanced-settings'), esc_html($first_error)); 160 return $file; 161 } 162 163 // 4. Simple, but effective security checks 164 $unsafe_patterns = [ 165 '/<script/i', 166 '/\bon\w+\s*=/i', 167 '/javascript:\s*[a-z]+/i', 168 '/<!ENTITY/i', 169 '/<object/i', 170 '/<iframe/i', 171 '/<embed/i', 172 '/href\s*=\s*["\']\s*javascript:/i', 173 '/xlink:href\s*=\s*["\']\s*javascript:/i', 174 '/style\s*=\s*["\'][^"]*expression\s*\(/i', 175 '/style\s*=\s*["\'][^"]*url\s*\(\s*javascript:/i', 176 '/<!--\[if[^\]]*?\]>.*?<!\[endif\]-->/is', 177 ]; 178 179 foreach ($unsafe_patterns as $pattern) { 180 if (preg_match($pattern, $file_content)) { 181 $file['error'] = __('SVG security check failed: Potential dangerous element detected.', 'advanced-settings') . ' ' . $pattern; 182 return $file; 183 } 184 } 185 186 // 5. Additional protection against Base64-Encoded malicious code 187 if (preg_match('/base64\s*[,;]/i', $file_content)) { 188 $file['error'] = __('SVG security check failed: Base64 encoding not allowed.', 'advanced-settings'); 189 return $file; 190 } 191 192 // Reset libxml state 193 libxml_disable_entity_loader($entity_loader_state); 194 libxml_clear_errors(); 195 196 return $file; 197 }); 198 }, 199 'priority' => 30, 200 ]); 201 202 203 204 advset_register_feature([ 205 'id' => 'editing.image.downsize_on_upload', 206 'category' => 'editing', 207 'ui_config' => fn() => [ 208 'tags' => [ 209 __('Editing', 'advanced-settings'), 210 __('Media', 'advanced-settings'), 211 __('Images', 'advanced-settings'), 212 __('Frontend', 'advanced-settings'), 213 __('Performance', 'advanced-settings'), 214 ], 215 'fields' => [ 216 'enable' => [ 217 'type' => 'toggle', 218 'label' => __('Downsize images on upload', 'advanced-settings'), 219 ], 220 'max_width' => [ 221 'type' => 'number', 222 'label' => __('Max width', 'advanced-settings'), 223 'description' => __('Empty or 0 means no limit.', 'advanced-settings'), 224 'min' => 0, 225 'visible' => ['enable' => true], 226 ], 227 'max_height' => [ 228 'type' => 'number', 229 'label' => __('Max height', 'advanced-settings'), 230 'description' => __('Empty or 0 means no limit.', 'advanced-settings'), 231 'min' => 0, 232 'visible' => ['enable' => true], 233 ], 234 ] 235 ], 236 'handler_cleanup' => function($settings) { 237 return empty($settings['enable']) ? null : $settings; 238 }, 239 'execution_handler' => function($settings) { 240 add_action('wp_handle_upload', function($upload) use($settings) { 241 $file_path = $upload['file']; 242 $image_info = getimagesize($file_path); 243 244 if (!$image_info) return $upload; 245 246 list($width, $height, $type) = $image_info; 247 248 $max_width = ((int) $settings['max_width']) ?? null; 249 $max_height = ((int) $settings['max_height']) ?? null; 250 251 if (($max_width === null || $width <= $max_width) && ($max_height === null || $height <= $max_height)) { 252 return $upload; // nothig to do 253 } 254 255 $editor = wp_get_image_editor($file_path); 256 if (is_wp_error($editor)) return $upload; 257 258 $editor->resize($max_width, $max_height, false); 259 $editor->save($file_path); // overwrites original 260 261 return $upload; 262 }); 263 }, 264 'priority' => 40, 265 ]); 266 267 268 269 advset_register_feature([ 14 270 'id' => 'editing.image.jpeg_quality', 15 271 'category' => 'editing', 16 272 'ui_config' => fn() => [ 273 'tags' => [ 274 __('Editing', 'advanced-settings'), 275 __('Media', 'advanced-settings'), 276 __('Images', 'advanced-settings'), 277 __('Frontend', 'advanced-settings'), 278 __('Performance', 'advanced-settings'), 279 ], 17 280 'fields' => [ 18 281 'jpeg_quality' => [ … … 33 296 }); 34 297 }, 35 'priority' => 20, 36 ]); 37 38 39 40 advset_register_feature([ 41 'id' => 'editing.image.downsize_on_upload', 42 'category' => 'editing', 43 'ui_config' => fn() => [ 44 'fields' => [ 45 'enable' => [ 46 'type' => 'toggle', 47 'label' => __('Downsize images on upload', 'advanced-settings'), 48 ], 49 'max_width' => [ 50 'type' => 'number', 51 'label' => __('Max width', 'advanced-settings'), 52 'description' => __('Empty or 0 means no limit.', 'advanced-settings'), 53 'min' => 0, 54 'visible' => ['enable' => true], 55 ], 56 'max_height' => [ 57 'type' => 'number', 58 'label' => __('Max height', 'advanced-settings'), 59 'description' => __('Empty or 0 means no limit.', 'advanced-settings'), 60 'min' => 0, 61 'visible' => ['enable' => true], 62 ], 63 ] 64 ], 65 'handler_cleanup' => function($settings) { 66 return empty($settings['enable']) ? null : $settings; 67 }, 68 'execution_handler' => function($settings) { 69 add_action('wp_handle_upload', function($upload) use($settings) { 70 $file_path = $upload['file']; 71 $image_info = getimagesize($file_path); 72 73 if (!$image_info) return $upload; 74 75 list($width, $height, $type) = $image_info; 76 77 $max_width = ((int) $settings['max_width']) ?? null; 78 $max_height = ((int) $settings['max_height']) ?? null; 79 80 if (($max_width === null || $width <= $max_width) && ($max_height === null || $height <= $max_height)) { 81 return $upload; // nothig to do 82 } 83 84 $editor = wp_get_image_editor($file_path); 85 if (is_wp_error($editor)) return $upload; 86 87 $editor->resize($max_width, $max_height, false); 88 $editor->save($file_path); // overwrites original 89 90 return $upload; 91 }); 92 }, 93 'priority' => 20, 94 ]); 95 96 298 'priority' => 50, 299 ]); 300 301 302 303 advset_register_feature([ 304 'id' => 'editing.thumbnails.enable_support', 305 'category' => 'editing', 306 'ui_config' => fn() => [ 307 'tags' => [ 308 __('Editing', 'advanced-settings'), 309 __('Frontend', 'advanced-settings'), 310 __('Content', 'advanced-settings'), 311 __('Images', 'advanced-settings'), 312 __('Media', 'advanced-settings'), 313 ], 314 'fields' => [ 315 'enable' => [ 316 'type' => 'toggle', 317 'label' => __('Add thumbnail support', 'advanced-settings'), 318 'disabled' => !ADVSET_THUMBS, 319 'description' => ADVSET_THUMBS 320 ? '' 321 : __('Already supported by current theme', 'advanced-settings'), 322 ], 323 ] 324 ], 325 'execution_handler' => function() { 326 add_action('after_setup_theme', function (){ 327 add_theme_support( 'post-thumbnails' ); 328 }); 329 }, 330 'priority' => 60, 331 ]); 332 define( 'ADVSET_THUMBS', !current_theme_supports('post-thumbnails') ); 333 334 335 336 advset_register_feature([ 337 'id' => 'editing.thumbnails.auto_from_first_image', 338 'category' => 'editing', 339 'ui_config' => fn() => [ 340 'tags' => [ 341 __('Editing', 'advanced-settings'), 342 __('Frontend', 'advanced-settings'), 343 __('Content', 'advanced-settings'), 344 __('Images', 'advanced-settings'), 345 __('Media', 'advanced-settings'), 346 __('Automations', 'advanced-settings'), 347 ], 348 'fields' => [ 349 'enable' => [ 350 'type' => 'toggle', 351 'label' => __('Automatically generate the Post Thumbnail', 'advanced-settings'), 352 'description' => __('from the first image in post', 'advanced-settings'), 353 ], 354 ] 355 ], 356 'execution_handler' => function() { 357 require_once ADVSET_DIR . '/feature-setup/features/includes/frontend.auto_thumbs.php'; 358 add_action('transition_post_status', 'advset__feature__auto_thumbs', 10, 3); 359 }, 360 'priority' => 70, 361 ]); 362 363 -
advanced-settings/trunk/feature-setup/features/frontend.php
r3281733 r3323103 12 12 13 13 advset_register_feature([ 14 'id' => 'frontend.meta.facebook_og_metas', 15 'category' => 'frontend', 16 'ui_config' => fn() => [ 17 'fields' => [ 18 'enable' => [ 19 'type' => 'toggle', 20 'label' => __('Enable Facebook Open Graph Meta Tags', 'advanced-settings'), 14 'id' => 'frontend.http_headers.remove_php_version', 15 'category' => 'frontend', 16 'ui_config' => fn() => [ 17 'tags' => [ 18 __('Frontend', 'advanced-settings'), 19 __('HTTP', 'advanced-settings'), 20 __('Security', 'advanced-settings'), 21 __('Cleanup', 'advanced-settings'), 22 ], 23 'fields' => [ 24 'enable' => [ 25 'type' => 'toggle', 26 'label' => __('Remove PHP version from HTTP headers', 'advanced-settings'), 27 'description' => __('Removes the PHP version from the HTTP headers of the website', 'advanced-settings'), 28 ], 29 ] 30 ], 31 'execution_handler' => function() { 32 header_remove('X-Powered-By'); 33 }, 34 'priority' => 10, 35 ]); 36 37 38 39 advset_register_feature([ 40 'id' => 'frontend.http_headers.add_security_headers', 41 'category' => 'frontend', 42 'ui_config' => fn() => [ 43 'tags' => [ 44 __('Frontend', 'advanced-settings'), 45 __('HTTP', 'advanced-settings'), 46 __('Security', 'advanced-settings'), 47 ], 48 'fields' => [ 49 'enable' => [ 50 'type' => 'toggle', 51 'label' => __('Add security headers', 'advanced-settings'), 52 /* translators: %s is a link to securityheaders.com */ 53 'descriptionHtml' => sprintf(__('Adds various security headers to HTTP responses. You can check your website\'s security headers with %s.', 'advanced-settings'), '<a href="https://securityheaders.com/?q=' . rawurlencode(get_home_url()) . '&hide=on&followRedirects=on" target="_blank">securityheaders.com</a>'), 54 ], 55 'info' => [ 56 'type' => 'info', 57 'label' => __('Caution:', 'advanced-settings'), 58 'description' => __('If you integrate external services into your website or your website requires access to browser features like camera, microphone, geolocation, or other device sensors, the security headers may be set too strictly. In this case, simply disable this feature. You can implement customized headers via code if necessary.', 'advanced-settings'), 59 'visible' => ['enable' => true] 21 60 ], 22 61 ] … … 24 63 'execution_handler' => function() { 25 64 if ( advset_is_admin_area() ) return; 26 27 add_action('wp_head', function() { 28 global $post; 29 if (is_single() || is_page()) { ?> 30 <meta property="og:title" content="<?php single_post_title(''); ?>" /> 31 <meta property="og:description" content="<?php echo strip_tags(get_the_excerpt($post->ID)); ?>" /> 32 <meta property="og:type" content="article" /> 33 <meta property="og:image" content="<?php if (function_exists('wp_get_attachment_thumb_url')) {echo wp_get_attachment_url(get_post_thumbnail_id($post->ID)); }?>" /> 34 <?php } 35 }); 36 }, 37 'priority' => 10, 65 add_action('send_headers', function() { 66 header('X-Content-Type-Options: nosniff'); 67 header('X-Frame-Options: SAMEORIGIN'); 68 header('X-XSS-Protection: 1; mode=block'); 69 header('Referrer-Policy: strict-origin-when-cross-origin'); 70 header('Content-Security-Policy: object-src \'none\';'); 71 header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload'); 72 header('Permissions-Policy: accelerometer=(),camera=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),payment=(),usb=(),interest-cohort=()'); 73 }); 74 }, 75 'priority' => 20, 38 76 ]); 39 77 … … 44 82 'category' => 'frontend', 45 83 'ui_config' => fn() => [ 84 'tags' => [ 85 __('Frontend', 'advanced-settings'), 86 __('Meta', 'advanced-settings'), 87 __('Favicon', 'advanced-settings'), 88 __('SEO', 'advanced-settings'), 89 ], 46 90 'fields' => [ 47 91 'enable' => [ … … 66 110 }); 67 111 }, 68 'priority' => 10, 112 'priority' => 30, 113 ]); 114 115 116 117 advset_register_feature([ 118 'id' => 'frontend.meta.facebook_og_metas', 119 'category' => 'frontend', 120 'ui_config' => fn() => [ 121 'tags' => [ 122 __('Frontend', 'advanced-settings'), 123 __('Meta', 'advanced-settings'), 124 __('SEO', 'advanced-settings'), 125 ], 126 'fields' => [ 127 'enable' => [ 128 'type' => 'toggle', 129 'label' => __('Enable Facebook Open Graph Meta Tags', 'advanced-settings'), 130 ], 131 ] 132 ], 133 'execution_handler' => function() { 134 if ( advset_is_admin_area() ) return; 135 136 add_action('wp_head', function() { 137 global $post; 138 if (is_single() || is_page()) { ?> 139 <meta property="og:title" content="<?php single_post_title(''); ?>" /> 140 <meta property="og:description" content="<?php echo strip_tags(get_the_excerpt($post->ID)); ?>" /> 141 <meta property="og:type" content="article" /> 142 <meta property="og:image" content="<?php if (function_exists('wp_get_attachment_thumb_url')) {echo wp_get_attachment_url(get_post_thumbnail_id($post->ID)); }?>" /> 143 <?php } 144 }); 145 }, 146 'priority' => 40, 69 147 ]); 70 148 … … 75 153 'category' => 'frontend', 76 154 'ui_config' => fn() => [ 155 'tags' => [ 156 __('Frontend', 'advanced-settings'), 157 __('Meta', 'advanced-settings'), 158 __('Cleanup', 'advanced-settings'), 159 ], 77 160 'fields' => [ 78 161 'enable' => [ … … 86 169 remove_action( 'wp_head', 'wp_shortlink_wp_head'); 87 170 }, 88 'priority' => 10,171 'priority' => 50, 89 172 ]); 90 173 … … 95 178 'category' => 'frontend', 96 179 'ui_config' => fn() => [ 180 'tags' => [ 181 __('Frontend', 'advanced-settings'), 182 __('Meta', 'advanced-settings'), 183 __('Cleanup', 'advanced-settings'), 184 ], 97 185 'fields' => [ 98 186 'enable' => [ … … 107 195 remove_action( 'wp_head', 'rsd_link'); 108 196 }, 109 'priority' => 10,197 'priority' => 60, 110 198 ]); 111 199 … … 116 204 'category' => 'frontend', 117 205 'ui_config' => fn() => [ 206 'tags' => [ 207 __('Frontend', 'advanced-settings'), 208 __('Meta', 'advanced-settings'), 209 __('Security', 'advanced-settings'), 210 __('Cleanup', 'advanced-settings'), 211 ], 118 212 'fields' => [ 119 213 'enable' => [ 120 214 'type' => 'toggle', 121 215 'label' => __('Remove generator meta tag', 'advanced-settings'), 216 'description' => __('Removes the WordPress version from the head section of the website', 'advanced-settings'), 122 217 ], 123 218 ] … … 127 222 remove_action( 'wp_head', 'wp_generator'); 128 223 }, 129 'priority' => 10,224 'priority' => 70, 130 225 ]); 131 226 … … 136 231 'category' => 'frontend', 137 232 'ui_config' => fn() => [ 233 'tags' => [ 234 __('Frontend', 'advanced-settings'), 235 __('Meta', 'advanced-settings'), 236 __('SEO', 'advanced-settings'), 237 ], 138 238 'fields' => [ 139 239 'enable' => [ … … 178 278 }); 179 279 }, 180 'priority' => 10,280 'priority' => 80, 181 281 ]); 182 282 … … 187 287 'category' => 'frontend', 188 288 'ui_config' => fn() => [ 289 'tags' => [ 290 __('Frontend', 'advanced-settings'), 291 __('Content', 'advanced-settings'), 292 __('Security', 'advanced-settings'), 293 __('Cleanup', 'advanced-settings'), 294 ], 189 295 'fields' => [ 190 296 'enable' => [ … … 210 316 }, 10, 2 ); 211 317 }, 212 'priority' => 20, 318 'priority' => 90, 319 ]); 320 321 322 323 advset_register_feature([ 324 'id' => 'frontend.title.improve_format', 325 'category' => 'frontend', 326 'deprecated' => true, 327 'ui_config' => fn() => [ 328 'tags' => [ 329 __('Developer', 'advanced-settings'), 330 __('Frontend', 'advanced-settings'), 331 __('Content', 'advanced-settings'), 332 __('Automations', 'advanced-settings'), 333 ], 334 'fields' => [ 335 'enable' => [ 336 'type' => 'toggle', 337 'label' => __('Adjust the wp_title function', 'advanced-settings'), 338 ], 339 ] 340 ], 341 'execution_handler' => function() { 342 add_filter('wp_title', function($title, $sep) { 343 global $paged, $page; 344 345 if ( is_feed() ) 346 return $title; 347 348 // Add the site name. 349 $title .= get_bloginfo( 'name' ); 350 351 // Add the site description for the home/front page. 352 $site_description = get_bloginfo( 'description', 'display' ); 353 if ( $site_description && ( is_home() || is_front_page() ) ) 354 $title = "$title $sep $site_description"; 355 356 // Add a page number if necessary. 357 if ( $paged >= 2 || $page >= 2 ) 358 $title = "$title $sep " . sprintf( __( 'Page %s', 'responsive' ), max( $paged, $page ) ); 359 360 return $title; 361 }, 10, 2); 362 }, 363 'priority' => 100, 213 364 ]); 214 365 … … 219 370 'category' => 'frontend', 220 371 'ui_config' => fn() => [ 372 'tags' => [ 373 __('Editing', 'advanced-settings'), 374 __('Frontend', 'advanced-settings'), 375 __('Content', 'advanced-settings'), 376 __('Cleanup', 'advanced-settings'), 377 __('Automations', 'advanced-settings'), 378 ], 221 379 'fields' => [ 222 380 'enable' => [ … … 230 388 add_filter( 'run_wptexturize', '__return_false' ); 231 389 }, 232 'priority' => 10, 233 ]); 234 235 236 237 advset_register_feature([ 238 'id' => 'frontend.thumbnails.enable_support', 239 'category' => 'frontend', 240 'ui_config' => fn() => [ 241 'fields' => [ 242 'enable' => [ 243 'type' => 'toggle', 244 'label' => __('Add thumbnail support', 'advanced-settings'), 245 'disabled' => !ADVSET_THUMBS, 246 'description' => ADVSET_THUMBS 247 ? '' 248 : __('Already supported by current theme', 'advanced-settings'), 249 ], 250 ] 251 ], 252 'execution_handler' => function() { 253 add_action('after_setup_theme', function (){ 254 add_theme_support( 'post-thumbnails' ); 255 }); 256 }, 257 'priority' => 30, 258 ]); 259 define( 'ADVSET_THUMBS', !current_theme_supports('post-thumbnails') ); 260 261 262 263 advset_register_feature([ 264 'id' => 'frontend.thumbnails.auto_from_first_image', 265 'category' => 'frontend', 266 'ui_config' => fn() => [ 267 'fields' => [ 268 'enable' => [ 269 'type' => 'toggle', 270 'label' => __('Automatically generate the Post Thumbnail', 'advanced-settings'), 271 'description' => __('from the first image in post', 'advanced-settings'), 272 ], 273 ] 274 ], 275 'execution_handler' => function() { 276 require_once ADVSET_DIR . '/feature-setup/features/includes/frontend.auto_thumbs.php'; 277 add_action('transition_post_status', 'advset__feature__auto_thumbs', 10, 3); 278 }, 390 'priority' => 110, 391 ]); 392 393 394 395 advset_register_feature([ 396 'id' => 'frontend.oembed.disable', 397 'category' => 'frontend', 398 'ui_config' => fn() => [ 399 'tags' => [ 400 __('Editing', 'advanced-settings'), 401 __('Frontend', 'advanced-settings'), 402 __('Content', 'advanced-settings'), 403 __('Security', 'advanced-settings'), 404 __('Cleanup', 'advanced-settings'), 405 __('GDPR', 'advanced-settings'), 406 __('Performance', 'advanced-settings'), 407 __('Automations', 'advanced-settings'), 408 ], 409 'fields' => [ 410 'enable' => [ 411 'type' => 'toggle', 412 'label' => __('Disable auto-embed of external content', 'advanced-settings'), 413 'description' => __('Disables WordPress oEmbed, which automatically converts URLs into embedded content.', 'advanced-settings'), 414 ], 415 ] 416 ], 417 'execution_handler' => function() { 418 remove_action('wp_head', 'wp_oembed_add_discovery_links'); 419 remove_action('wp_head', 'wp_oembed_add_host_js'); 420 remove_action('wp_head', 'rest_output_link_wp_head'); 421 remove_action('rest_api_init', 'wp_oembed_register_route'); 422 remove_filter('the_content', [$GLOBALS['wp_embed'], 'autoembed'], 8); 423 remove_filter('oembed_dataparse', 'wp_filter_oembed_result', 10); 424 add_filter('embed_oembed_discover', '__return_false'); 425 }, 426 'priority' => 120, 279 427 ]); 280 428 … … 285 433 'category' => 'frontend', 286 434 'ui_config' => fn() => [ 435 'tags' => [ 436 __('Editing', 'advanced-settings'), 437 __('Frontend', 'advanced-settings'), 438 __('Content', 'advanced-settings'), 439 __('Cleanup', 'advanced-settings'), 440 __('Automations', 'advanced-settings'), 441 ], 287 442 'fields' => [ 288 443 'enable' => [ … … 308 463 }); 309 464 }, 465 'priority' => 130, 310 466 ]); 311 467 … … 316 472 'category' => 'frontend', 317 473 'ui_config' => fn() => [ 474 'tags' => [ 475 __('Frontend', 'advanced-settings'), 476 __('Content', 'advanced-settings'), 477 __('SEO', 'advanced-settings'), 478 __('Cleanup', 'advanced-settings'), 479 __('Automations', 'advanced-settings'), 480 ], 318 481 'fields' => [ 319 482 'enable' => [ … … 339 502 }); 340 503 }, 504 'priority' => 140, 341 505 ]); 342 506 … … 347 511 'category' => 'frontend', 348 512 'ui_config' => fn() => [ 513 'tags' => [ 514 __('Frontend', 'advanced-settings'), 515 __('Content', 'advanced-settings'), 516 __('Comments', 'advanced-settings'), 517 __('Automations', 'advanced-settings'), 518 __('Cleanup', 'advanced-settings'), 519 ], 349 520 'fields' => [ 350 521 'enable' => [ … … 367 538 }, 10); 368 539 }, 369 'priority' => 40, 540 'priority' => 150, 541 ]); 542 543 544 545 advset_register_feature([ 546 'id' => 'frontend.post.show_author_bio', 547 'category' => 'frontend', 548 'deprecated' => true, 549 'ui_config' => fn() => [ 550 'tags' => [ 551 __('Frontend', 'advanced-settings'), 552 __('Content', 'advanced-settings'), 553 __('Automations', 'advanced-settings'), 554 ], 555 'fields' => [ 556 'enable' => [ 557 'type' => 'toggle', 558 'label' => __('Insert author bio in each post', 'advanced-settings'), 559 ], 560 ] 561 ], 562 'execution_handler' => function() { 563 add_filter('the_content', function($content='') { 564 return $content.' <div id="entry-author-info"> 565 <div id="author-avatar"> 566 '. get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'author_bio_avatar_size', 100 ) ) .' 567 </div> 568 <div id="author-description"> 569 <h2>'. sprintf( __( 'About %s' ), get_the_author() ) .'</h2> 570 '. get_the_author_meta( 'description' ) .' 571 <div id="author-link"> 572 <a href="'. get_author_posts_url( get_the_author_meta( 'ID' ) ) .'"> 573 '. sprintf( __( 'View all posts by %s <span class="meta-nav">→</span>' ), get_the_author() ) .' 574 </a> 575 </div> 576 </div> 577 </div>'; 578 }); 579 }, 580 'priority' => 160, 581 ]); 582 583 584 585 advset_register_feature([ 586 'id' => 'frontend.user.allow_html_bio', 587 'category' => 'frontend', 588 'deprecated' => true, 589 'ui_config' => fn() => [ 590 'tags' => [ 591 __('Admin', 'advanced-settings'), 592 __('Frontend', 'advanced-settings'), 593 __('Content', 'advanced-settings'), 594 ], 595 'fields' => [ 596 'enable' => [ 597 'type' => 'toggle', 598 'label' => __('Allow complex HTML in user profile description', 'advanced-settings'), 599 ], 600 ] 601 ], 602 'execution_handler' => function() { 603 remove_filter('pre_user_description', 'wp_filter_kses'); 604 }, 605 'priority' => 170, 370 606 ]); 371 607 … … 376 612 'category' => 'frontend', 377 613 'ui_config' => fn() => [ 614 'tags' => [ 615 __('Frontend', 'advanced-settings'), 616 __('Content', 'advanced-settings'), 617 __('Security', 'advanced-settings'), 618 __('Automations', 'advanced-settings'), 619 ], 378 620 'fields' => [ 379 621 'enable' => [ … … 480 722 }); 481 723 }, 482 'priority' => 1 0,483 ]); 484 485 486 487 advset_register_feature([ 488 'id' => 'frontend. title.improve_format',724 'priority' => 180, 725 ]); 726 727 728 729 advset_register_feature([ 730 'id' => 'frontend.analytics.google', 489 731 'category' => 'frontend', 490 732 'deprecated' => true, 491 733 'ui_config' => fn() => [ 492 'fields' => [ 493 'enable' => [ 494 'type' => 'toggle', 495 'label' => __('Adjust the wp_title function', 'advanced-settings'), 496 ], 497 ] 498 ], 499 'execution_handler' => function() { 500 add_filter('wp_title', function($title, $sep) { 501 global $paged, $page; 502 503 if ( is_feed() ) 504 return $title; 505 506 // Add the site name. 507 $title .= get_bloginfo( 'name' ); 508 509 // Add the site description for the home/front page. 510 $site_description = get_bloginfo( 'description', 'display' ); 511 if ( $site_description && ( is_home() || is_front_page() ) ) 512 $title = "$title $sep $site_description"; 513 514 // Add a page number if necessary. 515 if ( $paged >= 2 || $page >= 2 ) 516 $title = "$title $sep " . sprintf( __( 'Page %s', 'responsive' ), max( $paged, $page ) ); 517 518 return $title; 519 }, 10, 2); 520 }, 521 'priority' => 10, 522 ]); 523 524 525 526 advset_register_feature([ 527 'id' => 'frontend.post.show_author_bio', 528 'category' => 'frontend', 529 'deprecated' => true, 530 'ui_config' => fn() => [ 531 'fields' => [ 532 'enable' => [ 533 'type' => 'toggle', 534 'label' => __('Insert author bio in each post', 'advanced-settings'), 535 ], 536 ] 537 ], 538 'execution_handler' => function() { 539 add_filter('the_content', function($content='') { 540 return $content.' <div id="entry-author-info"> 541 <div id="author-avatar"> 542 '. get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'author_bio_avatar_size', 100 ) ) .' 543 </div> 544 <div id="author-description"> 545 <h2>'. sprintf( __( 'About %s' ), get_the_author() ) .'</h2> 546 '. get_the_author_meta( 'description' ) .' 547 <div id="author-link"> 548 <a href="'. get_author_posts_url( get_the_author_meta( 'ID' ) ) .'"> 549 '. sprintf( __( 'View all posts by %s <span class="meta-nav">→</span>' ), get_the_author() ) .' 550 </a> 551 </div> 552 </div> 553 </div>'; 554 }); 555 }, 556 'priority' => 10, 557 ]); 558 559 560 561 advset_register_feature([ 562 'id' => 'frontend.user.allow_html_bio', 563 'category' => 'frontend', 564 'deprecated' => true, 565 'ui_config' => fn() => [ 566 'fields' => [ 567 'enable' => [ 568 'type' => 'toggle', 569 'label' => __('Allow complex HTML in user profile description', 'advanced-settings'), 570 ], 571 ] 572 ], 573 'execution_handler' => function() { 574 remove_filter('pre_user_description', 'wp_filter_kses'); 575 }, 576 'priority' => 10, 577 ]); 578 579 580 581 advset_register_feature([ 582 'id' => 'frontend.analytics.google', 583 'category' => 'frontend', 584 'deprecated' => true, 585 'ui_config' => fn() => [ 734 'tags' => [ 735 __('Frontend', 'advanced-settings'), 736 __('Meta', 'advanced-settings'), 737 __('GDPR', 'advanced-settings'), 738 ], 586 739 'fields' => [ 587 740 'enable' => [ … … 614 767 }); 615 768 }, 616 'priority' => 1 0,769 'priority' => 190, 617 770 ]); 618 771 … … 624 777 'deprecated' => true, 625 778 'ui_config' => fn() => [ 779 'tags' => [ 780 __('Frontend', 'advanced-settings'), 781 __('Meta', 'advanced-settings'), 782 ], 626 783 'fields' => [ 627 784 'enable' => [ … … 655 812 }, 10, 2 ); 656 813 }, 657 'priority' => 10,814 'priority' => 200, 658 815 ]); 659 816 … … 664 821 'category' => 'frontend', 665 822 'ui_config' => fn() => [ 823 'tags' => [ 824 __('Frontend', 'advanced-settings'), 825 __('HTML', 'advanced-settings'), 826 __('Performance', 'advanced-settings'), 827 __('Automations', 'advanced-settings'), 828 ], 666 829 'fields' => [ 667 830 'enable' => [ … … 678 841 }); 679 842 }, 680 'priority' => 10,843 'priority' => 210, 681 844 ]); 682 845 … … 687 850 'category' => 'frontend', 688 851 'ui_config' => fn() => [ 852 'tags' => [ 853 __('Frontend', 'advanced-settings'), 854 __('HTML', 'advanced-settings'), 855 __('Performance', 'advanced-settings'), 856 __('Cleanup', 'advanced-settings'), 857 __('Automations', 'advanced-settings'), 858 ], 689 859 'fields' => [ 690 860 'enable' => [ … … 701 871 }); 702 872 }, 703 'priority' => 10,873 'priority' => 220, 704 874 ]); 705 875 … … 710 880 'category' => 'frontend', 711 881 'ui_config' => fn() => [ 882 'tags' => [ 883 __('Frontend', 'advanced-settings'), 884 __('Content', 'advanced-settings'), 885 __('Emojis', 'advanced-settings'), 886 __('Automations', 'advanced-settings'), 887 __('Cleanup', 'advanced-settings'), 888 __('GDPR', 'advanced-settings'), 889 ], 712 890 'fields' => [ 713 891 'enable' => [ … … 728 906 add_filter('emoji_svg_url', '__return_false'); 729 907 }, 730 'priority' => 10,731 ]); 732 733 908 'priority' => 230, 909 ]); 910 911 -
advanced-settings/trunk/feature-setup/features/system.php
r3306579 r3323103 15 15 'category' => 'system', 16 16 'ui_config' => fn() => [ 17 'tags' => [ 18 __('Admin', 'advanced-settings'), 19 __('Frontend', 'advanced-settings'), 20 __('Meta', 'advanced-settings'), 21 __('Favicon', 'advanced-settings'), 22 __('Cleanup', 'advanced-settings'), 23 __('Branding', 'advanced-settings'), 24 ], 17 25 'fields' => [ 18 26 'enable' => [ … … 40 48 'category' => 'system', 41 49 'ui_config' => fn() => [ 50 'tags' => [ 51 __('System', 'advanced-settings'), 52 __('Admin', 'advanced-settings'), 53 __('Frontend', 'advanced-settings'), 54 __('Cleanup', 'advanced-settings'), 55 __('Security', 'advanced-settings'), 56 __('Comments', 'advanced-settings'), 57 ], 42 58 'fields' => [ 43 59 'enable' => [ … … 60 76 } ); 61 77 }, 62 'priority' => 10,63 ]);64 65 66 67 advset_register_feature([68 'id' => 'system.posts.disable_autosave',69 'category' => 'system',70 'ui_config' => fn() => [71 'fields' => [72 'enable' => [73 'type' => 'toggle',74 'label' => __('Disable auto save', 'advanced-settings'),75 ],76 ]77 ],78 'execution_handler' => function() {79 define('AUTOSAVE_INTERVAL', 60 * 60 * 24 * 365 * 100); // save interval => 100 years80 },81 78 'priority' => 20, 82 79 ]); … … 85 82 86 83 advset_register_feature([ 84 'id' => 'system.xmlrpc.disable', 85 'category' => 'system', 86 'ui_config' => fn() => [ 87 'tags' => [ 88 __('System', 'advanced-settings'), 89 __('Security', 'advanced-settings'), 90 __('Performance', 'advanced-settings'), 91 __('Cleanup', 'advanced-settings'), 92 ], 93 'fields' => [ 94 'enable' => [ 95 'type' => 'toggle', 96 'label' => __('Disable XML-RPC', 'advanced-settings'), 97 'description' => __('Disables XML-RPC functionality for security', 'advanced-settings'), 98 ], 99 ] 100 ], 101 'execution_handler' => function() { 102 add_filter('xmlrpc_enabled', '__return_false'); 103 }, 104 'priority' => 30, 105 ]); 106 107 108 109 advset_register_feature([ 110 'id' => 'system.rest.disable_public', 111 'category' => 'system', 112 'ui_config' => fn() => [ 113 'tags' => [ 114 __('System', 'advanced-settings'), 115 __('Security', 'advanced-settings'), 116 __('Performance', 'advanced-settings'), 117 __('Cleanup', 'advanced-settings'), 118 ], 119 'fields' => [ 120 'enable' => [ 121 'type' => 'toggle', 122 'label' => __('Disable public REST API', 'advanced-settings'), 123 'description' => __('Disables REST API access for non-authenticated users', 'advanced-settings'), 124 ], 125 ] 126 ], 127 'execution_handler' => function() { 128 add_filter('rest_authentication_errors', function($result) { 129 if (!empty($result)) { 130 return $result; 131 } 132 if (!is_user_logged_in()) { 133 return new WP_Error('rest_forbidden', 'REST API restricted to authenticated users.', ['status' => 401]); 134 } 135 return $result; 136 }); 137 }, 138 'priority' => 40, 139 ]); 140 141 142 143 advset_register_feature([ 87 144 'id' => 'system.updates.skip_bundled_themes', 88 145 'category' => 'system', 89 146 'ui_config' => fn() => [ 147 'tags' => [ 148 __('System', 'advanced-settings'), 149 __('Updates', 'advanced-settings'), 150 __('Cleanup', 'advanced-settings'), 151 ], 90 152 'fields' => [ 91 153 'enable' => [ … … 130 192 } 131 193 }, 132 'priority' => 20,194 'priority' => 50, 133 195 ]); 134 196 … … 139 201 'category' => 'system', 140 202 'ui_config' => fn() => [ 203 'tags' => [ 204 __('System', 'advanced-settings'), 205 __('Updates', 'advanced-settings'), 206 __('Notifications', 'advanced-settings'), 207 __('Emails', 'advanced-settings'), 208 ], 141 209 'fields' => [ 142 210 'enable' => [ … … 150 218 add_filter('auto_core_update_send_email', '__return_false'); 151 219 }, 152 'priority' => 20,220 'priority' => 60, 153 221 ]); 154 222 … … 159 227 'category' => 'system', 160 228 'ui_config' => fn() => [ 229 'tags' => [ 230 __('System', 'advanced-settings'), 231 __('Updates', 'advanced-settings'), 232 __('Notifications', 'advanced-settings'), 233 __('Emails', 'advanced-settings'), 234 ], 161 235 'fields' => [ 162 236 'enable' => [ … … 170 244 add_filter('auto_plugin_update_send_email', '__return_false'); 171 245 }, 172 'priority' => 30,246 'priority' => 70, 173 247 ]); 174 248 … … 179 253 'category' => 'system', 180 254 'ui_config' => fn() => [ 255 'tags' => [ 256 __('System', 'advanced-settings'), 257 __('Updates', 'advanced-settings'), 258 __('Notifications', 'advanced-settings'), 259 __('Emails', 'advanced-settings'), 260 ], 181 261 'fields' => [ 182 262 'enable' => [ … … 190 270 add_filter('auto_theme_update_send_email', '__return_false'); 191 271 }, 192 'priority' => 40,193 ]); 194 195 272 'priority' => 80, 273 ]); 274 275 -
advanced-settings/trunk/migrations/3.x.x.php
r3281733 r3323103 152 152 }, 153 153 154 '3.1.0' => function() { 155 $settings = get_option('advanced_settings_settings', []); 156 157 // Add admin bar logo to branding feature 158 if ( !empty($settings['dashboard.adminbar.custom_logo']['url']) ) { 159 $settings['dashboard.branding.customize'] = [ 160 'enable' => true, 161 'admin_bar_logo' => $settings['dashboard.adminbar.custom_logo']['url'], 162 ]; 163 } 164 165 // Remove old admin bar logo option 166 unset($settings['dashboard.adminbar.custom_logo']); 167 168 // Move old auto save setting to editing category 169 if ( !empty($settings['system.posts.disable_autosave']) ) { 170 $settings['editing.posts.disable_autosave'] = $settings['system.posts.disable_autosave']; 171 unset($settings['system.posts.disable_autosave']); 172 } 173 174 // Move old auto thumbs setting to editing category 175 if ( !empty($settings['frontend.thumbnails.auto_from_first_image']) ) { 176 $settings['editing.thumbnails.auto_from_first_image'] = $settings['frontend.thumbnails.auto_from_first_image']; 177 unset($settings['frontend.thumbnails.auto_from_first_image']); 178 } 179 180 // Move old thumbs setting to editing category 181 if ( !empty($settings['frontend.thumbnails.enable_support']) ) { 182 $settings['editing.thumbnails.enable_support'] = $settings['frontend.thumbnails.enable_support']; 183 unset($settings['frontend.thumbnails.enable_support']); 184 } 185 186 // Rename dashboard features to adminarea features 187 foreach ($settings as $feature_id => $feature_settings) { 188 if ( strpos($feature_id, 'dashboard.') === 0 ) { 189 $settings['adminarea.' . substr($feature_id, 10)] = $feature_settings; 190 unset($settings[$feature_id]); 191 } 192 } 193 194 // Update settings 195 update_option('advanced_settings_settings', $settings); 196 }, 197 154 198 ]; -
advanced-settings/trunk/readme.txt
r3308393 r3323103 8 8 Requires at least: 5.0.0 9 9 Tested up to: 6.8 10 Stable tag: 3. 0.210 Stable tag: 3.1.0 11 11 License: GPLv3 or later 12 12 License URI: http://www.gnu.org/licenses/gpl-3.0.html … … 26 26 [→ details in FAQ](https://wordpress.org/plugins/advanced-settings#how%20is%20the%20security%20of%20the%20plugin%20ensured%3F) 27 27 28 **✳️ INFO ABOUT BAD REVIEWS**29 2 bad r eviews occurred in 2017 because outdated PHP versions were used, but can't happen again.28 **✳️ INFO ABOUT THE 2 BAD RATINGS** 29 2 bad ratings occurred in 2017 because outdated PHP versions were used, but can't happen again. 30 30 [→ details in FAQ](https://wordpress.org/plugins/advanced-settings#what%20caused%20the%20two%20bad%20ratings%3F) 31 31 … … 37 37 Advanced Settings 3 was developed to help as many users as possible. If you'd like to see a feature added to this plugin, please let us know. Don't worry, we'll keep the plugin fast and lean; this is a high priority for us. We'll only implement features that don't conflict with this. 38 38 39 = Dashboard=40 41 * Customize dashboard logo39 = Admin Area = 40 41 * Hide the top admin bar for all users in the frontend 42 42 * Hide WordPress update message in dashboard 43 * Hide the top admin bar for all users in the frontend44 43 * Hide the welcome panel in the dashboard 44 * Hide the default widgets in the dashboard 💥 new 45 * Customize the admin area branding 💥 new 46 47 = Frontend = 48 49 * Remove PHP version from HTTP headers 💥 new 50 * Add security HTTP headers 💥 new 51 * Automatically add FavIcon (when favicon.ico, favicon.png or favicon.svg exists in template folder) 52 * Add Facebook Open Graph meta tags 53 * Remove shortlink meta tag 54 * Remove RSD (Weblog Client Link) meta tag 55 * Remove WordPress generator meta tag 56 * Automatically add description meta tag using blog description and post excerpt (SEO) 57 * Disable author pages 58 * Remove wptexturize filter 59 * Disable auto embed of external content 💥 new 60 * Limit excerpt length 61 * Add "Read more" link after excerpt 62 * Remove trackbacks and pingbacks from comment count 63 * Protect email addresses from spam bots 64 * Compress HTML code 65 * Remove HTML comments (except conditional IE comments) 66 * Disable emoji image replacement 67 68 = Editing = 69 70 * Disable posts auto saving 71 * Limit post revisions 💥 new 72 * Allow SVG uploads for admins 💥 new 73 * Downsize images on upload to max size 74 * Set JPEG quality 75 * Add thumbnail support 76 * Automatically generate post thumbnail (from first image in post) 45 77 46 78 = System = … … 48 80 * Hide default WordPress favicon 49 81 * Disable comment system 50 * Disable posts auto saving 82 * Disable XML-RPC 💥 new 83 * Disable public REST API 💥 new 51 84 * Prevent installation of new default WordPress themes during core updates 52 85 * Disable email notifications for core updates 53 86 * Disable email notifications for plugin updates 54 87 * Disable email notifications for theme updates 55 56 = Frontend =57 58 * Disable author pages59 * Automatically add FavIcon (when favicon.ico, favicon.png or favicon.svg exists in template folder)60 * Automatically add description meta tag using blog description and post excerpt (SEO)61 * Remove WordPress generator meta tag62 * Remove RSD (Weblog Client Link) meta tag63 * Remove shortlink meta tag64 * Limit excerpt length65 * Add "Read more" link after excerpt66 * Remove wptexturize filter67 * Remove trackbacks and pingbacks from comment count68 * Compress HTML code69 * Remove HTML comments (except conditional IE comments)70 * Disable author pages71 * Add thumbnail support72 * Automatically generate post thumbnail (from first image in post)73 * Protect email addresses from spam bots74 * Add Facebook Open Graph meta tags75 * Disable emoji image replacement76 77 = Editing =78 79 * Set JPEG quality80 * Downsize images on upload to max size81 88 82 89 = Developer = … … 131 138 132 139 **Detailed answer:** 133 The plugin developer at the time had decided in 2017 to use PHP features that were introduced with PHP 5.4. Support for the previous version, PHP 5.3, had already been officially discontinued by The PHP Group 3 years earlier. It was therefore natural to assume that all websites actually in use had already been converted to PHP 5.4 or newer. Unfortunately, this was not the case for a few of them.134 135 Nowadays, you canspecify in the plugin metadata which PHP version is required as a minimum for the plugin, so that users can only update the plugin if they are using the correct PHP version. While this WordPress feature came too late to prevent the problems and the negative reviews, this problem can fortunately be prevented in the future.136 137 It would be great if you could contribute with your own review to ensure that the ratings reflect the current stateof the plugin.140 The plugin developer at the time had decided in 2017 to use PHP features that were introduced with PHP 5.4. Support for the previous version, PHP 5.3, had already been officially discontinued by The PHP Group 3 years earlier. It was therefore natural to assume that all websites actually in use had already been converted to PHP 5.4 or newer. Unfortunately, this was not the case for a few users. 141 142 Nowadays, WordPress allowes to specify in the plugin metadata which PHP version is required as a minimum for the plugin, so that users can only update the plugin if they are using the correct PHP version. While this WordPress feature came too late to prevent the problems and the negative reviews, this problem can fortunately be prevented in the future. 143 144 It would be great if you could contribute with your own review to ensure that the ratings reflect the quality of the plugin. 138 145 139 146 == Screenshots == … … 144 151 145 152 == Changelog == 153 154 = 3.1.0 - 2025-07-06 = 155 * Added 9 new features (see feature list) 156 * Added tags and tag navigation 146 157 147 158 = 3.0.2 - 2025-06-04 =
Note: See TracChangeset
for help on using the changeset viewer.