| @@ -283,8 +283,12 @@ | ||
| 283 | 283 | 'enable_breadcrumb_category' => true, |
| 284 | 284 | 'enable_breadcrumb_title' => true, |
| 285 | 285 | 'enable_sidebar_cat_list' => true, |
| 286 | 286 | 'enable_print_icon' => true, |
| 287 | + 'print_enable_logo' => false, | |
| 288 | + 'print_logo' => array(), | |
| 289 | + 'print_enable_footer' => false, | |
| 290 | + 'print_footer_text' => '', | |
| 287 | 291 | 'enable_tags' => true, |
| 288 | 292 | 'email_feedback' => true, |
| 289 | 293 | 'feedback_link_text' => __( 'Still stuck? How can we help?', 'betterdocs' ), |
| 290 | 294 | 'reaction_feedback_text' => __( 'Thanks for your feedback', 'betterdocs' ), |
| @@ -729,21 +733,38 @@ | ||
| 729 | 733 | betterdocs()->kbmigration->migrate(); |
| 730 | 734 | } |
| 731 | 735 | $_settings = wp_parse_args( $_normalized_settings, $_old_settings ); |
| 732 | 736 | |
| 733 | - // Check if there are actual changes before saving. | |
| 734 | - // update_option returns false when values serialize identically, which can happen | |
| 735 | - // due to object caching or type normalization even when user made changes. | |
| 736 | - $_has_changes = $_settings != $_old_settings; | |
| 737 | + // Detect whether this save actually changes the effective settings. | |
| 738 | + // | |
| 739 | + // The stored option and the submitted payload are normalized differently: | |
| 740 | + // an optional field can be ABSENT from storage yet arrive as '' (e.g. | |
| 741 | + // Feedback URL), and array fields can be stored empty ( [] ) while their | |
| 742 | + // normalized/default form is non-empty (e.g. Instant Answer's | |
| 743 | + // display_ia_texonomy defaults to ['all']). Comparing the raw arrays | |
| 744 | + // ( $_settings != $_old_settings ) therefore reported a phantom change on | |
| 745 | + // every save, leaving the tab perpetually "dirty" and always toasting | |
| 746 | + // "Changes Saved Successfully." instead of "There are no changes to be | |
| 747 | + // saved." — see WPDevelopers/betterdocs-pro#78. | |
| 748 | + // | |
| 749 | + // Compare like-for-like instead: fill defaults on both sides and run both | |
| 750 | + // through the same normalization, so semantically-equal states (absent vs | |
| 751 | + // '', [] vs ['all'], 'on' vs true) collapse to identical values and only a | |
| 752 | + // real edit registers. This is also more reliable than update_option()'s | |
| 753 | + // return, which is false whenever values serialize identically under object | |
| 754 | + // caching or type coercion even when the user did change something (#49). | |
| 755 | + $_defaults = array_merge( $this->get_default(), $this->get_pro_defaults() ); | |
| 756 | + $_old_normalized = $this->get_normalized_values( wp_parse_args( $_old_settings, $_defaults ), $_defaults ); | |
| 757 | + $_new_normalized = $this->get_normalized_values( wp_parse_args( $_settings, $_defaults ), $_defaults ); | |
| 758 | + $_has_changes = $_new_normalized != $_old_normalized; | |
| 737 | 759 | |
| 738 | 760 | $_saved = $this->database->save( $this->base_key, $_settings ); |
| 739 | 761 | |
| 740 | 762 | do_action_ref_array( 'betterdocs::settings::saved', array( $_saved, $_settings, $_old_settings, &$this ) ); |
| 741 | 763 | |
| 742 | - // Return true if save succeeded OR if there were changes to attempt saving. | |
| 743 | - // This handles cases where update_option returns false due to identical serialization | |
| 744 | - // (e.g., object caching, type coercion during serialization). | |
| 745 | - return $_saved || $_has_changes; | |
| 764 | + // The success / no-changes toast reflects whether the user made a real | |
| 765 | + // change, not update_option()'s (unreliable) return value. | |
| 766 | + return $_has_changes; | |
| 746 | 767 | } |
| 747 | 768 | |
| 748 | 769 | public function views( $hook ) { |
| 749 | 770 | return betterdocs()->views->get( 'admin/settings' ); |
| @@ -1396,8 +1417,44 @@ | ||
| 1396 | 1417 | 'enable_disable_text_active' => true, |
| 1397 | 1418 | 'default' => 1, |
| 1398 | 1419 | 'priority' => 3 |
| 1399 | 1420 | ), |
| 1421 | + 'print_enable_logo' => array( | |
| 1422 | + 'name' => 'print_enable_logo', | |
| 1423 | + 'type' => 'toggle', | |
| 1424 | + 'label' => __( 'Logo on Printed Doc', 'betterdocs' ), | |
| 1425 | + 'label_subtitle' => __( 'Show a logo at the top of the printed / PDF page', 'betterdocs' ), | |
| 1426 | + 'enable_disable_text_active' => true, | |
| 1427 | + 'default' => 0, | |
| 1428 | + 'priority' => 4 | |
| 1429 | + ), | |
| 1430 | + 'print_logo' => array( | |
| 1431 | + 'name' => 'print_logo', | |
| 1432 | + 'type' => 'media', | |
| 1433 | + 'value' => '', | |
| 1434 | + 'label' => __( 'Print Logo', 'betterdocs' ), | |
| 1435 | + 'label_subtitle' => __( 'Leave empty to use your site logo, or the site icon when no site logo is set', 'betterdocs' ), | |
| 1436 | + 'priority' => 5, | |
| 1437 | + 'rules' => Rules::is( 'print_enable_logo', true ) | |
| 1438 | + ), | |
| 1439 | + 'print_enable_footer' => array( | |
| 1440 | + 'name' => 'print_enable_footer', | |
| 1441 | + 'type' => 'toggle', | |
| 1442 | + 'label' => __( 'Footer on Printed Doc', 'betterdocs' ), | |
| 1443 | + 'label_subtitle' => __( 'Show a footer on every page of the printed / PDF document', 'betterdocs' ), | |
| 1444 | + 'enable_disable_text_active' => true, | |
| 1445 | + 'default' => 0, | |
| 1446 | + 'priority' => 6 | |
| 1447 | + ), | |
| 1448 | + 'print_footer_text' => array( | |
| 1449 | + 'name' => 'print_footer_text', | |
| 1450 | + 'type' => 'textarea', | |
| 1451 | + 'label' => __( 'Print Footer Text', 'betterdocs' ), | |
| 1452 | + 'label_subtitle' => __( 'Leave empty to use the site name and current year', 'betterdocs' ), | |
| 1453 | + 'default' => '', | |
| 1454 | + 'priority' => 7, | |
| 1455 | + 'rules' => Rules::is( 'print_enable_footer', true ) | |
| 1456 | + ), | |
| 1400 | 1457 | 'enable_tags' => array( |
| 1401 | 1458 | 'name' => 'enable_tags', |
| 1402 | 1459 | 'type' => 'toggle', |
| 1403 | 1460 | 'label' => __( 'Tags', 'betterdocs' ), |
| @@ -1402,9 +1459,9 @@ | ||
| 1402 | 1459 | 'type' => 'toggle', |
| 1403 | 1460 | 'label' => __( 'Tags', 'betterdocs' ), |
| 1404 | 1461 | 'enable_disable_text_active' => true, |
| 1405 | 1462 | 'default' => 1, |
| 1406 | - 'priority' => 4 | |
| 1463 | + 'priority' => 8 | |
| 1407 | 1464 | ), |
| 1408 | 1465 | 'show_last_update_time' => array( |
| 1409 | 1466 | 'name' => 'show_last_update_time', |
| 1410 | 1467 | 'type' => 'toggle', |
| @@ -1410,9 +1467,9 @@ | ||
| 1410 | 1467 | 'type' => 'toggle', |
| 1411 | 1468 | 'label' => __( 'Last Update Time', 'betterdocs' ), |
| 1412 | 1469 | 'enable_disable_text_active' => true, |
| 1413 | 1470 | 'default' => 1, |
| 1414 | - 'priority' => 5 | |
| 1471 | + 'priority' => 9 | |
| 1415 | 1472 | ), |
| 1416 | 1473 | 'enable_navigation' => array( |
| 1417 | 1474 | 'name' => 'enable_navigation', |
| 1418 | 1475 | 'type' => 'toggle', |
| @@ -1418,9 +1475,9 @@ | ||
| 1418 | 1475 | 'type' => 'toggle', |
| 1419 | 1476 | 'label' => __( 'Navigation', 'betterdocs' ), |
| 1420 | 1477 | 'enable_disable_text_active' => true, |
| 1421 | 1478 | 'default' => 1, |
| 1422 | - 'priority' => 6 | |
| 1479 | + 'priority' => 10 | |
| 1423 | 1480 | ), |
| 1424 | 1481 | 'enable_comment' => array( |
| 1425 | 1482 | 'name' => 'enable_comment', |
| 1426 | 1483 | 'type' => 'toggle', |
| @@ -1426,9 +1483,9 @@ | ||
| 1426 | 1483 | 'type' => 'toggle', |
| 1427 | 1484 | 'label' => __( 'Comment', 'betterdocs' ), |
| 1428 | 1485 | 'enable_disable_text_active' => true, |
| 1429 | 1486 | 'default' => '', |
| 1430 | - 'priority' => 7 | |
| 1487 | + 'priority' => 11 | |
| 1431 | 1488 | ), |
| 1432 | 1489 | 'enable_credit' => array( |
| 1433 | 1490 | 'name' => 'enable_credit', |
| 1434 | 1491 | 'type' => 'toggle', |
| @@ -1434,9 +1491,9 @@ | ||
| 1434 | 1491 | 'type' => 'toggle', |
| 1435 | 1492 | 'label' => __( 'Show Powered by BetterDocs', 'betterdocs' ), |
| 1436 | 1493 | 'enable_disable_text_active' => true, |
| 1437 | 1494 | 'default' => '', |
| 1438 | - 'priority' => 8 | |
| 1495 | + 'priority' => 12 | |
| 1439 | 1496 | ), |
| 1440 | 1497 | 'reaction_feedback_text' => array( |
| 1441 | 1498 | 'name' => 'reaction_feedback_text', |
| 1442 | 1499 | 'type' => 'text', |
| @@ -1441,9 +1498,9 @@ | ||
| 1441 | 1498 | 'name' => 'reaction_feedback_text', |
| 1442 | 1499 | 'type' => 'text', |
| 1443 | 1500 | 'label' => __( 'Reaction Feedback Text', 'betterdocs' ), |
| 1444 | 1501 | 'default' => __( 'Thanks for your feedback.', 'betterdocs' ), |
| 1445 | - 'priority' => 9 | |
| 1502 | + 'priority' => 13 | |
| 1446 | 1503 | ), |
| 1447 | 1504 | 'enable_estimated_reading_time' => array( |
| 1448 | 1505 | 'name' => 'enable_estimated_reading_time', |
| 1449 | 1506 | 'type' => 'toggle', |
| @@ -1449,9 +1506,9 @@ | ||
| 1449 | 1506 | 'type' => 'toggle', |
| 1450 | 1507 | 'label' => __( 'Estimated Reading Time', 'betterdocs' ), |
| 1451 | 1508 | 'enable_disable_text_active' => true, |
| 1452 | 1509 | 'default' => 0, |
| 1453 | - 'priority' => 10 | |
| 1510 | + 'priority' => 14 | |
| 1454 | 1511 | ), |
| 1455 | 1512 | 'estimated_reading_time_title' => array( |
| 1456 | 1513 | 'name' => 'estimated_reading_time_title', |
| 1457 | 1514 | 'type' => 'text', |
| @@ -1456,9 +1513,9 @@ | ||
| 1456 | 1513 | 'name' => 'estimated_reading_time_title', |
| 1457 | 1514 | 'type' => 'text', |
| 1458 | 1515 | 'label' => __( 'Estimated Reading Time Title', 'betterdocs' ), |
| 1459 | 1516 | 'default' => '', |
| 1460 | - 'priority' => 11, | |
| 1517 | + 'priority' => 15, | |
| 1461 | 1518 | 'rules' => Rules::is( 'enable_estimated_reading_time', true ) |
| 1462 | 1519 | ), |
| 1463 | 1520 | 'estimated_reading_time_text' => array( |
| 1464 | 1521 | 'name' => 'estimated_reading_time_text', |
| @@ -1464,9 +1521,9 @@ | ||
| 1464 | 1521 | 'name' => 'estimated_reading_time_text', |
| 1465 | 1522 | 'type' => 'text', |
| 1466 | 1523 | 'label' => __( 'Estimated Reading Time Text', 'betterdocs' ), |
| 1467 | 1524 | 'default' => __( 'min read', 'betterdocs' ), |
| 1468 | - 'priority' => 12, | |
| 1525 | + 'priority' => 16, | |
| 1469 | 1526 | 'rules' => Rules::is( 'enable_estimated_reading_time', true ) |
| 1470 | 1527 | ), |
| 1471 | 1528 | 'singular_estimated_reading_time_text' => array( |
| 1472 | 1529 | 'name' => 'singular_estimated_reading_time_text', |
| @@ -1472,9 +1529,9 @@ | ||
| 1472 | 1529 | 'name' => 'singular_estimated_reading_time_text', |
| 1473 | 1530 | 'type' => 'text', |
| 1474 | 1531 | 'label' => __( 'Estimated Reading Time Text Singular', 'betterdocs' ), |
| 1475 | 1532 | 'default' => __( 'min read', 'betterdocs' ), |
| 1476 | - 'priority' => 13, | |
| 1533 | + 'priority' => 17, | |
| 1477 | 1534 | 'rules' => Rules::is( 'enable_estimated_reading_time', true ) |
| 1478 | 1535 | ) |
| 1479 | 1536 | ) |
| 1480 | 1537 | ), |