Changeset 3801404
- Timestamp:
- 11/14/2026 04:36:41 AM (28 hours ago)
- Location:
- brendigo-sidrena-cijena
- Files:
-
- 146 added
- 37 edited
-
LICENSE (modified) (1 diff)
-
assets/banner-1544x500-en_US.png (added)
-
assets/banner-1544x500.png (added)
-
assets/banner-772x250-en_US.png (added)
-
assets/banner-772x250.png (added)
-
assets/css/admin.css (modified) (1 diff)
-
assets/css/archive.css (modified) (1 diff)
-
assets/css/cjenik.css (modified) (9 diffs)
-
assets/css/frontend.css (modified) (1 diff)
-
assets/icon-128x128.png (added)
-
assets/icon-256x256.png (added)
-
assets/images/bazna-brand-mark.png (added)
-
assets/images/bazna-logo.png (added)
-
assets/js/admin-catalog.js (modified) (5 diffs)
-
assets/js/admin.js (modified) (1 diff)
-
brendigo-sidrena-cijena.php (modified) (2 diffs)
-
changelog.txt (modified) (1 diff)
-
includes/admin/tab-javni-xml.php (modified) (2 diffs)
-
includes/admin/tab-postavke.php (modified) (7 diffs)
-
includes/admin/tab-pregled.php (modified) (4 diffs)
-
includes/admin/tab-proizvodi.php (modified) (7 diffs)
-
includes/admin/tab-upute.php (modified) (4 diffs)
-
includes/admin/tab-uvoz-izvoz.php (modified) (4 diffs)
-
includes/class-activator.php (modified) (4 diffs)
-
includes/class-admin-save.php (modified) (2 diffs)
-
includes/class-admin.php (modified) (18 diffs)
-
includes/class-autoloader.php (modified) (1 diff)
-
includes/class-bulk-import.php (modified) (1 diff)
-
includes/class-catalog.php (modified) (1 diff)
-
includes/class-cli.php (modified) (5 diffs)
-
includes/class-export.php (modified) (1 diff)
-
includes/class-feed-files.php (modified) (4 diffs)
-
includes/class-feed-routes.php (modified) (5 diffs)
-
includes/class-feed-rows.php (modified) (1 diff)
-
includes/class-frontend.php (modified) (6 diffs)
-
includes/class-i18n.php (modified) (2 diffs)
-
includes/class-import-export.php (modified) (3 diffs)
-
includes/class-legal.php (added)
-
includes/class-notifications.php (modified) (1 diff)
-
includes/class-plugin.php (modified) (8 diffs)
-
includes/class-price-history.php (modified) (1 diff)
-
includes/class-product-fields.php (modified) (7 diffs)
-
includes/class-product-meta.php (modified) (5 diffs)
-
includes/class-public-api.php (modified) (8 diffs)
-
includes/class-settings.php (modified) (6 diffs)
-
readme.txt (modified) (12 diffs)
-
tags/1.5.1 (added)
-
tags/1.5.1/LICENSE (added)
-
tags/1.5.1/assets (added)
-
tags/1.5.1/assets/banner-1544x500-en_US.png (added)
-
tags/1.5.1/assets/banner-1544x500.png (added)
-
tags/1.5.1/assets/banner-772x250-en_US.png (added)
-
tags/1.5.1/assets/banner-772x250.png (added)
-
tags/1.5.1/assets/css (added)
-
tags/1.5.1/assets/css/admin.css (added)
-
tags/1.5.1/assets/css/archive-embed.css (added)
-
tags/1.5.1/assets/css/archive.css (added)
-
tags/1.5.1/assets/css/cjenik-embed.css (added)
-
tags/1.5.1/assets/css/cjenik.css (added)
-
tags/1.5.1/assets/css/frontend.css (added)
-
tags/1.5.1/assets/css/woo-blocks.css (added)
-
tags/1.5.1/assets/icon-128x128.png (added)
-
tags/1.5.1/assets/icon-256x256.png (added)
-
tags/1.5.1/assets/images (added)
-
tags/1.5.1/assets/images/bazna-brand-mark.png (added)
-
tags/1.5.1/assets/images/bazna-logo.png (added)
-
tags/1.5.1/assets/js (added)
-
tags/1.5.1/assets/js/admin-catalog.js (added)
-
tags/1.5.1/assets/js/admin-import.js (added)
-
tags/1.5.1/assets/js/admin-outlets.js (added)
-
tags/1.5.1/assets/js/admin.js (added)
-
tags/1.5.1/assets/js/cjenik.js (added)
-
tags/1.5.1/assets/js/frontend.js (added)
-
tags/1.5.1/assets/js/woo-blocks.js (added)
-
tags/1.5.1/brendigo-sidrena-cijena.php (added)
-
tags/1.5.1/changelog.txt (added)
-
tags/1.5.1/includes (added)
-
tags/1.5.1/includes/admin (added)
-
tags/1.5.1/includes/admin/tab-javni-xml.php (added)
-
tags/1.5.1/includes/admin/tab-poslovnice.php (added)
-
tags/1.5.1/includes/admin/tab-postavke.php (added)
-
tags/1.5.1/includes/admin/tab-pregled.php (added)
-
tags/1.5.1/includes/admin/tab-proizvodi.php (added)
-
tags/1.5.1/includes/admin/tab-upute.php (added)
-
tags/1.5.1/includes/admin/tab-uvoz-izvoz.php (added)
-
tags/1.5.1/includes/class-activator.php (added)
-
tags/1.5.1/includes/class-admin-save.php (added)
-
tags/1.5.1/includes/class-admin.php (added)
-
tags/1.5.1/includes/class-archive.php (added)
-
tags/1.5.1/includes/class-audit-log.php (added)
-
tags/1.5.1/includes/class-autoloader.php (added)
-
tags/1.5.1/includes/class-automation.php (added)
-
tags/1.5.1/includes/class-bulk-import.php (added)
-
tags/1.5.1/includes/class-catalog.php (added)
-
tags/1.5.1/includes/class-cli.php (added)
-
tags/1.5.1/includes/class-compat.php (added)
-
tags/1.5.1/includes/class-export.php (added)
-
tags/1.5.1/includes/class-feed-files.php (added)
-
tags/1.5.1/includes/class-feed-routes.php (added)
-
tags/1.5.1/includes/class-feed-rows.php (added)
-
tags/1.5.1/includes/class-fields.php (added)
-
tags/1.5.1/includes/class-filesystem.php (added)
-
tags/1.5.1/includes/class-frontend.php (added)
-
tags/1.5.1/includes/class-i18n.php (added)
-
tags/1.5.1/includes/class-import-export.php (added)
-
tags/1.5.1/includes/class-import-parse.php (added)
-
tags/1.5.1/includes/class-legal.php (added)
-
tags/1.5.1/includes/class-migration.php (added)
-
tags/1.5.1/includes/class-money.php (added)
-
tags/1.5.1/includes/class-notifications.php (added)
-
tags/1.5.1/includes/class-plugin.php (added)
-
tags/1.5.1/includes/class-poslovnice.php (added)
-
tags/1.5.1/includes/class-price-history.php (added)
-
tags/1.5.1/includes/class-product-fields.php (added)
-
tags/1.5.1/includes/class-product-meta.php (added)
-
tags/1.5.1/includes/class-public-api.php (added)
-
tags/1.5.1/includes/class-settings.php (added)
-
tags/1.5.1/includes/class-upit.php (added)
-
tags/1.5.1/includes/class-woo-blocks.php (added)
-
tags/1.5.1/includes/class-woo-bulk-editor.php (added)
-
tags/1.5.1/includes/class-xlsx.php (added)
-
tags/1.5.1/includes/trait-row-helpers.php (added)
-
tags/1.5.1/languages (added)
-
tags/1.5.1/languages/README.md (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-ar.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-ar.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-bg_BG.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-bg_BG.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-bs_BA.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-bs_BA.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-cs_CZ.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-cs_CZ.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-de_DE.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-de_DE.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-en_AU.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-en_AU.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-en_CA.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-en_CA.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-en_GB.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-en_GB.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-en_US.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-en_US.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-es_ES.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-es_ES.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-fr_FR.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-fr_FR.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-hu_HU.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-hu_HU.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-it_IT.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-it_IT.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-ja.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-ja.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-nl_NL.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-nl_NL.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-pl_PL.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-pl_PL.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-pt_BR.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-pt_BR.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-pt_PT.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-pt_PT.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-ro_RO.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-ro_RO.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-ru_RU.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-ru_RU.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-sk_SK.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-sk_SK.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-sl_SI.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-sl_SI.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-sr_RS.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-sr_RS.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-sr_RS_latin.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-sr_RS_latin.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-tr_TR.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-tr_TR.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-uk.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-uk.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-zh_CN.mo (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena-zh_CN.po (added)
-
tags/1.5.1/languages/brendigo-sidrena-cijena.pot (added)
-
tags/1.5.1/languages/coverage.json (added)
-
tags/1.5.1/languages/index.php (added)
-
tags/1.5.1/readme.txt (added)
-
tags/1.5.1/uninstall.php (added)
Legend:
- Unmodified
- Added
- Removed
-
brendigo-sidrena-cijena/LICENSE
r3723942 r3801404 1 1 Sidrena 2 2 Copyright (C) 2026 Brendigo 3 Portions adapted from MJDD Sidrena i bazna cijena 1.26.0: 4 Copyright (C) 2026 Jure Zadravec / MJDD (GPL-2.0-or-later) 3 5 4 6 License: GNU General Public License v2 or later -
brendigo-sidrena-cijena/assets/css/admin.css
r3737344 r3801404 3815 3815 object-fit: contain; 3816 3816 } 3817 3818 /* Shared SIDRENA visual tokens: Android (Compose) + WordPress admin. 3819 * Scoped to SIDRENA pages; never restyle WordPress or WooCommerce globally. 3820 * Existing layout/responsiveness is retained while cards and actions match 3821 * Android's #07182D / #10263D / #28455F / #FF852C palette. 3822 */ 3823 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin { 3824 --br-bg: #07182d; 3825 --br-line: #28455f; 3826 --br-line-strong: #385a73; 3827 --br-text: #fff; 3828 --br-muted: #a9bad1; 3829 --br-gold: #ff852c; 3830 --br-green: #52d9a3; 3831 --br-blue: #80b9ff; 3832 --br-violet: #9091ff; 3833 --sidrena-teal: #52d9a3; 3834 --sidrena-teal-dark: #52d9a3; 3835 --sidrena-blue: #80b9ff; 3836 --sidrena-blue-dark: #80b9ff; 3837 --sidrena-wash: rgba(255, 133, 44, .08); 3838 --sidrena-gradient-btn: linear-gradient(135deg, #ffaa55, #ff852c); 3839 --sidrena-gradient-btn-hover: linear-gradient(135deg, #ffb566, #ff9346); 3840 } 3841 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-shell { 3842 background: #07182d; 3843 } 3844 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-sidebar { 3845 background: linear-gradient(180deg, #10263d, #07182d); 3846 } 3847 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-nav__item.is-active { 3848 border-color: rgba(255, 133, 44, .38); 3849 color: #ffaa55; 3850 background: rgba(255, 133, 44, .12); 3851 box-shadow: inset 3px 0 0 #ff852c; 3852 } 3853 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-brand__mark--sidrena { 3854 border-color: rgba(255, 133, 44, .36); 3855 background: linear-gradient(145deg, #19304a, #07182d); 3856 box-shadow: 0 0 0 4px rgba(255, 133, 44, .06); 3857 } 3858 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-urlbox { 3859 background: #10263d; 3860 border-color: #28455f; 3861 border-radius: 14px; 3862 } 3863 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-urlbox code { 3864 color: #d8e4f0; 3865 overflow-wrap: anywhere; 3866 } 3867 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-settings .button-primary, 3868 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .button-primary { 3869 border-radius: 12px; 3870 } 3871 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge { 3872 display: grid; 3873 gap: 12px; 3874 margin: 14px 0 20px; 3875 padding: clamp(14px, 2.5vw, 20px); 3876 border: 1px solid #28455f; 3877 border-radius: 16px; 3878 background: #10263d; 3879 color: #fff; 3880 } 3881 .sidrena-android-bridge__head { 3882 display: flex; 3883 flex-wrap: wrap; 3884 justify-content: space-between; 3885 gap: 10px; 3886 align-items: center; 3887 } 3888 .sidrena-android-bridge__head h3 { 3889 margin: 0; 3890 color: #fff; 3891 font-size: 18px; 3892 line-height: 1.4; 3893 } 3894 .sidrena-android-bridge p { 3895 margin: 0; 3896 color: #a9bad1; 3897 line-height: 1.6; 3898 } 3899 .sidrena-android-bridge__status { 3900 display: inline-flex; 3901 align-items: center; 3902 min-height: 30px; 3903 padding: 4px 12px; 3904 border: 1px solid #516477; 3905 border-radius: 99px; 3906 font-size: 12px; 3907 font-weight: 700; 3908 white-space: nowrap; 3909 } 3910 .sidrena-android-bridge .is-ready { 3911 color: #52d9a3; 3912 border-color: rgba(82, 217, 163, .30); 3913 } 3914 .sidrena-android-bridge .is-pending { 3915 color: #ffaa55; 3916 border-color: rgba(255, 133, 44, .36); 3917 } 3918 .sidrena-android-bridge__url { 3919 display: flex; 3920 align-items: center; 3921 flex-wrap: wrap; 3922 gap: 10px; 3923 padding: 12px; 3924 border: 1px solid #28455f; 3925 border-radius: 11px; 3926 background: #19304a; 3927 } 3928 .sidrena-android-bridge__url code { 3929 flex: 1 1 250px; 3930 min-width: 0; 3931 padding: 0; 3932 background: transparent; 3933 color: #fff; 3934 overflow-wrap: anywhere; 3935 } 3936 .sidrena-android-bridge__checks { 3937 display: flex; 3938 flex-wrap: wrap; 3939 gap: 8px 18px; 3940 margin: 0; 3941 padding: 0; 3942 list-style: none; 3943 } 3944 .sidrena-android-bridge__checks li { 3945 margin: 0; 3946 padding: 2px 0 2px 14px; 3947 border-left: 3px solid currentColor; 3948 font-size: 13px; 3949 } 3950 .sidrena-android-bridge .sidrena-android-bridge__warning { 3951 color: #ffcfaa; 3952 } 3953 @media (max-width: 782px) { 3954 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge { 3955 padding: 14px; 3956 } 3957 .sidrena-android-bridge__url .button { 3958 width: 100%; 3959 } 3960 } 3961 3962 /* Screen 04 shared catalog presentation: WordPress editor mirrors the navy 3963 * surfaces, 12–16 px corner radii and orange actions of the Android product 3964 * catalog without changing WooCommerce storefront or global admin controls. */ 3965 body.sidrena-cijena-screen, 3966 body.sidrena-cijena-screen #wpcontent, 3967 body.sidrena-cijena-screen #wpbody-content { 3968 background: #07182d; 3969 } 3970 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-card, 3971 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog-wrap, 3972 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-mapfield, 3973 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-setting-row { 3974 border-color: #28455f; 3975 border-radius: 14px; 3976 background-color: #10263d; 3977 color: #fff; 3978 } 3979 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog { 3980 background: #10263d; 3981 color: #fff; 3982 } 3983 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog thead th { 3984 border-bottom-color: #28455f; 3985 background: #19304a; 3986 color: #a9bad1; 3987 } 3988 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog tbody td { 3989 border-bottom-color: #28455f; 3990 background: transparent; 3991 color: #fff; 3992 } 3993 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog tbody tr:hover td { 3994 background: rgba(255, 133, 44, .05); 3995 } 3996 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin input[type="search"], 3997 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin input[type="text"], 3998 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin input[type="url"], 3999 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin select, 4000 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin textarea { 4001 border-color: #28455f !important; 4002 border-radius: 11px !important; 4003 background: #19304a !important; 4004 color: #fff !important; 4005 } 4006 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin input:focus-visible, 4007 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin select:focus-visible, 4008 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin button:focus-visible, 4009 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin a:focus-visible { 4010 outline: 2px solid #ff852c; 4011 outline-offset: 2px; 4012 } 4013 @media (max-width: 782px) { 4014 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog-wrap { 4015 overflow-x: auto; 4016 max-width: 100%; 4017 } 4018 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-card { 4019 border-radius: 12px; 4020 padding: 14px; 4021 } 4022 } 4023 4024 4025 /* Only the first 12 outlets are shown in the Android connectivity panel; 4026 * all published outlets remain available through the public REST endpoint. */ 4027 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge__outlets { 4028 display: grid; 4029 gap: 8px; 4030 padding: 12px; 4031 border: 1px solid #28455f; 4032 border-radius: 12px; 4033 background: #19304a; 4034 } 4035 .sidrena-android-bridge__outlets h4 { 4036 margin: 0; 4037 color: #fff; 4038 font-size: 14px; 4039 } 4040 .sidrena-android-bridge__outlet-list { 4041 display: grid; 4042 gap: 6px; 4043 margin: 0; 4044 padding: 0; 4045 list-style: none; 4046 } 4047 .sidrena-android-bridge__outlet-list > li { 4048 display: flex; 4049 flex-wrap: wrap; 4050 align-items: center; 4051 gap: 6px 14px; 4052 margin: 0; 4053 padding: 8px 0; 4054 border-bottom: 1px solid #28455f; 4055 } 4056 .sidrena-android-bridge__outlet-list > li:last-child { 4057 border-bottom: 0; 4058 } 4059 .sidrena-android-bridge__outlet-list strong { 4060 flex: 1 1 160px; 4061 color: #fff; 4062 font-size: 13px; 4063 } 4064 .sidrena-android-bridge__outlet-list span { 4065 font-size: 12px; 4066 white-space: nowrap; 4067 } 4068 4069 /* SIDRENA Android connection panel: narrow phones and large browser zoom. 4070 * Preserve real values; only wrap content, never hide CSV/outlet statuses. */ 4071 @media (max-width: 600px) { 4072 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge, 4073 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge__url, 4074 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge__outlets { 4075 min-width: 0; 4076 max-width: 100%; 4077 box-sizing: border-box; 4078 } 4079 4080 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge__status, 4081 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge__outlet-list span { 4082 white-space: normal; 4083 overflow-wrap: anywhere; 4084 } 4085 4086 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge__url code, 4087 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge__outlet-list strong { 4088 min-width: 0; 4089 flex-basis: 100%; 4090 overflow-wrap: anywhere; 4091 } 4092 4093 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge__url .button { 4094 width: 100%; 4095 min-height: 44px; 4096 white-space: normal; 4097 } 4098 } 4099 4100 /* Cross-viewport QA (240–1920px): keep cards, controls and headings inside 4101 * the admin content area. Wide product tables scroll inside their own wrapper, 4102 * never through the whole WordPress page. */ 4103 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin, 4104 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-shell, 4105 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-main, 4106 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-panels, 4107 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-card, 4108 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog-wrap { 4109 box-sizing: border-box; 4110 max-width: 100%; 4111 min-width: 0; 4112 } 4113 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog-wrap { 4114 overflow-x: auto; 4115 overscroll-behavior-x: contain; 4116 -webkit-overflow-scrolling: touch; 4117 } 4118 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-card, 4119 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-topbar, 4120 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge__outlets { 4121 overflow-wrap: anywhere; 4122 } 4123 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-woo-catalog-tools__note { 4124 flex: 1 1 100%; 4125 min-width: 0; 4126 margin: 0; 4127 color: #a9bad1; 4128 font-size: 12px; 4129 line-height: 1.55; 4130 } 4131 @media (max-width: 782px) { 4132 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-woo-catalog-tools { 4133 display: grid; 4134 grid-template-columns: minmax(0, 1fr); 4135 } 4136 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-woo-catalog-tools label, 4137 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-woo-catalog-tools input, 4138 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-woo-catalog-tools select { 4139 box-sizing: border-box; 4140 width: 100%; 4141 min-width: 0; 4142 max-width: 100%; 4143 } 4144 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-android-bridge__outlet-list span { 4145 white-space: normal; 4146 overflow-wrap: anywhere; 4147 } 4148 } 4149 @media (max-width: 480px) { 4150 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-topbar__meta { 4151 display: grid; 4152 grid-template-columns: minmax(0, 1fr); 4153 } 4154 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-nav { 4155 grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); 4156 } 4157 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-card { 4158 padding: 12px; 4159 } 4160 } 4161 4162 4163 /* Pixel QA — responsive admin navigation and ergonomic controls. 4164 * An earlier 782px rule switches the nav to horizontal flex scrolling, so the 4165 * 480px grid-template-columns declaration never took effect. On very narrow 4166 * phones restore the intended two-column navigation without clipped labels. 4167 * Scope all rules to the SIDRENA admin shell, not global WordPress controls. */ 4168 @media (max-width: 782px) { 4169 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-nav__item, 4170 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-woo-catalog-footer .button, 4171 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-woo-catalog-tools input, 4172 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-woo-catalog-tools select { 4173 box-sizing: border-box; 4174 min-height: 44px; 4175 } 4176 } 4177 @media (max-width: 480px) { 4178 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-nav { 4179 display: grid; 4180 grid-template-columns: repeat(2, minmax(0, 1fr)); 4181 gap: 8px; 4182 overflow-x: visible; 4183 scroll-snap-type: none; 4184 padding: 0; 4185 } 4186 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-nav__item { 4187 min-width: 0; 4188 width: auto; 4189 white-space: normal; 4190 overflow-wrap: anywhere; 4191 padding: 8px 10px; 4192 scroll-snap-align: none; 4193 } 4194 } 4195 4196 4197 /* Android/WordPress brand parity: orange primary CTA needs navy lettering. 4198 * White on the #FF852C gradient lacks readable text contrast. The following 4199 * overrides remain inside the official SIDRENA admin, never global wp-admin. */ 4200 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .button-primary, 4201 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin button.button-primary, 4202 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin input[type="submit"].button-primary, 4203 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .button-primary:hover, 4204 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .button-primary:focus-visible, 4205 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .button-primary:active { 4206 color: #07182d !important; 4207 text-shadow: none !important; 4208 } 4209 4210 4211 /* SIDRENA admin — editable product rows remain usable inside their own 4212 * horizontally scrollable catalog at phone/tablet widths. 4213 * This deliberately leaves the published values and column order untouched. */ 4214 @media (max-width: 782px) { 4215 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog input[type="text"], 4216 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog input[type="url"], 4217 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog input[type="number"], 4218 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog input[type="date"], 4219 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog select, 4220 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog button, 4221 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog .button { 4222 box-sizing: border-box; 4223 min-height: 44px; 4224 } 4225 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog button, 4226 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-catalog .button { 4227 padding-inline: 12px; 4228 white-space: nowrap; 4229 } 4230 } 4231 4232 4233 /* SIDRENA 1.5.8: prevent long names and action buttons from overlapping 4234 * the edit-card heading on phone/tablet admin screens. Preserve desktop 4235 * information hierarchy, WordPress menu and catalog table data. */ 4236 @media (max-width: 782px) { 4237 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-card__head { 4238 box-sizing: border-box; 4239 display: flex; 4240 flex-wrap: wrap; 4241 gap: 12px; 4242 align-items: flex-start; 4243 max-width: 100%; 4244 min-width: 0; 4245 } 4246 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-card__head > * { 4247 box-sizing: border-box; 4248 min-width: 0; 4249 max-width: 100%; 4250 overflow-wrap: anywhere; 4251 } 4252 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-card__head h2 { 4253 overflow-wrap: anywhere; 4254 white-space: normal; 4255 margin-block: 0 6px; 4256 } 4257 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-cijena-card__head .button { 4258 min-height: 44px; 4259 white-space: normal; 4260 text-align: center; 4261 } 4262 } 4263 4264 4265 /* BAZNA: local CSS-only replacement for the legacy S image. No webfonts. */ 4266 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-admin-brand__mark--bazna { 4267 display: inline-flex; 4268 align-items: center; 4269 justify-content: center; 4270 flex: 0 0 48px; 4271 color: #ffaa55; 4272 border-color: rgba(255, 170, 85, 0.55); 4273 background: linear-gradient(145deg, #123457, #07182d); 4274 box-shadow: 0 0 0 5px rgba(255, 133, 44, 0.07), 0 12px 30px rgba(7, 24, 45, 0.22); 4275 font-family: Arial, sans-serif; 4276 font-size: 31px; 4277 font-weight: 900; 4278 letter-spacing: 0; 4279 line-height: 1; 4280 } 4281 4282 4283 /* BAZNA: license is a full admin tab, including 240–480px phones. 4284 * Keep very long domain/key values inside the panel; never change fields or 4285 * the license request itself. All selectors are limited to the BAZNA shell. */ 4286 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .bazna-license-form { 4287 display: grid; 4288 grid-template-columns: minmax(0, 1fr); 4289 gap: 10px; 4290 width: 100%; 4291 max-width: 720px; 4292 min-width: 0; 4293 margin-block: 16px; 4294 } 4295 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .bazna-license-form label { 4296 display: block; 4297 min-width: 0; 4298 } 4299 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .bazna-license-form input[type="text"] { 4300 display: block; 4301 box-sizing: border-box; 4302 width: 100%; 4303 min-width: 0; 4304 max-width: 100%; 4305 min-height: 44px; 4306 overflow-wrap: anywhere; 4307 } 4308 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .bazna-license-form .description, 4309 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-settings-card > p > code { 4310 overflow-wrap: anywhere; 4311 word-break: break-word; 4312 } 4313 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .bazna-license-form .button { 4314 box-sizing: border-box; 4315 min-height: 44px; 4316 max-width: 100%; 4317 height: auto; 4318 padding-block: 8px; 4319 white-space: normal; 4320 text-align: center; 4321 justify-self: start; 4322 } 4323 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .bazna-license-form--active { 4324 display: flex; 4325 align-items: flex-start; 4326 flex-wrap: wrap; 4327 } 4328 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .bazna-license-form--active .description { 4329 flex: 1 1 100%; 4330 min-width: 0; 4331 } 4332 @media (max-width: 480px) { 4333 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .bazna-license-form .button { 4334 width: 100%; 4335 justify-self: stretch; 4336 } 4337 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .bazna-license-form--active { 4338 flex-direction: column; 4339 } 4340 } 4341 4342 4343 /* BAZNA 8-tab responsive QA: mobile inputs must shrink INSIDE the admin 4344 * card. CSS grid "1fr" alone permits min-content (input default width) 4345 * to overflow 240/280px screens. Keep all changes scoped to this plugin. */ 4346 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-poslovnica__grid > *, 4347 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-poslovnica__field, 4348 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-poslovnica__field label, 4349 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-settings-card p > label { 4350 box-sizing: border-box; 4351 min-width: 0; 4352 max-width: 100%; 4353 } 4354 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-poslovnica__grid label, 4355 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-settings-card p > label { 4356 display: block; 4357 overflow-wrap: anywhere; 4358 } 4359 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-poslovnica__grid input:not([type="checkbox"]):not([type="radio"]), 4360 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-poslovnica__grid select, 4361 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-poslovnica__grid textarea, 4362 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-settings-card p > label input:not([type="checkbox"]):not([type="radio"]), 4363 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-settings-card p > label select, 4364 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .brendigo-settings-card p > label textarea { 4365 box-sizing: border-box; 4366 display: block; 4367 width: 100%; 4368 max-width: 100%; 4369 min-width: 0; 4370 } 4371 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin input[type="file"] { 4372 box-sizing: border-box; 4373 max-width: 100%; 4374 min-width: 0; 4375 } 4376 @media (max-width: 782px) { 4377 .wrap.sidrena-cijena-settings.brendigo-sidrena-admin .sidrena-poslovnica__grid { 4378 grid-template-columns: minmax(0, 1fr) !important; 4379 } 4380 } -
brendigo-sidrena-cijena/assets/css/archive.css
r3727711 r3801404 1 1 :root { 2 2 color-scheme: dark; 3 --br-bg: #0 6101e;3 --br-bg: #07182d; 4 4 --br-line: rgba(159, 181, 210, 0.16); 5 --br-text: #f 7f9fc;6 --br-muted: # 9aaac0;7 --br-gold: #f 4bd52;5 --br-text: #ffffff; 6 --br-muted: #a9bad1; 7 --br-gold: #ff852c; 8 8 } 9 9 * { box-sizing: border-box; } -
brendigo-sidrena-cijena/assets/css/cjenik.css
r3727711 r3801404 1 1 :root { 2 2 color-scheme: dark; 3 --br-bg: #0 6101e;3 --br-bg: #07182d; 4 4 --br-line: rgba(159, 181, 210, 0.16); 5 --br-text: #f 7f9fc;6 --br-muted: # 9aaac0;7 --br-gold: #f 4bd52;8 --br-green: # 39d99b;5 --br-text: #ffffff; 6 --br-muted: #a9bad1; 7 --br-gold: #ff852c; 8 --br-green: #52d9a3; 9 9 --br-red: #ff7d8f; 10 10 } … … 16 16 background: 17 17 radial-gradient(circle at 82% 4%, rgba(115, 87, 255, 0.16), transparent 28%), 18 radial-gradient(circle at 12% 92%, rgba(2 44, 189, 82, 0.08), transparent 30%),18 radial-gradient(circle at 12% 92%, rgba(255, 133, 44, 0.08), transparent 30%), 19 19 var(--br-bg); 20 20 color: var(--br-text); … … 47 47 height: 330px; 48 48 border-radius: 50%; 49 background: radial-gradient(circle, rgba(2 44, 189, 82, 0.16), transparent 66%);49 background: radial-gradient(circle, rgba(255, 133, 44, 0.16), transparent 66%); 50 50 pointer-events: none; 51 51 } … … 102 102 103 103 .cjenik-btn { 104 background: linear-gradient(135deg, #f 6cb69, #e2a239);104 background: linear-gradient(135deg, #ffaa55, #ff852c); 105 105 color: #111924; 106 106 box-shadow: 0 10px 24px rgba(226, 162, 57, 0.16); … … 131 131 border: 1px solid var(--br-line); 132 132 border-radius: 11px; 133 background: # 071525;133 background: #19304a; 134 134 color: var(--br-text); 135 135 font: inherit; … … 137 137 } 138 138 .cjenik-search input::placeholder { color: #71849d; } 139 .cjenik-search input:focus { border-color: rgba(2 44, 189, 82, 0.7); box-shadow: 0 0 0 3px rgba(244, 189, 82, 0.1); }139 .cjenik-search input:focus { border-color: rgba(255, 133, 44, 0.7); box-shadow: 0 0 0 3px rgba(255, 133, 44, 0.1); } 140 140 141 141 .cjenik-pager { … … 147 147 } 148 148 .cjenik-pager[hidden] { display: none !important; } 149 .cjenik-page { min-width: 40px; min-height: 38px; padding: 0 12px; border-color: var(--br-line); background: # 0d1b2d; color: #dfe6ef; }150 .cjenik-page:hover { border-color: rgba(2 44, 189, 82, 0.45); background: #13243a; }151 .cjenik-page.is-current { border-color: rgba(2 44, 189, 82, 0.55); background: rgba(244, 189, 82, 0.14); color: #ffe29d; }149 .cjenik-page { min-width: 40px; min-height: 38px; padding: 0 12px; border-color: var(--br-line); background: #10263d; color: #dfe6ef; } 150 .cjenik-page:hover { border-color: rgba(255, 133, 44, 0.45); background: #13243a; } 151 .cjenik-page.is-current { border-color: rgba(255, 133, 44, 0.55); background: rgba(255, 133, 44, 0.14); color: #ffaa55; } 152 152 .cjenik-page-gap { color: var(--br-muted); } 153 153 … … 177 177 178 178 .cjenik-table th, .cjenik-upit th { 179 background: # 0d1b2d;179 background: #10263d; 180 180 color: #aebdd0; 181 181 font-size: 0.72rem; … … 233 233 234 234 @media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition: none !important; scroll-behavior: auto !important; } } 235 236 237 /* SIDRENA mobile catalog: same 07/18/2d background, 10/26/3d cards, 238 * 28/45/5f borders, and ff/85/2c price accent as Android screens 04–05. 239 * data-field is a stable public schema key; visible labels stay translated. 240 */ 241 .cjenik-table td[data-field="maloprodajna_cijena"] { 242 color: #ff852c; 243 font-weight: 800; 244 font-variant-numeric: tabular-nums; 245 } 246 .cjenik-table td[data-field="sidrena_cijena"] { 247 color: #a9bad1; 248 font-variant-numeric: tabular-nums; 249 } 250 @media (max-width: 720px) { 251 .cjenik-table-wrap { 252 border: 0; 253 background: transparent; 254 box-shadow: none; 255 overflow: visible; 256 } 257 .cjenik-table tbody tr { 258 margin: 0 0 8px; 259 padding: 12px 14px; 260 border: 1px solid #28455f; 261 border-radius: 12px; 262 background: #10263d; 263 } 264 .cjenik-table tbody tr[data-kind="usluga"] { 265 border-color: #36526a; 266 } 267 .cjenik-table tr[data-kind="usluga"] td[data-field="naziv"] { 268 color: #fff; 269 font-size: 15px; 270 font-weight: 750; 271 } 272 .cjenik-table tr[data-kind="usluga"] td[data-field="maloprodajna_cijena"] { 273 font-size: 16px; 274 line-height: 1.45; 275 } 276 .cjenik-table td[data-field="sidrena_cijena"] { 277 color: #a9bad1; 278 font-size: 12px; 279 } 280 .cjenik-table tbody tr td::before { 281 color: #a9bad1; 282 } 283 } 284 285 /* Public price list: prevent long product names, SKUs and URLs from 286 * producing page-level horizontal scrolling on compact phones. */ 287 .cjenik-table-wrap, 288 .sidrena-cjenik, 289 .cjenik-toolbar, 290 .cjenik-search { 291 box-sizing: border-box; 292 min-width: 0; 293 max-width: 100%; 294 } 295 .cjenik-table td, 296 .cjenik-upit td, 297 .cjenik-hero, 298 .cjenik-empty-filter { 299 overflow-wrap: anywhere; 300 } 301 @media (max-width: 720px) { 302 .cjenik-table-wrap { 303 width: 100%; 304 } 305 .cjenik-table tbody tr, 306 .cjenik-upit tbody tr { 307 box-sizing: border-box; 308 width: 100%; 309 max-width: 100%; 310 min-width: 0; 311 } 312 .cjenik-table td, 313 .cjenik-upit td { 314 overflow-wrap: anywhere; 315 word-break: normal; 316 } 317 /* Override the more specific desktop nowrap rules for price/URL cells. 318 * Long SKUs and public URLs must wrap inside the mobile card, not push 319 * the complete document beyond the device viewport. */ 320 .cjenik-table td:nth-child(n + 3), 321 .cjenik-upit td:last-child { 322 white-space: normal; 323 } 324 } -
brendigo-sidrena-cijena/assets/css/frontend.css
r3737238 r3801404 189 189 .sidrena-price-chart__note{font-size:.875em;opacity:.85} 190 190 .sidrena-price-chart table{width:100%;border-collapse:collapse}.sidrena-price-chart th,.sidrena-price-chart td{padding:.35em;border-bottom:1px solid #9996;text-align:left} 191 192 /* On a small storefront viewport a floating help bubble can exceed the right 193 * edge of a WooCommerce card. Open it in normal flow for touch and keyboard 194 * users instead; it remains hidden unless the price label is activated. */ 195 @media (max-width: 600px) { 196 .sidrena-cijena--has-tooltip { 197 width: 100%; 198 overflow-wrap: anywhere; 199 } 200 201 .sidrena-cijena--has-tooltip .sidrena-cijena__tooltip { 202 position: static; 203 display: none; 204 width: 100%; 205 max-width: 100%; 206 margin-top: 10px; 207 transform: none; 208 overflow-wrap: anywhere; 209 } 210 211 .sidrena-cijena--has-tooltip .sidrena-cijena__tooltip::after { 212 display: none; 213 } 214 215 .sidrena-cijena--has-tooltip:is(:hover, :focus, :focus-within) .sidrena-cijena__tooltip { 216 display: block; 217 opacity: 1; 218 visibility: visible; 219 } 220 } -
brendigo-sidrena-cijena/assets/js/admin-catalog.js
r3737344 r3801404 67 67 } 68 68 var prefix = typeof sidrenaCijenaAdmin !== "undefined" && sidrenaCijenaAdmin.catalogIdPrefix ? sidrenaCijenaAdmin.catalogIdPrefix : ""; 69 return '[ sidrena-cijena id="' + prefix + id + '"]';69 return '[bazna-cijena id="' + prefix + id + '"]'; 70 70 } 71 71 … … 688 688 } 689 689 if (!$.trim(row.sidrena_cijena || "")) { 690 missing.push(" sidrena");690 missing.push("bazna_cijena"); 691 691 } 692 692 return missing; … … 738 738 }); 739 739 740 var message = i18n.catalogRequired || "Naziv, redovna cijena i sidrena cijena obavezni su za svaki popunjeni redak.";740 var message = i18n.catalogRequired || "Naziv, aktualna cijena i bazna cijena obvezni su za svaki popunjeni redak."; 741 741 var $notice = $form.find(".brendigo-catalog-validation"); 742 742 if (!$notice.length) { … … 837 837 $form.on("input change", ".brendigo-woo-row :input", updateChangeStatus); 838 838 839 function visibleRows() {840 return $rows.filter(function () {841 return !$(this).is("[hidden]");842 });843 }844 845 839 function applyFilters() { 846 840 var query = $.trim($("#sidrena-wc-filter").val() || "").toLowerCase(); … … 871 865 $form.on("change", ".js-sidrena-wc-price", applyFilters); 872 866 873 $(".js-sidrena-wc-fill-date").on("click", function () { 874 var date = $.trim($("#sidrena-wc-bulk-date").val() || ""); 875 if (!date) { 876 return; 877 } 878 visibleRows().find(".js-sidrena-wc-date").each(function () { 879 if (!$.trim($(this).val() || "")) { 880 $(this).val(date).trigger("change"); 881 } 882 }); 883 }); 884 885 $(".js-sidrena-wc-fill-price").on("click", function () { 886 var message = i18n.fillCurrentConfirm || "Fill empty reference-price fields with the current price? Use this only if that price applied on the reference date."; 887 if (!window.confirm(message)) { 888 return; 889 } 890 visibleRows().each(function () { 891 var $row = $(this); 892 var $field = $row.find(".js-sidrena-wc-price"); 893 if ($.trim($field.val() || "")) { 894 return; 895 } 896 var price = $.trim($row.find(".brendigo-woo-current").data("current") || ""); 897 if (price) { 898 $field.val(price).trigger("change"); 899 } 900 }); 901 }); 867 // Historical reference prices and dates must be entered individually 868 // with evidence, never copied from the current WooCommerce price. 902 869 903 870 $resetButton.on("click", function () { -
brendigo-sidrena-cijena/assets/js/admin.js
r3727711 r3801404 41 41 42 42 if (!prefix && style !== "plain") { 43 prefix = " Sidrena cijena";43 prefix = "Bazna cijena"; 44 44 } 45 45 -
brendigo-sidrena-cijena/brendigo-sidrena-cijena.php
r3737344 r3801404 2 2 /** 3 3 * Plugin Name: SIDRENA – Sidrene cijene i cjenici 4 * Plugin URI: https://brendigo.com/ sidrene-cijene/5 * Description: Sidrene cijene i javni HTML/XML/CSV cjenici s arhivom za WordPress, uz dodatnu WooCommerce integraciju.6 * Version: 1.5. 04 * Plugin URI: https://brendigo.com/ 5 * Description: Bazne cijene, javni HTML/XML/CSV cjenici i arhiva za WordPress s opcionalnom WooCommerce integracijom. 6 * Version: 1.5.20 7 7 * Requires at least: 6.6 8 8 * Requires PHP: 7.4 … … 19 19 defined( 'ABSPATH' ) || exit; 20 20 21 define( 'BRENDIGO_SIDRENA_CIJENA_VERSION', '1.5. 0' );21 define( 'BRENDIGO_SIDRENA_CIJENA_VERSION', '1.5.20' ); 22 22 define( 'BRENDIGO_SIDRENA_CIJENA_FILE', __FILE__ ); 23 23 define( 'BRENDIGO_SIDRENA_CIJENA_PATH', plugin_dir_path( __FILE__ ) ); -
brendigo-sidrena-cijena/changelog.txt
r3737344 r3801404 1 == BAZNA 1.5.20 == 2 - Uklonjeni BAZNA licencni ključevi, aktivacijske provjere, ograničenja uvoza/objave i licencni servis iz WordPressa, Weba, Joomle, Shopifyja i Androida. Windows 0.10.7 više ne traži komercijalni EULA ni aktivaciju. 3 - Službeni WordPress ZIP i WordPress.org kandidat koriste jedinstveni otključani izvorni kod. Objedinjeno izdanje ne distribuira stari licencni servis. 4 - Administratorska prijava, CSRF, Shopify HMAC, javni REST API i postojeći korisnički podaci ostaju sačuvani. 5 - Usklađen javni pretraživ HTML cjenik proizvoda, usluga i usluga „Cijena na upit” na PHP/Joomla/Shopify platformama; prikaz uvijek čita posljednju objavu, ne nacrt. 6 - WordPress REST v1 i Web/Joomla/Shopify REST v1 podržavaju filtriranje usluga na upit po oznaci poslovnice i tekstu kriterija, bez izlaganja administracijskih podataka. 7 - Androidova opća pretraga sada uključuje usluge na upit s nazivom i kriterijima, ali bez izmišljene brojčane cijene, uz odvojenu poslovnicu i filtarske kategorije. 8 - Izlazni HTML escapea nazive i kriterije. Novi PHP/Android testovi štite podatke i responzivnost. 9 - Prethodni računi, povijesne cijene, arhive, REST v1 URL-ovi i postojeća konfiguracija ostaju netaknuti. 10 11 == BAZNA 1.5.19 == 12 - WordPress: „Cijena na upit” dostupna u REST v1 samo iz uspješno objavljenog snapshota, bez administracijskih nacrta. 13 - Web PHP, Joomla, Shopify i Android: zajednički javni REST ugovor s nazivom, kriterijima i poslovnicom. 14 - Iznosi za usluge na upit ne izmišljaju se i ne objavljuju u CSV/XML numeričkim cjenicima. 15 - Zadržane su postojeće cijene, korisnici, arhive i REST v1 rute. Android targetSdk ostaje 36. 16 - Dodani testovi i matrica kompatibilnosti s referentnim GPL dodatkom 1.26.0. 17 18 == BAZNA 1.5.18 == 19 - WordPress i Android: zajednički javni REST v1 zadržava povratnu kompatibilnost i razlikuje stanje objave po poslovnicama. 20 - Android početna ploča broji samo stvarno objavljene CSV cjenike; neobjavljene datoteke i promjene ne predstavljaju se kao ažurne. 21 - Pravna revizija 14. 11. 2026.: savjetovanje završeno, konačni pravilnici nisu proglašeni objavljenima bez provjere Narodnih novina; datumi i arhiva ostaju usklađeni s objavljenim odlukama. 22 - Google Play: app ID ostaje com.brendigo.bazna; dodane napomene za Data safety, pravila privatnosti i sigurnosne provjere. 23 - Ne mijenjaju se računi, licencni ključevi, povijesne cijene, postojeći javni API ili spremljene postavke. 24 25 == BAZNA 1.5.17 == 26 - Android: paket je preimenovan u com.brendigo.bazna i pripremljen kao nova Google Play aplikacija. 27 - Android: nadograđene ovisnosti, dodatne provjere sigurnosti i responzivnosti, izdvajanje navigacijskog koda. 28 - WordPress: verzijska oznaka bez migracije baze, promjene korisničkih računa ili izmjena javnog REST API-ja. 29 30 == BAZNA 1.5.11 == 31 - Novi javni brend BAZNA — Bazne cijene (Android, WordPress i Windows). 32 - Stari podaci, WordPress ID i REST v1 ostaju kompatibilni. 33 - Dodani novi shortcode aliasi; stari shortcodeovi ostaju važeći. 34 - Zamjena samo zadanih naziva cijena bez brisanja korisničkih tekstova. 35 36 = 1.5.4 – development candidate (2026-11-02) = 37 * WordPress REST v1 now exposes optional available_csv for goods and services, including independent per-outlet readiness. Both missing and published-empty CSV files are represented honestly. 38 * Product feeds optionally include the original public WooCommerce attachment URL in slika_url; no private images, image proxies, user data, or additional authentication are introduced. 39 * Added an Android connection and publication-status panel to the existing public cjenici settings page. 40 * Shared navy, orange, green brand colors across WordPress dashboard and public cjenik/archive pages. 41 * Two standalone PHP contract regression tests and CI checks verify public API, file readiness, no filesystem leakage, and backward-compatible CSV columns. 42 * No DB migrations, no changes to saved prices, legal-date rules, shortcode semantics, or existing REST URLs. Not a released tag until publication. 43 1 44 = 1.5.0 – 2026-10-09 = 2 45 * Matched the plugin name and readme heading exactly for WordPress.org Plugin Check. -
brendigo-sidrena-cijena/includes/admin/tab-javni-xml.php
r3737238 r3801404 75 75 } 76 76 } 77 $this->render_url_box( __( 'Javni REST API', 'brendigo-sidrena-cijena' ), rest_url( 'brendigo- sidrena/v1/cjenici' ), rest_url( 'brendigo-sidrena/v1/cjenici' ), __( 'Otvori API', 'brendigo-sidrena-cijena' ) );77 $this->render_url_box( __( 'Javni REST API', 'brendigo-sidrena-cijena' ), rest_url( 'brendigo-bazna/v1/cjenici' ), rest_url( 'brendigo-bazna/v1/cjenici' ), __( 'Otvori API', 'brendigo-sidrena-cijena' ) ); 78 78 79 79 if ( $sidrena_settings->is_multi_poslovnica() ) { … … 86 86 ?> 87 87 </div> 88 89 <?php 90 // Read the exact same published files as the public Android discovery API. 91 $sidrena_android_products = $sidrena_feeds->get_type_public_path( 'proizvodi', 'csv' ); 92 $sidrena_android_services = $sidrena_feeds->get_type_public_path( 'usluge', 'csv' ); 93 $sidrena_android_products_ready = is_string( $sidrena_android_products ) && '' !== $sidrena_android_products && is_file( $sidrena_android_products ) && is_readable( $sidrena_android_products ); 94 $sidrena_android_services_ready = is_string( $sidrena_android_services ) && '' !== $sidrena_android_services && is_file( $sidrena_android_services ) && is_readable( $sidrena_android_services ); 95 $sidrena_android_ready = $sidrena_android_products_ready && $sidrena_android_services_ready; 96 $sidrena_android_pending = false; 97 if ( class_exists( 'Brendigo_Sidrena_Cijena_Automation' ) ) { 98 $sidrena_android_pending_state = Brendigo_Sidrena_Cijena_Automation::instance()->get_pending_state(); 99 $sidrena_android_pending = is_array( $sidrena_android_pending_state ) && ! empty( $sidrena_android_pending_state['since'] ); 100 } 101 ?> 102 <section class="sidrena-android-bridge" aria-labelledby="sidrena-android-bridge-title"> 103 <div class="sidrena-android-bridge__head"> 104 <h3 id="sidrena-android-bridge-title"><?php echo esc_html__( 'BAZNA Android · Povezivanje', 'brendigo-sidrena-cijena' ); ?></h3> 105 <span class="sidrena-android-bridge__status <?php echo $sidrena_android_ready && ! $sidrena_android_pending ? 'is-ready' : 'is-pending'; ?>"> 106 <?php 107 echo $sidrena_android_pending 108 ? esc_html__( 'Promjene čekaju objavu', 'brendigo-sidrena-cijena' ) 109 : ( $sidrena_android_ready 110 ? esc_html__( 'CSV datoteke objavljene', 'brendigo-sidrena-cijena' ) 111 : esc_html__( 'Čeka objavu', 'brendigo-sidrena-cijena' ) ); 112 ?> 113 </span> 114 </div> 115 <p><?php echo esc_html__( 'U Android aplikaciju unesite HTTPS adresu ove WordPress stranice. Korisnička imena i lozinke nisu potrebni: aplikacija čita samo javni BAZNA REST API.', 'brendigo-sidrena-cijena' ); ?></p> 116 <p><?php echo esc_html__( 'Objavljena datoteka ne dokazuje točnost bazne cijene ni najniže cijene prije sniženja. Povijesne iznose i datume potvrdite izvornom evidencijom. Objavljene odluke imaju predviđen početak primjene 17. studenoga 2026.; pravilnici su 9. studenoga još bili u savjetovanju.', 'brendigo-sidrena-cijena' ); ?></p> 117 <?php if ( $sidrena_android_pending ) : ?> 118 <p class="sidrena-android-bridge__warning"><?php echo esc_html__( 'Upozorenje: katalog je izmijenjen nakon posljednje javne objave. Ponovno generirajte CSV/XML cjenike kako Android ne bi prikazivao zastarjele cijene.', 'brendigo-sidrena-cijena' ); ?></p> 119 <?php endif; ?> 120 <div class="sidrena-android-bridge__url"> 121 <code><?php echo esc_html( home_url( '/' ) ); ?></code> 122 <button class="button button-secondary sidrena-cijena-copy" type="button" data-copy="<?php echo esc_attr( home_url( '/' ) ); ?>"><?php echo esc_html__( 'Kopiraj adresu', 'brendigo-sidrena-cijena' ); ?></button> 123 </div> 124 <ul class="sidrena-android-bridge__checks"> 125 <li class="<?php echo $sidrena_android_products_ready ? 'is-ready' : 'is-pending'; ?>"> 126 <?php echo esc_html__( 'CSV proizvodi', 'brendigo-sidrena-cijena' ); ?>: 127 <?php echo $sidrena_android_products_ready ? esc_html__( 'objavljeno', 'brendigo-sidrena-cijena' ) : esc_html__( 'nije objavljeno', 'brendigo-sidrena-cijena' ); ?> 128 </li> 129 <li class="<?php echo $sidrena_android_services_ready ? 'is-ready' : 'is-pending'; ?>"> 130 <?php echo esc_html__( 'CSV usluge', 'brendigo-sidrena-cijena' ); ?>: 131 <?php echo $sidrena_android_services_ready ? esc_html__( 'objavljeno', 'brendigo-sidrena-cijena' ) : esc_html__( 'nije objavljeno', 'brendigo-sidrena-cijena' ); ?> 132 </li> 133 </ul> 134 <?php if ( $sidrena_settings->is_multi_poslovnica() ) : ?> 135 <?php 136 $sidrena_android_outlets = Brendigo_Sidrena_Cijena_Poslovnice::instance()->all(); 137 $sidrena_android_outlets_shown = array_slice( $sidrena_android_outlets, 0, 12 ); 138 ?> 139 <div class="sidrena-android-bridge__outlets"> 140 <h4><?php echo esc_html__( 'Povezivanje poslovnica', 'brendigo-sidrena-cijena' ); ?></h4> 141 <p><?php echo esc_html__( 'Android učitava zasebne CSV cjenike svake odabrane poslovnice. Status webshopa ne zamjenjuje status poslovnice.', 'brendigo-sidrena-cijena' ); ?></p> 142 <ul class="sidrena-android-bridge__outlet-list"> 143 <?php foreach ( $sidrena_android_outlets_shown as $sidrena_android_outlet ) : ?> 144 <?php 145 $sidrena_android_code = isset( $sidrena_android_outlet['oznaka'] ) ? (string) $sidrena_android_outlet['oznaka'] : ''; 146 if ( '' === $sidrena_android_code ) { 147 continue; 148 } 149 $sidrena_android_name = isset( $sidrena_android_outlet['naziv'] ) && '' !== $sidrena_android_outlet['naziv'] ? $sidrena_android_outlet['naziv'] : $sidrena_android_code; 150 $sidrena_android_outlet_products = $sidrena_feeds->get_type_public_path( 'proizvodi', 'csv', $sidrena_android_code ); 151 $sidrena_android_outlet_services = $sidrena_feeds->get_type_public_path( 'usluge', 'csv', $sidrena_android_code ); 152 $sidrena_android_outlet_products_ok = is_string( $sidrena_android_outlet_products ) && '' !== $sidrena_android_outlet_products && is_file( $sidrena_android_outlet_products ) && is_readable( $sidrena_android_outlet_products ); 153 $sidrena_android_outlet_services_ok = is_string( $sidrena_android_outlet_services ) && '' !== $sidrena_android_outlet_services && is_file( $sidrena_android_outlet_services ) && is_readable( $sidrena_android_outlet_services ); 154 ?> 155 <li> 156 <strong><?php echo esc_html( $sidrena_android_name ); ?></strong> 157 <span class="<?php echo $sidrena_android_outlet_products_ok ? 'is-ready' : 'is-pending'; ?>"><?php echo esc_html__( 'Proizvodi', 'brendigo-sidrena-cijena' ); ?>: <?php echo $sidrena_android_outlet_products_ok ? esc_html__( 'objavljeno', 'brendigo-sidrena-cijena' ) : esc_html__( 'nije objavljeno', 'brendigo-sidrena-cijena' ); ?></span> 158 <span class="<?php echo $sidrena_android_outlet_services_ok ? 'is-ready' : 'is-pending'; ?>"><?php echo esc_html__( 'Usluge', 'brendigo-sidrena-cijena' ); ?>: <?php echo $sidrena_android_outlet_services_ok ? esc_html__( 'objavljeno', 'brendigo-sidrena-cijena' ) : esc_html__( 'nije objavljeno', 'brendigo-sidrena-cijena' ); ?></span> 159 </li> 160 <?php endforeach; ?> 161 </ul> 162 <?php if ( count( $sidrena_android_outlets ) > count( $sidrena_android_outlets_shown ) ) : ?> 163 <p><?php echo esc_html__( 'Prikazano je prvih 12 poslovnica. Stanje ostalih dostupno je u javnom REST API-ju.', 'brendigo-sidrena-cijena' ); ?></p> 164 <?php endif; ?> 165 </div> 166 <?php endif; ?> 167 <?php if ( ! $sidrena_android_ready ) : ?> 168 <p class="sidrena-android-bridge__warning"><?php echo esc_html__( 'Najprije generirajte javni cjenik. Nakon objave u Android aplikaciji odaberite Osvježi. Izostanak proizvoda ili usluga u CSV datoteci dopušten je ako je datoteka ispravno objavljena.', 'brendigo-sidrena-cijena' ); ?></p> 169 <?php endif; ?> 170 </section> 88 171 89 172 <?php if ( $sidrena_generated_at > 0 ) : ?> -
brendigo-sidrena-cijena/includes/admin/tab-postavke.php
r3737238 r3801404 14 14 <div> 15 15 <p class="brendigo-section-kicker"><?php echo esc_html__( 'Pravna napomena', 'brendigo-sidrena-cijena' ); ?></p> 16 <h2><?php echo esc_html__( 'Prikaz sidrene cijene', 'brendigo-sidrena-cijena' ); ?></h2>16 <h2><?php echo esc_html__( 'Prikaz bazne cijene', 'brendigo-sidrena-cijena' ); ?></h2> 17 17 <p><?php echo esc_html__( 'Odredite naziv, datum i način prikaza referentne cijene uz proizvod.', 'brendigo-sidrena-cijena' ); ?></p> 18 18 </div> … … 28 28 <div class="sidrena-cijena-card__head brendigo-card-title"> 29 29 <span class="dashicons dashicons-desktop" aria-hidden="true"></span> 30 <div><h2><?php echo esc_html( $sidrena_woo ? __( 'Prikaz na trgovini', 'brendigo-sidrena-cijena' ) : __( 'Prikaz na web-stranici', 'brendigo-sidrena-cijena' ) ); ?></h2><p><?php echo esc_html( $sidrena_woo ? __( 'Kontrolirajte način na koji se sidrena cijena prikazuje kupcu.', 'brendigo-sidrena-cijena' ) : __( 'Postavite prikaz sidrene cijene za samostalne proizvode i usluge.', 'brendigo-sidrena-cijena' ) ); ?></p></div>30 <div><h2><?php echo esc_html( $sidrena_woo ? __( 'Prikaz na trgovini', 'brendigo-sidrena-cijena' ) : __( 'Prikaz na web-stranici', 'brendigo-sidrena-cijena' ) ); ?></h2><p><?php echo esc_html( $sidrena_woo ? __( 'Kontrolirajte način na koji se bazna cijena prikazuje kupcu.', 'brendigo-sidrena-cijena' ) : __( 'Postavite prikaz bazne cijene za samostalne proizvode i usluge.', 'brendigo-sidrena-cijena' ) ); ?></p></div> 31 31 </div> 32 32 33 33 <?php if ( $sidrena_woo ) : ?> 34 34 <div class="brendigo-setting-row"> 35 <div><strong><?php echo esc_html__( 'Automatski prikaz sidrene cijene', 'brendigo-sidrena-cijena' ); ?></strong><small><?php echo esc_html__( 'Prikaži sidrenu cijenu uz WooCommerce cijenu proizvoda.', 'brendigo-sidrena-cijena' ); ?></small></div>35 <div><strong><?php echo esc_html__( 'Automatski prikaz bazne cijene', 'brendigo-sidrena-cijena' ); ?></strong><small><?php echo esc_html__( 'Prikaži baznu cijenu uz WooCommerce cijenu proizvoda.', 'brendigo-sidrena-cijena' ); ?></small></div> 36 36 <?php $this->render_toggle( 'sidrena_cijena_auto_display', 'sidrena_cijena_auto_display', 'yes' === $sidrena_settings->get( 'auto_display' ), __( 'Automatski prikaz', 'brendigo-sidrena-cijena' ) ); ?> 37 37 </div> 38 38 <div class="brendigo-setting-row"> 39 <div><strong><?php echo esc_html__( 'Automatsko popunjavanje novih proizvoda', 'brendigo-sidrena-cijena' ); ?></strong><small><?php echo esc_html__( 'Ako su polja prazna, nova stavka može dobiti trenutačnu redovnu cijenu i datum spremanja kao vlastiti referentni datum.', 'brendigo-sidrena-cijena' ); ?></small></div> 40 <?php $this->render_toggle( 'sidrena_cijena_auto_fill', 'sidrena_cijena_auto_fill', 'yes' === $sidrena_settings->get( 'auto_fill' ), __( 'Automatsko popunjavanje', 'brendigo-sidrena-cijena' ) ); ?> 39 <div><strong><?php echo esc_html__( 'Povijesna cijena unosi se uz dokaz', 'brendigo-sidrena-cijena' ); ?></strong> 40 <small><?php echo esc_html__( 'Automatsko preslikavanje današnje redovne cijene u baznu cijenu isključeno je. Upišite stvarnu povijesnu cijenu i odgovarajući datum za svaku stavku; sačuvajte izvorne dokaze.', 'brendigo-sidrena-cijena' ); ?></small></div> 41 <span class="sidrena-android-bridge__status is-pending"><?php echo esc_html__( 'Povijesni unos: ručna provjera', 'brendigo-sidrena-cijena' ); ?></span> 41 42 </div> 42 43 <?php endif; ?> 43 44 44 45 <div class="brendigo-setting-row"> 45 <div><strong><?php echo esc_html__( 'Prikaži tooltip', 'brendigo-sidrena-cijena' ); ?></strong><small><?php echo esc_html__( 'Kupcu kratko objasnite što sidrena cijena znači.', 'brendigo-sidrena-cijena' ); ?></small></div>46 <div><strong><?php echo esc_html__( 'Prikaži tooltip', 'brendigo-sidrena-cijena' ); ?></strong><small><?php echo esc_html__( 'Kupcu kratko objasnite što bazna cijena znači.', 'brendigo-sidrena-cijena' ); ?></small></div> 46 47 <?php $this->render_toggle( 'sidrena_cijena_enable_tooltip', 'sidrena_cijena_enable_tooltip', 'yes' === $sidrena_settings->get( 'enable_tooltip' ), __( 'Tooltip', 'brendigo-sidrena-cijena' ) ); ?> 47 48 </div> … … 50 51 <span><?php echo esc_html__( 'Oznaka retka', 'brendigo-sidrena-cijena' ); ?></span> 51 52 <input type="text" id="sidrena_cijena_prefix" name="sidrena_cijena_prefix" value="<?php echo esc_attr( $sidrena_settings->get( 'prefix' ) ); ?>" /> 52 <small><?php echo esc_html__( 'Preporučeno: “ Sidrena cijena”.', 'brendigo-sidrena-cijena' ); ?></small>53 <small><?php echo esc_html__( 'Preporučeno: “Bazna cijena”.', 'brendigo-sidrena-cijena' ); ?></small> 53 54 </label> 54 55 … … 56 57 <span><?php echo esc_html__( 'Format datuma', 'brendigo-sidrena-cijena' ); ?></span> 57 58 <div class="sidrena-cijena-choices"> 58 <label class="sidrena-cijena-choice"><input type="radio" name="sidrena_cijena_date_style" value="parens" <?php checked( $sidrena_settings->get( 'date_style' ), 'parens' ); ?> /><span><?php echo esc_html__( ' Sidrena cijena (datum)', 'brendigo-sidrena-cijena' ); ?></span></label>59 <label class="sidrena-cijena-choice"><input type="radio" name="sidrena_cijena_date_style" value="plain" <?php checked( $sidrena_settings->get( 'date_style' ), 'plain' ); ?> /><span><?php echo esc_html__( ' Sidrena cijena datum', 'brendigo-sidrena-cijena' ); ?></span></label>59 <label class="sidrena-cijena-choice"><input type="radio" name="sidrena_cijena_date_style" value="parens" <?php checked( $sidrena_settings->get( 'date_style' ), 'parens' ); ?> /><span><?php echo esc_html__( 'Bazna cijena (datum)', 'brendigo-sidrena-cijena' ); ?></span></label> 60 <label class="sidrena-cijena-choice"><input type="radio" name="sidrena_cijena_date_style" value="plain" <?php checked( $sidrena_settings->get( 'date_style' ), 'plain' ); ?> /><span><?php echo esc_html__( 'Bazna cijena datum', 'brendigo-sidrena-cijena' ); ?></span></label> 60 61 </div> 61 62 <code id="sidrena-cijena-preview"><?php echo esc_html( $sidrena_settings->get_preview_label() . $sidrena_settings->preview_separator() . '19,99 €' ); ?></code> … … 95 96 96 97 <section class="sidrena-cijena-card brendigo-settings-card brendigo-live-preview"> 97 <div class="sidrena-cijena-card__head brendigo-card-title"><span class="dashicons dashicons-visibility" aria-hidden="true"></span><div><h2><?php echo esc_html__( 'Pregled prikaza', 'brendigo-sidrena-cijena' ); ?></h2><p><?php echo esc_html__( 'Pregled izgleda sidrene cijene uz proizvod.', 'brendigo-sidrena-cijena' ); ?></p></div></div>98 <div class="sidrena-cijena-card__head brendigo-card-title"><span class="dashicons dashicons-visibility" aria-hidden="true"></span><div><h2><?php echo esc_html__( 'Pregled prikaza', 'brendigo-sidrena-cijena' ); ?></h2><p><?php echo esc_html__( 'Pregled izgleda bazne cijene uz proizvod.', 'brendigo-sidrena-cijena' ); ?></p></div></div> 98 99 <div class="brendigo-preview-demo"> 99 100 <div class="brendigo-preview-demo__media"><span class="dashicons dashicons-products" aria-hidden="true"></span></div> … … 103 104 printf( 104 105 /* translators: %s: locked general reference date. */ 105 esc_html__( ' Sidrena cijena (%s)', 'brendigo-sidrena-cijena' ),106 esc_html__( 'Bazna cijena (%s)', 'brendigo-sidrena-cijena' ), 106 107 esc_html( Brendigo_Sidrena_Cijena_Settings::REFERENCE_DATE_GENERAL ) 107 108 ); … … 119 120 <?php if ( $sidrena_woo ) : ?> 120 121 <section class="sidrena-cijena-card brendigo-tools-card"> 121 <div class="sidrena-cijena-card__head brendigo-card-title"><span class="dashicons dashicons-admin-tools" aria-hidden="true"></span><div><h2><?php echo esc_html__( 'Alati za postojeći katalog', 'brendigo-sidrena-cijena' ); ?></h2><p><?php echo esc_html__( 'Masovno popunjavanje koristi se samo kada znate koja referentna cijena i datum pripadaju proizvodima.', 'brendigo-sidrena-cijena' ); ?></p></div></div> 122 <div class="brendigo-tool-actions"> 123 <button type="button" class="button button-secondary sidrena-cijena-snapshot-btn" id="sidrena-cijena-run-snapshot"><span class="dashicons dashicons-update" aria-hidden="true"></span><?php 124 printf( 125 /* translators: %s: locked general reference date. */ 126 esc_html__( 'Popuni prazne cijene s %s', 'brendigo-sidrena-cijena' ), 127 esc_html( Brendigo_Sidrena_Cijena_Settings::REFERENCE_DATE_GENERAL ) 128 ); 129 ?></button> 130 <button type="button" class="button button-secondary sidrena-cijena-snapshot-btn" id="sidrena-cijena-run-snapshot-today"><span class="dashicons dashicons-calendar-alt" aria-hidden="true"></span><?php echo esc_html__( 'Nove stavke: koristi današnji datum', 'brendigo-sidrena-cijena' ); ?></button> 122 <div class="sidrena-cijena-card__head brendigo-card-title"> 123 <span class="dashicons dashicons-shield" aria-hidden="true"></span> 124 <div><h2><?php echo esc_html__( 'Provjera povijesnih cijena', 'brendigo-sidrena-cijena' ); ?></h2> 125 <p><?php echo esc_html__( 'Masovno kopiranje trenutačnih cijena i automatsko dodavanje datuma onemogućeno je: ne dokazuje cijenu na referentni dan.', 'brendigo-sidrena-cijena' ); ?></p></div> 131 126 </div> 132 <div class="sidrena-cijena-progress" id="sidrena-snapshot-progress" hidden><div class="sidrena-cijena-progress__track"><div class="sidrena-cijena-progress__bar" id="sidrena-snapshot-bar"></div></div></div> 133 <p class="sidrena-cijena-snapshot-status" aria-live="polite"></p> 134 <div class="brendigo-info-box"><span class="dashicons dashicons-info-outline" aria-hidden="true"></span><p><?php echo esc_html__( 'Masovno popunjavanje upisuje samo prazna polja. Već spremljene vrijednosti ostaju nepromijenjene.', 'brendigo-sidrena-cijena' ); ?></p></div> 127 <div class="brendigo-info-box"> 128 <span class="dashicons dashicons-info-outline" aria-hidden="true"></span> 129 <p><?php echo esc_html__( 'Za svaku stavku utvrdite je li primjenjiv 2. 5. 2025. ili 10. 9. 2026.; koristite sačuvanu evidenciju i ručno unesite odgovarajući iznos i datum. Bazna cijena i najniža cijena u 30 dana ne smiju se automatski izvoditi iz bazne cijene.', 'brendigo-sidrena-cijena' ); ?></p> 130 </div> 135 131 </section> 136 132 <?php endif; ?> -
brendigo-sidrena-cijena/includes/admin/tab-pregled.php
r3737238 r3801404 91 91 <div> 92 92 <p class="brendigo-section-kicker"><?php echo esc_html__( 'Pregled podataka', 'brendigo-sidrena-cijena' ); ?></p> 93 <h2><?php echo esc_html__( ' Sidrene cijene i datumi na jednom mjestu', 'brendigo-sidrena-cijena' ); ?></h2>93 <h2><?php echo esc_html__( 'Bazne cijene i datumi na jednom mjestu', 'brendigo-sidrena-cijena' ); ?></h2> 94 94 <p><?php echo esc_html__( 'Uredite cijenu koja je vrijedila na odgovarajući datum, a javni cjenik i arhiva generiraju se iz spremljenih podataka.', 'brendigo-sidrena-cijena' ); ?></p> 95 95 </div> … … 102 102 </section> 103 103 104 <section class="sidrena-cijena-card brendigo-dashboard-card" aria-labelledby="sidrena-legal-2026-title"> 105 <div class="sidrena-cijena-card__head brendigo-card-title"> 106 <span class="dashicons dashicons-shield-alt" aria-hidden="true"></span> 107 <div> 108 <h2 id="sidrena-legal-2026-title"><?php echo esc_html__( 'Propisi o baznim cijenama — 2026.', 'brendigo-sidrena-cijena' ); ?></h2> 109 <p><?php 110 /* translators: %s: effective date in Croatian locale. */ 111 echo esc_html( sprintf( 112 __( 'Narodne novine 101/2026, izmjene 110/2026. Proširene obveze primjenjuju se od %s.', 'brendigo-sidrena-cijena' ), 113 wp_date( 'j. n. Y.', strtotime( Brendigo_Sidrena_Cijena_Legal::EFFECTIVE_DATE . ' 12:00:00 UTC' ) ) 114 ) ); 115 ?></p> 116 </div> 117 </div> 118 <p><?php 119 /* translators: 1: legacy FMCG reference date, 2: general reference date. */ 120 echo esc_html( sprintf( 121 __( 'Za ranije obuhvaćenu robu provjerite stvarnu cijenu na dan %1$s, a za ostalu robu i usluge na dan %2$s. Bazne cijene ne smiju se zaključivati iz sadašnje cijene.', 'brendigo-sidrena-cijena' ), 122 wp_date( 'j. n. Y.', strtotime( Brendigo_Sidrena_Cijena_Legal::REFERENCE_FMCG . ' 12:00:00 UTC' ) ), 123 wp_date( 'j. n. Y.', strtotime( Brendigo_Sidrena_Cijena_Legal::REFERENCE_GENERAL . ' 12:00:00 UTC' ) ) 124 ) ); 125 ?></p> 126 <p><?php echo esc_html__( 'Provjerite dnevnu objavu proizvoda najkasnije do 8:00, primjenjivi rok za objavu promjene cijene usluge, potpunost CSV/XML podataka po poslovnici i javnu arhivu najmanje 30 dana.', 'brendigo-sidrena-cijena' ); ?></p> 127 <?php 128 $bazna_local_today = wp_date( 'Y-m-d' ); 129 $bazna_legal_phase = Brendigo_Sidrena_Cijena_Legal::phase_on( $bazna_local_today ); 130 ?> 131 <?php if ( 'preparation' === $bazna_legal_phase ) : ?> 132 <p role="status"><?php echo esc_html__( 'Priprema za 17. studenoga 2026.: već objavljene odluke određuju budući datum primjene. Unesite i provjerite povijesne bazne cijene te testirajte dnevnu objavu cjenika prije početka primjene.', 'brendigo-sidrena-cijena' ); ?></p> 133 <?php elseif ( 'published_decisions_effective' === $bazna_legal_phase ) : ?> 134 <p role="status"><?php echo esc_html__( 'Datum primjene objavljenih odluka (17. studenoga 2026.) je nastupio. Provjerite jesu li u međuvremenu stupili na snagu novi pravilnici ili odluke koje ih zamjenjuju; ovaj dodatak ne potvrđuje pravnu usklađenost vašeg cjenika.', 'brendigo-sidrena-cijena' ); ?></p> 135 <?php endif; ?> 136 <p><?php echo esc_html__( 'Nacrti pravilnika o baznim cijenama i objavi cjenika bili su u savjetovanju do 13. studenoga 2026.; njihovu konačnu objavu i moguće izmjene treba posebno provjeriti. Bazna cijena nije isto što i najniža cijena u prethodnih 30 dana.', 'brendigo-sidrena-cijena' ); ?></p> 137 <p><a href="<?php echo esc_url( 'https://narodne-novine.nn.hr/clanci/sluzbeni/2026_09_101_1212.html' ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html__( 'Odluka NN 101/2026', 'brendigo-sidrena-cijena' ); ?></a> 138 · <a href="<?php echo esc_url( 'https://narodne-novine.nn.hr/clanci/sluzbeni/2026_09_110_1309.html' ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html__( 'Izmjena NN 110/2026', 'brendigo-sidrena-cijena' ); ?></a></p> 139 </section> 140 104 141 <section class="brendigo-kpi-grid" aria-label="<?php echo esc_attr__( 'Sažetak', 'brendigo-sidrena-cijena' ); ?>"> 105 142 <article class="brendigo-kpi-card"> 106 143 <span class="dashicons dashicons-products" aria-hidden="true"></span> 107 <div><strong><?php echo esc_html( number_format_i18n( $sidrena_count ) ); ?></strong><span><?php echo esc_html__( 'stavki s a sidrenom cijenom', 'brendigo-sidrena-cijena' ); ?></span></div>144 <div><strong><?php echo esc_html( number_format_i18n( $sidrena_count ) ); ?></strong><span><?php echo esc_html__( 'stavki s baznom cijenom', 'brendigo-sidrena-cijena' ); ?></span></div> 108 145 </article> 109 146 <article class="brendigo-kpi-card"> … … 145 182 146 183 <article class="sidrena-cijena-card brendigo-dashboard-card brendigo-product-preview"> 147 <div class="sidrena-cijena-card__head brendigo-card-title"><span class="dashicons dashicons-visibility" aria-hidden="true"></span><div><h2><?php echo esc_html__( 'Prikaz na proizvodu', 'brendigo-sidrena-cijena' ); ?></h2><p><?php echo esc_html__( 'Pregled kako će spremljena sidrena cijena izgledati uz proizvod.', 'brendigo-sidrena-cijena' ); ?></p></div></div>184 <div class="sidrena-cijena-card__head brendigo-card-title"><span class="dashicons dashicons-visibility" aria-hidden="true"></span><div><h2><?php echo esc_html__( 'Prikaz na proizvodu', 'brendigo-sidrena-cijena' ); ?></h2><p><?php echo esc_html__( 'Pregled kako će spremljena bazna cijena izgledati uz proizvod.', 'brendigo-sidrena-cijena' ); ?></p></div></div> 148 185 <?php if ( '' !== $sidrena_preview_name ) : ?> 149 186 <div class="brendigo-product-preview__body"> … … 156 193 <?php 157 194 /* translators: %s: reference date. */ 158 $sidrena_preview_anchor_label = sprintf( __( ' Sidrena cijena (%s)', 'brendigo-sidrena-cijena' ), $sidrena_preview_date );195 $sidrena_preview_anchor_label = sprintf( __( 'Bazna cijena (%s)', 'brendigo-sidrena-cijena' ), $sidrena_preview_date ); 159 196 ?> 160 197 <div class="brendigo-preview-price-row"><span><?php echo esc_html( $sidrena_preview_anchor_label ); ?></span><strong><?php echo wp_kses_post( $sidrena_preview_anchor ); ?></strong></div> 161 <div class="brendigo-preview-note"><span class="dashicons dashicons-info-outline" aria-hidden="true"></span><span><?php echo esc_html__( 'Prikaz koristi stvarne podatke proizvoda i spremljeni datum sidrene cijene.', 'brendigo-sidrena-cijena' ); ?></span></div>198 <div class="brendigo-preview-note"><span class="dashicons dashicons-info-outline" aria-hidden="true"></span><span><?php echo esc_html__( 'Prikaz koristi stvarne podatke proizvoda i spremljeni datum bazne cijene.', 'brendigo-sidrena-cijena' ); ?></span></div> 162 199 </div> 163 200 </div> 164 201 <?php else : ?> 165 <div class="brendigo-empty-state"><span class="dashicons dashicons-products" aria-hidden="true"></span><p><?php echo esc_html__( 'Dodajte sidrenu cijenu proizvodu kako bi se ovdje prikazao stvarni pregled.', 'brendigo-sidrena-cijena' ); ?></p></div>202 <div class="brendigo-empty-state"><span class="dashicons dashicons-products" aria-hidden="true"></span><p><?php echo esc_html__( 'Dodajte baznu cijenu proizvodu kako bi se ovdje prikazao stvarni pregled.', 'brendigo-sidrena-cijena' ); ?></p></div> 166 203 <?php endif; ?> 167 204 </article> -
brendigo-sidrena-cijena/includes/admin/tab-proizvodi.php
r3737238 r3801404 31 31 <div class="sidrena-cijena-callout"> 32 32 <span class="dashicons dashicons-info-outline" aria-hidden="true"></span> 33 <p><?php echo esc_html( $sidrena_woo ? __( 'Svi WooCommerce proizvodi povlače se automatski iz postojećeg kataloga i prikazuju po stranicama. Upišite samo sidrenu cijenu i, kada je potrebno, datum na koji je ta cijena vrijedila. Barkod i vidljivost možete doraditi na istom mjestu. Dodatne stavke koristite samo za ono što nije WooCommerce proizvod.', 'brendigo-sidrena-cijena' ) : __( 'Dodajte proizvode i usluge koji trebaju biti u javnom cjeniku. Za svaku stavku upišite važeću i sidrenu cijenu te datum na koji je sidrena cijena vrijedila.', 'brendigo-sidrena-cijena' ) ); ?></p>33 <p><?php echo esc_html( $sidrena_woo ? __( 'Svi WooCommerce proizvodi povlače se automatski iz postojećeg kataloga i prikazuju po stranicama. Upišite samo baznu cijenu i, kada je potrebno, datum na koji je ta cijena vrijedila. Barkod i vidljivost možete doraditi na istom mjestu. Dodatne stavke koristite samo za ono što nije WooCommerce proizvod.', 'brendigo-sidrena-cijena' ) : __( 'Dodajte proizvode i usluge koji trebaju biti u javnom cjeniku. Za svaku stavku upišite važeću i baznu cijenu te datum na koji je bazna cijena vrijedila.', 'brendigo-sidrena-cijena' ) ); ?></p> 34 34 </div> 35 35 … … 39 39 <div> 40 40 <h2><?php echo esc_html__( 'WooCommerce proizvodi', 'brendigo-sidrena-cijena' ); ?></h2> 41 <p><?php echo esc_html__( 'Katalog je stalno povezan s WooCommerceom, bez zasebnog kopiranja proizvoda. Naziv, SKU i važeća cijena ostaju na izvornom proizvodu; ovdje unosite podatke potrebne za sidrenu cijenu.', 'brendigo-sidrena-cijena' ); ?></p>41 <p><?php echo esc_html__( 'Katalog je stalno povezan s WooCommerceom, bez zasebnog kopiranja proizvoda. Naziv, SKU i važeća cijena ostaju na izvornom proizvodu; ovdje unosite podatke potrebne za baznu cijenu.', 'brendigo-sidrena-cijena' ); ?></p> 42 42 </div> 43 43 <span class="brendigo-admin-chip"><?php echo esc_html( number_format_i18n( (int) $sidrena_woo_catalog['total'] ) ); ?> <?php echo esc_html__( 'proizvoda', 'brendigo-sidrena-cijena' ); ?></span> … … 65 65 <select id="sidrena-wc-price-filter"> 66 66 <option value="all"><?php echo esc_html__( 'Svi proizvodi', 'brendigo-sidrena-cijena' ); ?></option> 67 <option value="missing"><?php echo esc_html__( 'Bez sidrene cijene', 'brendigo-sidrena-cijena' ); ?></option>68 <option value="complete"><?php echo esc_html__( 'S a sidrenom cijenom', 'brendigo-sidrena-cijena' ); ?></option>67 <option value="missing"><?php echo esc_html__( 'Bez bazne cijene', 'brendigo-sidrena-cijena' ); ?></option> 68 <option value="complete"><?php echo esc_html__( 'S baznom cijenom', 'brendigo-sidrena-cijena' ); ?></option> 69 69 </select> 70 70 </label> 71 <label> 72 <span><?php echo esc_html__( 'Datum za prazna polja', 'brendigo-sidrena-cijena' ); ?></span> 73 <input type="text" id="sidrena-wc-bulk-date" value="<?php echo esc_attr( Brendigo_Sidrena_Cijena_Settings::instance()->get( 'default_date' ) ); ?>" inputmode="numeric" /> 74 </label> 75 <button type="button" class="button button-secondary js-sidrena-wc-fill-date"><?php echo esc_html__( 'Popuni prazne datume', 'brendigo-sidrena-cijena' ); ?></button> 76 <button type="button" class="button button-secondary js-sidrena-wc-fill-price"><?php echo esc_html__( 'Preuzmi važeću cijenu u prazna polja', 'brendigo-sidrena-cijena' ); ?></button> 71 <p class="brendigo-woo-catalog-tools__note"><?php echo esc_html__( 'Baznu cijenu i povijesni datum unosite samo uz provjeru izvorne evidencije. Današnja cijena nije dokaz povijesne cijene.', 'brendigo-sidrena-cijena' ); ?></p> 77 72 </div> 78 73 <div class="brendigo-woo-catalog-summary"> … … 93 88 <th><?php echo esc_html__( 'SKU', 'brendigo-sidrena-cijena' ); ?></th> 94 89 <th><?php echo esc_html__( 'Važeća cijena', 'brendigo-sidrena-cijena' ); ?></th> 95 <th><?php echo esc_html__( ' Sidrena cijena', 'brendigo-sidrena-cijena' ); ?></th>90 <th><?php echo esc_html__( 'Bazna cijena', 'brendigo-sidrena-cijena' ); ?></th> 96 91 <th><?php echo esc_html__( 'Cijena je vrijedila na dan', 'brendigo-sidrena-cijena' ); ?></th> 97 92 <th><?php echo esc_html__( 'Barkod', 'brendigo-sidrena-cijena' ); ?></th> … … 111 106 <td class="brendigo-woo-current" data-current="<?php echo esc_attr( '' !== $sidrena_wc_row['current'] ? $sidrena_wc_row['current'] : $sidrena_wc_row['regular'] ); ?>"><?php echo '' !== $sidrena_wc_row['display'] ? wp_kses_post( $sidrena_wc_row['display'] ) : '—'; ?></td> 112 107 <td><input type="text" class="wc_input_price js-sidrena-wc-price" inputmode="decimal" name="sidrena_wc[<?php echo esc_attr( (string) $sidrena_wc_row['id'] ); ?>][price]" value="<?php echo esc_attr( $sidrena_wc_row['sidrena'] ); ?>" /></td> 113 <td><input type="text" class="js-sidrena-wc-date" inputmode="numeric" name="sidrena_wc[<?php echo esc_attr( (string) $sidrena_wc_row['id'] ); ?>][date]" value="<?php echo esc_attr( $sidrena_wc_row['date'] ); ?>" placeholder=" <?php echo esc_attr( Brendigo_Sidrena_Cijena_Settings::instance()->get( 'default_date' ) ); ?>" /></td>108 <td><input type="text" class="js-sidrena-wc-date" inputmode="numeric" name="sidrena_wc[<?php echo esc_attr( (string) $sidrena_wc_row['id'] ); ?>][date]" value="<?php echo esc_attr( $sidrena_wc_row['date'] ); ?>" placeholder="DD.MM.GGGG." /></td> 114 109 <td><input type="text" name="sidrena_wc[<?php echo esc_attr( (string) $sidrena_wc_row['id'] ); ?>][barcode]" value="<?php echo esc_attr( $sidrena_wc_row['barcode'] ); ?>" /></td> 115 110 <td><select name="sidrena_wc[<?php echo esc_attr( (string) $sidrena_wc_row['id'] ); ?>][visibility]"><option value="auto"<?php selected( $sidrena_wc_row['visibility'], 'auto' ); ?>><?php echo esc_html__( 'Automatski', 'brendigo-sidrena-cijena' ); ?></option><option value="include"<?php selected( $sidrena_wc_row['visibility'], 'include' ); ?>><?php echo esc_html__( 'Uključi', 'brendigo-sidrena-cijena' ); ?></option><option value="exclude"<?php selected( $sidrena_wc_row['visibility'], 'exclude' ); ?>><?php echo esc_html__( 'Isključi', 'brendigo-sidrena-cijena' ); ?></option></select></td> … … 123 118 <div class="brendigo-woo-catalog-footer"> 124 119 <div class="brendigo-woo-catalog-footer__actions"> 125 <button type="submit" class="button button-primary button-hero js-sidrena-wc-save"><?php echo esc_html__( 'Spremi sidrene cijene', 'brendigo-sidrena-cijena' ); ?></button>120 <button type="submit" class="button button-primary button-hero js-sidrena-wc-save"><?php echo esc_html__( 'Spremi bazne cijene', 'brendigo-sidrena-cijena' ); ?></button> 126 121 <button type="button" class="button button-secondary js-sidrena-wc-reset"><?php echo esc_html__( 'Poništi nespremljene promjene', 'brendigo-sidrena-cijena' ); ?></button> 127 122 </div> … … 220 215 <th><?php echo esc_html__( 'Jedinica mjere', 'brendigo-sidrena-cijena' ); ?></th> 221 216 <th><?php echo esc_html__( 'Cijena za jedinicu', 'brendigo-sidrena-cijena' ); ?></th> 222 <th><?php echo esc_html__( ' Sidrena cijena', 'brendigo-sidrena-cijena' ); ?></th>217 <th><?php echo esc_html__( 'Bazna cijena', 'brendigo-sidrena-cijena' ); ?></th> 223 218 <th><?php echo esc_html__( 'Datum sidrene', 'brendigo-sidrena-cijena' ); ?></th> 224 219 <?php if ( Brendigo_Sidrena_Cijena_Settings::instance()->is_cjm_enabled() ) : ?> -
brendigo-sidrena-cijena/includes/admin/tab-upute.php
r3737238 r3801404 29 29 'title' => __( 'Prije prvog korištenja', 'brendigo-sidrena-cijena' ), 30 30 'steps' => array( 31 array( __( 'Za novu instalaciju otvorite Dodaci → Dodaj novi → Prenesi dodatak, odaberite SIDRENA ZIP i aktivirajte ga. Pri nadogradnji postojećeg dodatka prvo napravite sigurnosnu kopiju.', 'brendigo-sidrena-cijena' ), 'wp-plugins', __( 'Otvori dodatke', 'brendigo-sidrena-cijena' ) ),31 array( __( 'Za novu instalaciju otvorite Dodaci → Dodaj novi → Prenesi dodatak, odaberite BAZNA ZIP i aktivirajte ga. Pri nadogradnji postojećeg dodatka prvo napravite sigurnosnu kopiju.', 'brendigo-sidrena-cijena' ), 'wp-plugins', __( 'Otvori dodatke', 'brendigo-sidrena-cijena' ) ), 32 32 array( __( 'Napravite sigurnosnu kopiju stranice i baze podataka, posebno ako prelazite sa starije verzije dodatka.', 'brendigo-sidrena-cijena' ) ), 33 33 array( __( 'U WordPressu otvorite Postavke → Općenito i provjerite vremensku zonu stranice. Ona određuje vrijeme dnevne objave.', 'brendigo-sidrena-cijena' ), 'wp-settings', __( 'Otvori postavke WordPressa', 'brendigo-sidrena-cijena' ) ), 34 34 array( __( 'U kartici Poslovnice provjerite naziv vrste objekta, adresu i oznaku. Ako imate više lokacija, unesite svaku zasebno i spremite.', 'brendigo-sidrena-cijena' ), 'poslovnice', __( 'Otvori Poslovnice', 'brendigo-sidrena-cijena' ) ), 35 array( __( 'Nemojte prepisivati sidrenu cijenu današnjom cijenom. Unesite samo iznos i datum za koje imate stvarnu evidenciju.', 'brendigo-sidrena-cijena' ) ),35 array( __( 'Nemojte prepisivati baznu cijenu današnjom cijenom. Unesite samo iznos i datum za koje imate stvarnu evidenciju.', 'brendigo-sidrena-cijena' ) ), 36 36 ), 37 37 ), … … 42 42 'intro' => __( 'Za cjenik proizvoda i usluga ne trebate internetsku trgovinu. Ovaj način rada ne uključuje košaricu ni naplatu.', 'brendigo-sidrena-cijena' ), 43 43 'steps' => array( 44 array( __( 'Nakon aktivacije u lijevom izborniku otvorite B rendigo Sidrena Cijena→ Proizvodi i usluge.', 'brendigo-sidrena-cijena' ), 'proizvodi', __( 'Otvori proizvode i usluge', 'brendigo-sidrena-cijena' ) ),44 array( __( 'Nakon aktivacije u lijevom izborniku otvorite BAZNA → Proizvodi i usluge.', 'brendigo-sidrena-cijena' ), 'proizvodi', __( 'Otvori proizvode i usluge', 'brendigo-sidrena-cijena' ) ), 45 45 array( __( 'Kliknite „Dodaj proizvod ili uslugu” i odaberite vrstu stavke. Unesite naziv i redovnu cijenu; ostala polja, poput SKU-a, barkoda, marke i mjerne jedinice, ispunite kada su potrebna.', 'brendigo-sidrena-cijena' ) ), 46 array( __( 'U polje „ Sidrena cijena” upišite stvarni iznos iz evidencije, a u „Datum sidrene” odgovarajući datum. Za novu stavku ne izmišljajte cijenu iz ranijeg razdoblja.', 'brendigo-sidrena-cijena' ) ),46 array( __( 'U polje „Bazna cijena” upišite stvarni iznos iz evidencije, a u „Cijena je vrijedila na dan” odgovarajući datum. Za novu stavku ne izmišljajte cijenu iz ranijeg razdoblja.', 'brendigo-sidrena-cijena' ) ), 47 47 array( __( 'Ako imate više poslovnica, odaberite onu kojoj stavka pripada. Zatim kliknite „Spremi cjenik”.', 'brendigo-sidrena-cijena' ) ), 48 48 array( __( 'Otvorite „Javni cjenik”, kliknite „Objavi cjenik sada” i potom „Otvori javni cjenik”. Provjerite naziv, iznose, datume i dostupnost.', 'brendigo-sidrena-cijena' ), 'javni-xml', __( 'Otvori Javni cjenik', 'brendigo-sidrena-cijena' ) ), 49 array( __( 'Ako želite cjenik na svojoj WordPress stranici, dodajte stranicu, umetnite blok „Kratki kod” i zalijepite [ sidrena-cjenik]. Za javnu arhivu koristite [sidrena-arhiva].', 'brendigo-sidrena-cijena' ), 'wp-pages', __( 'Otvori stranice', 'brendigo-sidrena-cijena' ) ),49 array( __( 'Ako želite cjenik na svojoj WordPress stranici, dodajte stranicu, umetnite blok „Kratki kod” i zalijepite [bazna_cjenik]. Za javnu arhivu koristite [bazna_arhiva]. Stari kratki kodovi [sidrena-cjenik] i [sidrena-arhiva] ostaju podržani radi kompatibilnosti.', 'brendigo-sidrena-cijena' ), 'wp-pages', __( 'Otvori stranice', 'brendigo-sidrena-cijena' ) ), 50 50 ), 51 51 ); … … 53 53 $sidrena_help_woocommerce = array( 54 54 'title' => __( 'Upute: WordPress s WooCommerceom', 'brendigo-sidrena-cijena' ), 55 'intro' => __( 'WooCommerce upravlja nazivima proizvoda, zalihama i aktualnim cijenama. SIDRENA dodaje sidrene podatkei javne cjenike; proizvode nije potrebno ponovno unositi.', 'brendigo-sidrena-cijena' ),55 'intro' => __( 'WooCommerce upravlja nazivima proizvoda, zalihama i aktualnim cijenama. BAZNA dodaje podatke o baznim cijenama i javne cjenike; proizvode nije potrebno ponovno unositi.', 'brendigo-sidrena-cijena' ), 56 56 'steps' => array( 57 57 array( __( 'Provjerite jesu li WooCommerce i vaši proizvodi ispravno postavljeni. Otvorite Proizvodi → Svi proizvodi i pregledajte redovne, akcijske cijene te varijacije.', 'brendigo-sidrena-cijena' ), 'woo-products', __( 'Otvori WooCommerce proizvode', 'brendigo-sidrena-cijena' ) ), 58 array( __( 'Otvorite WooCommerce → B rendigo Sidrena Cijena → Dodatne stavke. U gornjem dijelu prikazani su WooCommerce proizvodi povezani s trgovinom.', 'brendigo-sidrena-cijena' ), 'proizvodi', __( 'Otvori Dodatne stavke', 'brendigo-sidrena-cijena' ) ),59 array( __( 'Za svaki proizvod ili varijaciju unesite točnu „ Sidrenu cijenu” i „Cijena je vrijedila na dan”. Po potrebi upišite barkod te odaberite prikaz u javnom cjeniku.', 'brendigo-sidrena-cijena' ) ),60 array( __( 'Kliknite „Spremi sidrene cijene”. Ne koristite „Preuzmi važeću cijenu u prazna polja” kao zamjenu za povijesnu evidenciju.', 'brendigo-sidrena-cijena' ) ),61 array( __( 'U Postavkama po potrebi uključite „Automatski prikaz sidrene cijene”, spremite, a zatim otvorite javnu stranicu proizvoda i provjerite rezultat.', 'brendigo-sidrena-cijena' ), 'postavke', __( 'Otvori Postavke', 'brendigo-sidrena-cijena' ) ),58 array( __( 'Otvorite WooCommerce → BAZNA – Bazne cijene → Proizvodi i usluge. U gornjem dijelu prikazani su WooCommerce proizvodi povezani s trgovinom.', 'brendigo-sidrena-cijena' ), 'proizvodi', __( 'Otvori Dodatne stavke', 'brendigo-sidrena-cijena' ) ), 59 array( __( 'Za svaki proizvod ili varijaciju unesite točnu „Baznu cijenu” i „Cijena je vrijedila na dan”. Po potrebi upišite barkod te odaberite prikaz u javnom cjeniku.', 'brendigo-sidrena-cijena' ) ), 60 array( __( 'Kliknite „Spremi bazne cijene”. Ne koristite „Preuzmi važeću cijenu u prazna polja” kao zamjenu za povijesnu evidenciju.', 'brendigo-sidrena-cijena' ) ), 61 array( __( 'U Postavkama po potrebi uključite „Automatski prikaz bazne cijene”, spremite, a zatim otvorite javnu stranicu proizvoda i provjerite rezultat.', 'brendigo-sidrena-cijena' ), 'postavke', __( 'Otvori Postavke', 'brendigo-sidrena-cijena' ) ), 62 62 array( __( 'U Javnom cjeniku objavite podatke. Pregledajte jednostavne proizvode, svaku varijaciju, datume, poreze, košaricu i naplatu. Prikaz može ovisiti o temi i blokovima.', 'brendigo-sidrena-cijena' ), 'javni-xml', __( 'Otvori Javni cjenik', 'brendigo-sidrena-cijena' ) ), 63 63 array( __( 'Stavke koje nisu WooCommerce proizvodi (npr. usluge) možete dodatno unijeti u donji dio kartice „Dodatne stavke”. Ne unosite iste proizvode dvaput.', 'brendigo-sidrena-cijena' ) ), … … 146 146 <section id="sidrena-help-faq" class="sidrena-cijena-card sidrena-help__section" aria-labelledby="sidrena-help-faq-title"> 147 147 <h2 id="sidrena-help-faq-title"><?php echo esc_html__( 'Česta pitanja i rješavanje problema', 'brendigo-sidrena-cijena' ); ?></h2> 148 <details><summary><?php echo esc_html__( 'Ne vidim cijenu ili se promjena ne prikazuje javno.', 'brendigo-sidrena-cijena' ); ?></summary><p><?php echo esc_html__( 'Provjerite je li stavka spremljena, ima li ispravnu sidrenu cijenu i datum te je li uključena u javni cjenik. Zatim u Javnom cjeniku ponovno pokrenite objavu. Ako i dalje nema promjene, očistite predmemoriju stranice i preglednika.', 'brendigo-sidrena-cijena' ); ?></p></details>148 <details><summary><?php echo esc_html__( 'Ne vidim cijenu ili se promjena ne prikazuje javno.', 'brendigo-sidrena-cijena' ); ?></summary><p><?php echo esc_html__( 'Provjerite je li stavka spremljena, ima li ispravnu baznu cijenu i datum te je li uključena u javni cjenik. Zatim u Javnom cjeniku ponovno pokrenite objavu. Ako i dalje nema promjene, očistite predmemoriju stranice i preglednika.', 'brendigo-sidrena-cijena' ); ?></p></details> 149 149 <details><summary><?php echo esc_html__( 'Svakodnevna objava nije pokrenuta na vrijeme.', 'brendigo-sidrena-cijena' ); ?></summary><p><?php echo esc_html__( 'Provjerite vremensku zonu WordPressa, uključenu dnevnu objavu i povijest objava. WordPressovi zakazani zadaci ovise o prometu ili poslužiteljskom rasporedu. Kontaktirajte hosting za pouzdan cron i provjerite je li e-mail za upozorenja ispravan.', 'brendigo-sidrena-cijena' ); ?></p></details> 150 <details><summary><?php echo esc_html__( 'Kako izbjegavam pogreške s povijesnom cijenom?', 'brendigo-sidrena-cijena' ); ?></summary><p><?php echo esc_html__( ' Sidrenu cijenu unosite samo prema svojoj stvarnoj evidenciji za propisani datum. Povijest koju plugin prikuplja počinje tek od uključivanja praćenja; ne dokazuje ranije cijene. Najniža cijena prije sniženja zaseban je podatak i ne zamjenjuje sidrenu cijenu.', 'brendigo-sidrena-cijena' ); ?></p></details>150 <details><summary><?php echo esc_html__( 'Kako izbjegavam pogreške s povijesnom cijenom?', 'brendigo-sidrena-cijena' ); ?></summary><p><?php echo esc_html__( 'Baznu cijenu unosite samo prema svojoj stvarnoj evidenciji za propisani datum. Povijest koju plugin prikuplja počinje tek od uključivanja praćenja; ne dokazuje ranije cijene. Najniža cijena prije sniženja zaseban je podatak i ne zamjenjuje baznu cijenu.', 'brendigo-sidrena-cijena' ); ?></p></details> 151 151 <details><summary><?php echo esc_html__( 'Mogu li koristiti plugin bez webshopa?', 'brendigo-sidrena-cijena' ); ?></summary><p><?php echo esc_html__( 'Da. Ručno unesite proizvode i usluge pa objavite javni HTML/XML/CSV cjenik. WooCommerce je potreban samo za funkcije trgovine poput narudžbi i naplate.', 'brendigo-sidrena-cijena' ); ?></p></details> 152 152 <details><summary><?php echo esc_html__( 'Kako postupiti ako uvoz ne uspije?', 'brendigo-sidrena-cijena' ); ?></summary><p><?php echo esc_html__( 'Provjerite format datoteke, mapiranje stupaca, prazne cijene i duple SKU vrijednosti. Ne pokrećite opet isti uvoz naslijepo. Ako ste već promijenili cijene, upotrijebite sigurnosnu kopiju ili ručno provjerite podatke.', 'brendigo-sidrena-cijena' ); ?></p></details> -
brendigo-sidrena-cijena/includes/admin/tab-uvoz-izvoz.php
r3737238 r3801404 12 12 <div class="sidrena-cijena-card__head"> 13 13 <h2><?php echo esc_html__( 'Uvoz cjenika', 'brendigo-sidrena-cijena' ); ?></h2> 14 <p><?php echo esc_html( Brendigo_Sidrena_Cijena_Plugin::woocommerce_active() ? __( 'Učitajte CSV, XML ili XLSX. Retci se spajaju prvo po SKU-u, a ako SKU ne nađe proizvod onda po postojećem stupcu ID. Uvoz u webshop ažurira Woo proizvod, uključujući zalihu. Uvoz u drugu poslovnicu upisuje dostupnost samo na tu poslovnicu. Ako ni SKU ni ID ne pogode postojeći proizvod, redak postaje ručna stavka te poslovnice.', 'brendigo-sidrena-cijena' ) : __( 'Učitajte CSV, XML ili XLSX. Retci se spajaju prvo po SKU-u u odabranoj poslovnici, zatim po ID-u. Ostali se dodaju u taj cjenik. Naziv, redovna i sidrena cijena su obavezni za nove retke. Prazna polja ne brišu postojeće vrijednosti.', 'brendigo-sidrena-cijena' ) ); ?></p>14 <p><?php echo esc_html( Brendigo_Sidrena_Cijena_Plugin::woocommerce_active() ? __( 'Učitajte CSV, XML ili XLSX. Retci se spajaju prvo po SKU-u, a ako SKU ne nađe proizvod onda po postojećem stupcu ID. Uvoz u webshop ažurira Woo proizvod, uključujući zalihu. Uvoz u drugu poslovnicu upisuje dostupnost samo na tu poslovnicu. Ako ni SKU ni ID ne pogode postojeći proizvod, redak postaje ručna stavka te poslovnice.', 'brendigo-sidrena-cijena' ) : __( 'Učitajte CSV, XML ili XLSX. Retci se spajaju prvo po SKU-u u odabranoj poslovnici, zatim po ID-u. Ostali se dodaju u taj cjenik. Naziv, redovna i bazna cijena su obavezni za nove retke. Prazna polja ne brišu postojeće vrijednosti.', 'brendigo-sidrena-cijena' ) ); ?></p> 15 15 </div> 16 16 … … 62 62 </label> 63 63 <label class="sidrena-cijena-mapfield"> 64 <span><?php echo esc_html__( ' Sidrena cijena', 'brendigo-sidrena-cijena' ); ?></span>64 <span><?php echo esc_html__( 'Bazna cijena', 'brendigo-sidrena-cijena' ); ?></span> 65 65 <select id="sidrena-import-map-sidrena"></select> 66 66 </label> 67 67 <label class="sidrena-cijena-mapfield"> 68 <span><?php echo esc_html__( ' Sidrena cijena datum', 'brendigo-sidrena-cijena' ); ?></span>68 <span><?php echo esc_html__( 'Bazna cijena datum', 'brendigo-sidrena-cijena' ); ?></span> 69 69 <select id="sidrena-import-map-datum"></select> 70 70 </label> … … 144 144 <div class="sidrena-cijena-card__head"> 145 145 <h2><?php echo esc_html__( 'Izvoz cjenika', 'brendigo-sidrena-cijena' ); ?></h2> 146 <p><?php echo esc_html__( 'Izvoz cjenika je isti javni CSV ili XML: vrsta, datum, maloprodajna cijena, marka, naziv posebnog oblika, jedinica mjere, cijena jedinice mjere, sidrena cijena, barkod i dostupnost. Uključeni su samo objavljeni proizvodi. Varijacije su zasebni redovi, a dodatne stavke idu na kraj. Izvoz bez sidrene cijene ostaje interni popis (naziv, SKU, redovna, akcijska i sidrena cijena).', 'brendigo-sidrena-cijena' ); ?></p>146 <p><?php echo esc_html__( 'Izvoz cjenika je isti javni CSV ili XML: vrsta, datum, maloprodajna cijena, marka, naziv posebnog oblika, jedinica mjere, cijena jedinice mjere, bazna cijena, barkod i dostupnost. Uključeni su samo objavljeni proizvodi. Varijacije su zasebni redovi, a dodatne stavke idu na kraj. Izvoz bez bazne cijene ostaje interni popis (naziv, SKU, redovna, akcijska i bazna cijena).', 'brendigo-sidrena-cijena' ); ?></p> 147 147 </div> 148 148 <form method="post" action="<?php echo esc_url( $this->get_settings_tab_url( 'uvoz-izvoz' ) ); ?>"> … … 162 162 <button type="submit" class="button button-secondary" name="sidrena_cijena_action" value="export_missing"> 163 163 <span class="dashicons dashicons-download" aria-hidden="true"></span> 164 <?php echo esc_html__( 'Izvezi proizvode bez sidrene cijene', 'brendigo-sidrena-cijena' ); ?>164 <?php echo esc_html__( 'Izvezi proizvode bez bazne cijene', 'brendigo-sidrena-cijena' ); ?> 165 165 </button> 166 166 <button type="submit" class="button button-secondary" name="sidrena_cijena_action" value="export_template"> -
brendigo-sidrena-cijena/includes/class-activator.php
r3727711 r3801404 30 30 31 31 /** 32 * Process one short slice of products, then reschedule if needed. 33 * 34 * A page is 40 parents, but each HTTP request stops after WORK_BUDGET 35 * product objects so a proxy timeout cannot drop the rest of the catalog. 36 * Offset and child resume inside the same page. 37 * 38 * @param int $page Optional explicit page. 0 reads the stored cursor. 39 * @param bool $stamp_today Also write today's date when the date field is empty. 40 * @param int $offset Parent index inside the current page. 41 * @param int $child Variation index inside the current parent. 42 * @return array{done:bool,processed:int,written:int,page:int,next_page:int,next_offset:int,next_child:int,total:int,seen:int} 32 * Deprecated cron entry point. Kept only so existing scheduled events can 33 * run safely after plugin updates: remove legacy cursors and never infer 34 * historical prices from current prices or today's date. 35 * 36 * @return array<string,int|bool> Blocked status for legacy consumers. 43 37 */ 44 38 public static function process_batch( $page = 0, $stamp_today = false, $offset = 0, $child = 0 ) { 45 ignore_user_abort( true ); 46 47 $page = absint( $page ); 48 $offset = absint( $offset ); 49 $child = absint( $child ); 50 if ( $page < 1 ) { 51 $page = max( 1, absint( get_option( self::PAGE_OPTION, 1 ) ) ); 52 $offset = absint( get_option( self::OFFSET_OPTION, 0 ) ); 53 $child = absint( get_option( self::CHILD_OPTION, 0 ) ); 54 } 55 56 $ids = self::snapshot_ids( $page ); 57 $total = self::snapshot_total(); 58 59 $meta = Brendigo_Sidrena_Cijena_Product_Meta::instance(); 60 $date = $stamp_today ? Brendigo_Sidrena_Cijena_Product_Meta::today_date() : ''; 61 $processed = 0; 62 $written = 0; 63 $budget = self::WORK_BUDGET; 64 $advanced = 0; 65 $next_child = 0; 66 $slice = array_slice( $ids, $offset ); 67 68 foreach ( $slice as $product_id ) { 69 if ( $budget < 1 && $advanced > 0 ) { 70 break; 71 } 72 73 $product = wc_get_product( $product_id ); 74 if ( ! $product ) { 75 ++$advanced; 76 $child = 0; 77 continue; 78 } 79 80 ++$processed; 81 --$budget; 82 83 if ( $product->is_type( 'variable' ) || $product->is_type( 'variable-subscription' ) ) { 84 $children = array_values( $product->get_children() ); 85 $start = $child; 86 $child = 0; 87 $count = count( $children ); 88 89 for ( $i = $start; $i < $count; $i++ ) { 90 if ( $budget < 1 ) { 91 $next_child = $i; 92 break 2; 93 } 94 95 $variation = wc_get_product( $children[ $i ] ); 96 if ( $variation && $meta->snapshot_if_empty( $variation, $date ) ) { 97 ++$written; 98 } 99 --$budget; 100 } 101 102 ++$advanced; 103 continue; 104 } 105 106 if ( $meta->snapshot_if_empty( $product, $date ) ) { 107 ++$written; 108 } 109 $child = 0; 110 ++$advanced; 111 } 112 113 $next_offset = $offset + $advanced; 114 $page_complete = ( $next_child < 1 ) && ( $next_offset >= count( $ids ) ); 115 $done = $page_complete && count( $ids ) < self::BATCH_SIZE; 116 $next_page = $page; 117 $consumed = $page_complete ? count( $ids ) : $next_offset; 118 119 if ( $page_complete && ! $done ) { 120 $next_page = $page + 1; 121 $next_offset = 0; 122 } 123 124 $seen = $done ? $total : ( ( $page - 1 ) * self::BATCH_SIZE ) + $consumed; 125 if ( $total < $seen ) { 126 $total = $seen; 127 } 128 129 if ( $done ) { 130 delete_option( self::PENDING_OPTION ); 131 delete_option( self::PAGE_OPTION ); 132 delete_option( self::OFFSET_OPTION ); 133 delete_option( self::CHILD_OPTION ); 134 delete_option( self::FILL_PROMPT_OPTION ); 135 if ( class_exists( 'Brendigo_Sidrena_Cijena_Automation' ) ) { 136 Brendigo_Sidrena_Cijena_Automation::instance()->queue_rebuild( 'snapshot-complete' ); 137 } 138 } else { 139 update_option( self::PAGE_OPTION, $next_page, false ); 140 update_option( self::OFFSET_OPTION, $next_offset, false ); 141 update_option( self::CHILD_OPTION, $next_child, false ); 142 if ( ! wp_next_scheduled( 'sidrena_cijena_snapshot_batch' ) ) { 143 wp_schedule_single_event( time() + 2, 'sidrena_cijena_snapshot_batch' ); 144 } 145 } 146 147 return array( 148 'done' => $done, 149 'processed' => $processed, 150 'written' => $written, 151 'page' => $page, 152 'next_page' => $done ? $page : $next_page, 153 'next_offset' => $done ? 0 : $next_offset, 154 'next_child' => $done ? 0 : $next_child, 155 'total' => $total, 156 'seen' => $seen, 157 ); 158 } 159 160 /** 161 * Parent IDs for one snapshot page, ordered by ID. 162 * 163 * @param int $page 1-based page. 164 * @return array<int,int> 165 */ 166 private static function snapshot_ids( $page ) { 167 $ids = wc_get_products( self::snapshot_query_args( $page, self::BATCH_SIZE ) ); 168 169 return is_array( $ids ) ? array_map( 'absint', $ids ) : array(); 170 } 171 172 /** 173 * How many parent products the snapshot walks. 174 * 175 * @return int 176 */ 177 private static function snapshot_total() { 178 $query = wc_get_products( self::snapshot_query_args( 1, 1, true ) ); 179 if ( is_object( $query ) && isset( $query->total ) ) { 180 return (int) $query->total; 181 } 182 183 return 0; 184 } 185 186 /** 187 * Shared product query for the admin/cron snapshot. 188 * 189 * @param int $page 1-based page. 190 * @param int $limit Page size. 191 * @param bool $paginate Return a result object with a total. 192 * @return array<string,mixed> 193 */ 194 private static function snapshot_query_args( $page, $limit, $paginate = false ) { 195 return array( 196 'status' => array( 'publish', 'private', 'draft', 'pending' ), 197 'type' => array( 'simple', 'variable', 'external', 'subscription', 'variable-subscription' ), 198 'limit' => $limit, 199 'page' => max( 1, absint( $page ) ), 200 'paginate' => (bool) $paginate, 201 'return' => 'ids', 202 'orderby' => 'ID', 203 'order' => 'ASC', 204 ); 39 // Stop legacy scheduled snapshot work: current prices are not historical evidence. 40 self::clear_pending_state(); 41 return array( 'done' => true, 'processed' => 0, 'written' => 0, 42 'page' => 0, 'next_page' => 0, 'next_offset' => 0, 43 'next_child' => 0, 'total' => 0, 'seen' => 0, 44 'blocked' => true ); 45 // Historical-price autofill is intentionally prohibited; legacy cron 46 // callbacks remain registered only to clear stale pending work safely. 205 47 } 206 48 … … 265 107 266 108 $stats_before = self::catalog_stats(); 109 110 if ( ! $dry_run ) { 111 // Read-only audit is allowed, but bulk historic values cannot be guessed. 112 return array( 'written' => 0, 'processed' => 0, 'updated' => 0, 113 'inserted' => 0, 'missing_before' => (int) $stats_before['missing'], 114 'dry_run' => false, 'fast' => $fast, 'blocked' => true ); 115 } 267 116 268 117 if ( $fast ) { … … 324 173 */ 325 174 public static function fill_page( $page, $batch_size = 250, $dry_run = false, $stamp_date = '' ) { 175 if ( ! $dry_run ) { 176 return array( 'done' => true, 'processed' => 0, 'written' => 0, 'page' => $page, 'blocked' => true ); 177 } 326 178 $page = max( 1, absint( $page ) ); 327 179 $batch_size = max( 1, absint( $batch_size ) ); … … 398 250 */ 399 251 public static function fast_fill( $dry_run = false ) { 252 if ( ! $dry_run ) { 253 return array( 'written' => 0, 'updated' => 0, 'inserted' => 0, 'blocked' => true ); 254 } 400 255 global $wpdb; 401 256 -
brendigo-sidrena-cijena/includes/class-admin-save.php
r3737238 r3801404 153 153 $payload['brand_taxonomy'] = isset( $_POST['sidrena_cijena_brand_taxonomy'] ) ? sanitize_text_field( wp_unslash( $_POST['sidrena_cijena_brand_taxonomy'] ) ) : ''; 154 154 $payload['auto_display'] = isset( $_POST['sidrena_cijena_auto_display'] ) ? 'yes' : 'no'; 155 $payload['auto_fill'] = isset( $_POST['sidrena_cijena_auto_fill'] ) ? 'yes' : 'no';155 $payload['auto_fill'] = 'no'; // Historical values must be verified, never inferred. 156 156 } 157 157 … … 386 386 wp_send_json_error( array( 'message' => 'forbidden' ), 403 ); 387 387 } 388 // Legacy AJAX URLs must not bypass the legal protection when the 389 // removed UI controls are invoked directly or by an old cached script. 390 wp_send_json_error( 391 array( 'message' => __( 'Masovno zaključivanje povijesnih cijena onemogućeno je. Unesite provjerenu cijenu i datum za svaku stavku.', 'brendigo-sidrena-cijena' ) ), 392 409 393 ); 394 return; 388 395 389 396 while ( ob_get_level() > 0 ) { -
brendigo-sidrena-cijena/includes/class-admin.php
r3737344 r3801404 64 64 65 65 /** 66 * Whether the current request is the Sidrena cijena settings screen.66 * Whether the current request is the Bazna cijena settings screen. 67 67 * 68 68 * @return bool … … 119 119 public function register_menu() { 120 120 $cap = Brendigo_Sidrena_Cijena_Plugin::manage_capability(); 121 $title = __( 'B rendigo Sidrena Cijena', 'brendigo-sidrena-cijena' );121 $title = __( 'BAZNA – Bazne cijene', 'brendigo-sidrena-cijena' ); 122 122 123 123 if ( Brendigo_Sidrena_Cijena_Plugin::woocommerce_active() ) { … … 163 163 $multi = $settings->is_multi_poslovnica(); 164 164 $xml_url = $export->get_public_url(); 165 $page_title = 'pregled' === $tab ? __( 'B rendigo Sidrena Cijena', 'brendigo-sidrena-cijena' ) : ( isset( $tabs[ $tab ]['label'] ) ? $tabs[ $tab ]['label'] : __( 'Brendigo Sidrena Cijena', 'brendigo-sidrena-cijena' ) );165 $page_title = 'pregled' === $tab ? __( 'BAZNA – Bazne cijene', 'brendigo-sidrena-cijena' ) : ( isset( $tabs[ $tab ]['label'] ) ? $tabs[ $tab ]['label'] : __( 'BAZNA – Bazne cijene', 'brendigo-sidrena-cijena' ) ); 166 166 $page_subtitles = array( 167 'pregled' => __( ' Sidrene cijene, digitalni cjenik, arhiva, poslovnice i razmjena podataka u jednom sučelju.', 'brendigo-sidrena-cijena' ),167 'pregled' => __( 'Bazne cijene, digitalni cjenik, arhiva, poslovnice i razmjena podataka u jednom sučelju.', 'brendigo-sidrena-cijena' ), 168 168 'proizvodi' => __( 'Ručno upravljanje proizvodima i uslugama koje ulaze u javni cjenik.', 'brendigo-sidrena-cijena' ), 169 'postavke' => __( 'Prikaz, tekstovi, pravila i alati za sidrene cijene.', 'brendigo-sidrena-cijena' ),170 'uvoz-izvoz' => __( 'CSV i XML razmjena podataka za sidrene cijene i javni cjenik.', 'brendigo-sidrena-cijena' ),169 'postavke' => __( 'Prikaz, tekstovi, pravila i alati za bazne cijene.', 'brendigo-sidrena-cijena' ), 170 'uvoz-izvoz' => __( 'CSV i XML razmjena podataka za bazne cijene i javni cjenik.', 'brendigo-sidrena-cijena' ), 171 171 'javni-xml' => __( 'HTML prikaz, XML/CSV datoteke i arhiva javnog cjenika.', 'brendigo-sidrena-cijena' ), 172 172 'poslovnice' => __( 'Više lokacija, zasebni javni cjenici i datoteke po poslovnici.', 'brendigo-sidrena-cijena' ), … … 177 177 <div class="wrap sidrena-cijena-settings brendigo-sidrena-admin"> 178 178 <div class="brendigo-admin-shell"> 179 <aside class="brendigo-admin-sidebar" aria-label="<?php echo esc_attr__( 'B rendigo Sidrena Cijena', 'brendigo-sidrena-cijena' ); ?>">179 <aside class="brendigo-admin-sidebar" aria-label="<?php echo esc_attr__( 'BAZNA – Bazne cijene', 'brendigo-sidrena-cijena' ); ?>"> 180 180 <a class="brendigo-admin-brand" href="<?php echo esc_url( $this->get_settings_tab_url( 'pregled' ) ); ?>"> 181 <span class="brendigo-admin-brand__mark brendigo-admin-brand__mark-- sidrena" aria-hidden="true"><img src="<?php echo esc_url( BRENDIGO_SIDRENA_CIJENA_URL . 'assets/images/sidrena-brand-mark.png' ); ?>" alt="" width="48" height="48" loading="eager" decoding="async" /></span>182 <span class="brendigo-admin-brand__text"><strong> SIDRENA</strong><small>Brendigo</small></span>181 <span class="brendigo-admin-brand__mark brendigo-admin-brand__mark--bazna" aria-hidden="true">B</span> 182 <span class="brendigo-admin-brand__text"><strong>BAZNA</strong><small>Brendigo</small></span> 183 183 </a> 184 184 <nav class="brendigo-admin-nav"> … … 192 192 <div class="brendigo-admin-sidebar__legal"> 193 193 <span class="dashicons dashicons-info-outline" aria-hidden="true"></span> 194 <strong><?php echo esc_html__( ' Sidrena cijena', 'brendigo-sidrena-cijena' ); ?></strong>194 <strong><?php echo esc_html__( 'Bazna cijena', 'brendigo-sidrena-cijena' ); ?></strong> 195 195 <small><?php echo esc_html__( 'Referentna cijena s datumom na koji je vrijedila.', 'brendigo-sidrena-cijena' ); ?></small> 196 196 </div> … … 200 200 <header class="brendigo-admin-topbar"> 201 201 <div> 202 <p class="brendigo-admin-eyebrow"><?php echo esc_html__( 'Upravljanje sidrenim cijenama', 'brendigo-sidrena-cijena' ); ?></p>202 <p class="brendigo-admin-eyebrow"><?php echo esc_html__( 'Upravljanje baznim cijenama', 'brendigo-sidrena-cijena' ); ?></p> 203 203 <h1><?php echo esc_html( $page_title ); ?></h1> 204 204 <p><?php echo esc_html( $page_subtitle ); ?></p> … … 237 237 $this->render_tab_postavke( $settings ); 238 238 } elseif ( 'upute' === $tab ) { 239 $this->render_tab_upute();239 $this->render_tab_upute(); 240 240 } else { 241 241 do_action( 'sidrena_cijena_render_settings_tab', $tab ); … … 244 244 245 245 <footer class="sidrena-cijena-card sidrena-cijena-credit"> 246 <div><strong><?php echo esc_html__( 'B rendigo Sidrena Cijena', 'brendigo-sidrena-cijena' ); ?></strong><p><?php echo esc_html__( 'Sidrene cijene i javni cjenik na jednom mjestu.', 'brendigo-sidrena-cijena' ); ?></p></div>246 <div><strong><?php echo esc_html__( 'BAZNA – Bazne cijene', 'brendigo-sidrena-cijena' ); ?></strong><p><?php echo esc_html__( 'Bazne cijene i javni cjenik na jednom mjestu.', 'brendigo-sidrena-cijena' ); ?></p></div> 247 247 <a class="sidrena-cijena-credit__brand" href="https://brendigo.com" target="_blank" rel="noopener noreferrer" aria-label="Brendigo.com"><span class="brendigo-admin-brand__mark brendigo-admin-brand__mark--small" aria-hidden="true">B</span><span>Brendigo</span></a> 248 248 </footer> … … 259 259 * @return array<string, array{label:string, icon:string}> 260 260 */ 261 private function get_tabs() { 261 /** WordPress admin tabs remain accessible to authorized users without activation. */ 262 private function get_tabs() { 262 263 $tabs = array(); 263 264 … … 297 298 298 299 /** 299 * Extra Sidrena cijena settings tabs.300 * Extra Bazna cijena settings tabs. 300 301 * 301 302 * @param array<string, array{label:string, icon:string}> $tabs Tabs. … … 319 320 } 320 321 321 if ( isset( $_GET['sidrena_xml'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended322 if ( isset( $_GET['sidrena_xml'] ) && isset( $tabs['javni-xml'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended 322 323 return 'javni-xml'; 323 324 } … … 559 560 560 561 /** 561 * After activation, p oint at the two fill buttons. Shown on every admin screen until dismissed or a fill finishes.562 * After activation, prompt an administrator to verify historical prices manually. 562 563 */ 563 564 private function render_fill_prompt_notice() { … … 573 574 574 575 echo '<div class="notice notice-info"><p>'; 575 echo esc_html__( ' Sidrena cijena ne upisuje cijene pri aktivaciji. Prazna polja možete popuniti na kartici Postavke: iz redovne cijene (datum ostaje zadani) ili s današnjim datumom.', 'brendigo-sidrena-cijena' );576 echo esc_html__( 'Automatsko popunjavanje sidrenih/baznih cijena iz današnjih cijena isključeno je. Za svaku stavku upišite dokazanu povijesnu cijenu i njezin referentni datum.', 'brendigo-sidrena-cijena' ); 576 577 echo ' <a href="' . esc_url( $settings_url ) . '">' . esc_html__( 'Otvori postavke', 'brendigo-sidrena-cijena' ) . '</a>'; 577 578 echo ' · <a href="' . esc_url( $dismiss_url ) . '">' . esc_html__( 'Sakrij', 'brendigo-sidrena-cijena' ) . '</a>'; … … 597 598 598 599 echo '<div class="notice notice-info"><p>'; 599 echo esc_html__( ' Sidrena cijena: u tijeku je spremanje redovnih cijena proizvoda i varijacija. Već unesene sidrene cijene neće se prepisati.', 'brendigo-sidrena-cijena' );600 echo esc_html__( 'Zatečena automatska obrada povijesnih cijena zaustavljena je. Postojeće cijene nisu izmijenjene; verificirajte datum i iznos svake stavke.', 'brendigo-sidrena-cijena' ); 600 601 echo '</p></div>'; 601 602 } … … 633 634 634 635 echo '<div class="notice notice-info"><p>'; 635 echo esc_html__( ' Sidrena cijena: u tijeku je spremanje redovnih cijena proizvoda i varijacija. Već unesene sidrene cijene neće se prepisati.', 'brendigo-sidrena-cijena' );636 echo esc_html__( 'Zatečena automatska obrada povijesnih cijena zaustavljena je. Postojeće cijene nisu izmijenjene; verificirajte datum i iznos svake stavke.', 'brendigo-sidrena-cijena' ); 636 637 echo '</p></div>'; 637 638 } … … 733 734 'todayConfirm' => sprintf( 734 735 /* translators: %s: locked general reference date. */ 735 __( 'Ovo popunjava prazne sidrene cijene trenutnom redovnom cijenom i upisuje današnji datum kao referentni (samo ako datum još nije unesen). Proizvodi koji su postojali na %s trebaju ostati na zadanom datumu. Nastaviti?', 'brendigo-sidrena-cijena' ),736 __( 'Ovo popunjava prazne bazne cijene trenutnom redovnom cijenom i upisuje današnji datum kao referentni (samo ako datum još nije unesen). Proizvodi koji su postojali na %s trebaju ostati na zadanom datumu. Nastaviti?', 'brendigo-sidrena-cijena' ), 736 737 Brendigo_Sidrena_Cijena_Settings::REFERENCE_DATE_GENERAL 737 738 ), 738 739 'error' => __( 'Došlo je do pogreške. Pokušajte ponovno.', 'brendigo-sidrena-cijena' ), 739 'purgeConfirm' => __( 'Ovo će trajno obrisati sve sidrene cijene, ručni cjenik, evidenciju povijesti cijena, postavke, javni XML i arhivu, zatim deaktivirati dodatak. Radnja se ne može poništiti. Nastaviti?', 'brendigo-sidrena-cijena' ),740 'purgeConfirm' => __( 'Ovo će trajno obrisati sve bazne cijene, ručni cjenik, evidenciju povijesti cijena, postavke, javni XML i arhivu, zatim deaktivirati dodatak. Radnja se ne može poništiti. Nastaviti?', 'brendigo-sidrena-cijena' ), 740 741 'purging' => __( 'Brisanje podataka…', 'brendigo-sidrena-cijena' ), 741 742 'copied' => __( 'Kopirano', 'brendigo-sidrena-cijena' ), 742 743 'copyFailed' => __( 'Kopiranje nije uspjelo', 'brendigo-sidrena-cijena' ), 743 'catalogRequired' => __( 'Naziv, redovna cijena i sidrena cijena obavezni su za svaki popunjeni redak. Ispravite označena polja prije spremanja.', 'brendigo-sidrena-cijena' ),744 'catalogRequired' => __( 'Naziv, redovna cijena i bazna cijena obavezni su za svaki popunjeni redak. Ispravite označena polja prije spremanja.', 'brendigo-sidrena-cijena' ), 744 745 'noFile' => __( 'Odaberite CSV, XML ili XLSX datoteku.', 'brendigo-sidrena-cijena' ), 745 746 'invalidFile' => __( 'Dopušteni su CSV, XML i XLSX.', 'brendigo-sidrena-cijena' ), … … 804 805 'unsavedLabel' => __( 'Nespremljene promjene', 'brendigo-sidrena-cijena' ), 805 806 'saving' => __( 'Spremanje…', 'brendigo-sidrena-cijena' ), 806 'fillCurrentConfirm' => __( 'Popuniti prazna polja sidrene cijene važećom cijenom prikazanih proizvoda? Koristite samo ako je ta cijena vrijedila na referentni datum koji unosite.', 'brendigo-sidrena-cijena' ),807 807 'wooNoChanges' => __( 'Nema nespremljenih promjena.', 'brendigo-sidrena-cijena' ), 808 'wooLeaveWarning' => __( 'Imate nespremljene promjene sidrenih cijena. Ako napustite stranicu, promjene će se izgubiti.', 'brendigo-sidrena-cijena' ),808 'wooLeaveWarning' => __( 'Imate nespremljene promjene baznih cijena. Ako napustite stranicu, promjene će se izgubiti.', 'brendigo-sidrena-cijena' ), 809 809 'wooResetConfirm' => __( 'Poništiti sve nespremljene promjene na ovoj stranici?', 'brendigo-sidrena-cijena' ), 810 810 'wooVisibleRows' => __( 'Prikazano {visible} od {total} stavki na ovoj stranici.', 'brendigo-sidrena-cijena' ), … … 861 861 */ 862 862 public function add_product_column( $columns ) { 863 $columns['sidrena_cijena'] = __( ' Sidrena cijena', 'brendigo-sidrena-cijena' );863 $columns['sidrena_cijena'] = __( 'Bazna cijena', 'brendigo-sidrena-cijena' ); 864 864 return $columns; 865 865 } -
brendigo-sidrena-cijena/includes/class-autoloader.php
r3737238 r3801404 24 24 'Brendigo_Sidrena_Cijena_Notifications' => 'includes/class-notifications.php', 25 25 'Brendigo_Sidrena_Cijena_Public_API' => 'includes/class-public-api.php', 26 'Brendigo_Sidrena_Cijena_Legal' => 'includes/class-legal.php', 26 27 'Brendigo_Sidrena_Cijena_Woo_Blocks' => 'includes/class-woo-blocks.php', 27 28 'Brendigo_Sidrena_Cijena_Settings' => 'includes/class-settings.php', -
brendigo-sidrena-cijena/includes/class-bulk-import.php
r3737238 r3801404 65 65 nocache_headers(); 66 66 header( 'Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ); 67 header( 'Content-Disposition: attachment; filename=" sidrena-predlozak.xlsx"' );67 header( 'Content-Disposition: attachment; filename="BAZNA-predlozak.xlsx"' ); 68 68 header( 'Content-Length: ' . strlen( $bytes ) ); 69 69 echo $bytes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- XLSX binary. -
brendigo-sidrena-cijena/includes/class-catalog.php
r3737238 r3801404 637 637 } 638 638 639 return $this->normalize_date( (string) Brendigo_Sidrena_Cijena_Settings::instance()->get( 'default_date' ) ); 639 // Do not present the general date as verified for every manual row. 640 return ''; 640 641 } 641 642 -
brendigo-sidrena-cijena/includes/class-cli.php
r3727711 r3801404 79 79 80 80 if ( 0 === (int) $stats['missing'] ) { 81 WP_CLI::success( 'Nothing to fill. Every eligible product already has a sidrena cijena.' );81 WP_CLI::success( 'Nothing to fill. Every eligible product already has a bazna cijena.' ); 82 82 return; 83 83 } … … 112 112 WP_CLI::success( 113 113 sprintf( 114 'Dry-run: would fill %d empty sidrena field(s). Re-run without --dry-run to write.',114 'Dry-run: would fill %d empty bazna field(s). Re-run without --dry-run to write.', 115 115 $would 116 116 ) … … 124 124 WP_CLI::success( 125 125 sprintf( 126 'Filled %d sidrena field(s) (inserted=%d updated=%d). Remaining empty: %d.',126 'Filled %d bazna field(s) (inserted=%d updated=%d). Remaining empty: %d.', 127 127 (int) $result['written'], 128 128 (int) $result['inserted'], … … 134 134 135 135 /** 136 * Show how many products/variations already have a sidrena cijena.136 * Show how many products/variations already have a bazna cijena. 137 137 * 138 138 * ## EXAMPLES … … 162 162 WP_CLI::success( 163 163 sprintf( 164 '%d of %d eligible items have a sidrena cijena.',164 '%d of %d eligible items have a bazna cijena.', 165 165 $stats['filled'], 166 166 $stats['eligible'] -
brendigo-sidrena-cijena/includes/class-export.php
r3737238 r3801404 665 665 } 666 666 667 // Snapshot the HTML-only on-request services only when published feed 668 // generation has succeeded. Public REST must never read unapproved drafts. 669 if ( ! is_wp_error( $result ) && class_exists( 'Brendigo_Sidrena_Cijena_Upit' ) ) { 670 $published_inquiry = array(); 671 foreach ( Brendigo_Sidrena_Cijena_Upit::instance()->all() as $row ) { 672 if ( count( $published_inquiry ) >= 500 ) { 673 break; 674 } 675 if ( ! is_array( $row ) || empty( $row['naziv'] ) || empty( $row['kriteriji'] ) ) { 676 continue; 677 } 678 $published_inquiry[] = array( 679 'id' => (string) $row['id'], 680 'name' => (string) $row['naziv'], 681 'criteria' => (string) $row['kriteriji'], 682 'outlet' => isset( $row['poslovnica'] ) ? (string) $row['poslovnica'] : '', 683 ); 684 } 685 update_option( 'brendigo_bazna_published_inquiry_v1', $published_inquiry, false ); 686 } 667 687 if ( ! is_wp_error( $result ) && class_exists( 'Brendigo_Sidrena_Cijena_Automation' ) ) { 668 688 Brendigo_Sidrena_Cijena_Automation::instance()->clear_pending(); -
brendigo-sidrena-cijena/includes/class-feed-files.php
r3737238 r3801404 87 87 ); 88 88 89 $this->headers( 'text/csv; charset=utf-8', ' sidrena-cijena-predlozak.csv' );89 $this->headers( 'text/csv; charset=utf-8', 'BAZNA-cjenik-predlozak.csv' ); 90 90 echo chr( 0xEF ) . chr( 0xBB ) . chr( 0xBF ) . implode( '', $lines ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 91 91 exit; … … 256 256 } 257 257 258 return array( 'id', 'vrsta', 'naziv', 'sku', 'marka', 'url', ' jedinica_mjere', 'cijena_jedinice_mjere', 'maloprodajna_cijena', 'naziv_posebnog_oblika', 'sidrena_cijena', 'sidrena_datum', 'barkod', 'dostupnost' );258 return array( 'id', 'vrsta', 'naziv', 'sku', 'marka', 'url', 'slika_url', 'jedinica_mjere', 'cijena_jedinice_mjere', 'maloprodajna_cijena', 'naziv_posebnog_oblika', 'sidrena_cijena', 'sidrena_datum', 'barkod', 'dostupnost' ); 259 259 } 260 260 … … 865 865 ++$row_index; 866 866 867 $html .= '<tr data- search="' . esc_attr( $search ) . '"' . $hidden . '>';867 $html .= '<tr data-kind="' . esc_attr( $vrsta ) . '" data-search="' . esc_attr( $search ) . '"' . $hidden . '>'; 868 868 foreach ( $columns as $key => $column ) { 869 $html .= '<td data- label="' . esc_attr( $column['label'] ) . '">' . $cells[ $key ] . '</td>';869 $html .= '<td data-field="' . esc_attr( $key ) . '" data-label="' . esc_attr( $column['label'] ) . '">' . $cells[ $key ] . '</td>'; 870 870 } 871 871 $html .= '</tr>'; … … 940 940 'maloprodajna_cijena' => array( 'label' => __( 'Maloprodajna cijena', 'brendigo-sidrena-cijena' ), 'always' => true ), 941 941 'naziv_posebnog_oblika' => array( 'label' => __( 'Poseban oblik prodaje', 'brendigo-sidrena-cijena' ), 'always' => false ), 942 'sidrena_cijena' => array( 'label' => __( ' Sidrena cijena', 'brendigo-sidrena-cijena' ), 'always' => true ),942 'sidrena_cijena' => array( 'label' => __( 'Bazna cijena', 'brendigo-sidrena-cijena' ), 'always' => true ), 943 943 'sidrena_datum' => array( 'label' => __( 'Datum sidrene', 'brendigo-sidrena-cijena' ), 'always' => false ), 944 944 'dostupnost' => array( 'label' => __( 'Dostupnost', 'brendigo-sidrena-cijena' ), 'always' => false ), -
brendigo-sidrena-cijena/includes/class-feed-routes.php
r3727711 r3801404 602 602 $files = Brendigo_Sidrena_Cijena_Archive::instance()->get_archive_files(); 603 603 $shop = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); 604 $title = __( 'Arhiva sidrene cijene', 'brendigo-sidrena-cijena' );604 $title = __( 'Arhiva baznih cijena', 'brendigo-sidrena-cijena' ); 605 605 606 606 $this->open_public_document( … … 771 771 $count = (int) $snapshot['count']; 772 772 $shop = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); 773 $title = __( 'Cjenik - sidrena cijena', 'brendigo-sidrena-cijena' );773 $title = __( 'Cjenik - bazna cijena', 'brendigo-sidrena-cijena' ); 774 774 $label = $settings->get_preview_label(); 775 775 $scope = is_array( $outlet ) ? $this->outlet_label( $outlet ) : ( $settings->is_multi_poslovnica() ? $this->webshop_oznaka() : '' ); … … 790 790 wp_enqueue_script( 'brendigo-sidrena-cijena-cjenik' ); 791 791 /* translators: %s: shop name. */ 792 $meta_description = sprintf( __( 'Važeći cjenik s a sidrenom cijenom: %s', 'brendigo-sidrena-cijena' ), $shop );792 $meta_description = sprintf( __( 'Važeći cjenik s baznom cijenom: %s', 'brendigo-sidrena-cijena' ), $shop ); 793 793 $this->open_public_document( 794 794 $shop . ' - ' . $title, … … 903 903 public function serve_cjenik_empty_page() { 904 904 $shop = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); 905 $title = __( 'Cjenik - sidrena cijena', 'brendigo-sidrena-cijena' );905 $title = __( 'Cjenik - bazna cijena', 'brendigo-sidrena-cijena' ); 906 906 907 907 $this->open_public_document( … … 925 925 public function serve_cjenik_pending_page() { 926 926 $shop = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); 927 $title = __( 'Cjenik - sidrena cijena', 'brendigo-sidrena-cijena' );927 $title = __( 'Cjenik - bazna cijena', 'brendigo-sidrena-cijena' ); 928 928 929 929 $this->open_public_document( -
brendigo-sidrena-cijena/includes/class-feed-rows.php
r3727711 r3801404 308 308 $row['id'] = (string) $product->get_id(); 309 309 $row['url'] = (string) get_permalink( $product->get_id() ); 310 // Optional public thumbnail for SIDRENA Android catalog cards. 311 // Images are never required to publish a valid cjenik. 312 $image_id = method_exists( $product, 'get_image_id' ) ? (int) $product->get_image_id() : 0; 313 $image_url = $image_id > 0 ? wp_get_attachment_image_url( $image_id, 'woocommerce_thumbnail' ) : false; 314 $row['slika_url'] = is_string( $image_url ) ? esc_url_raw( $image_url ) : ''; 310 315 $row['barkod'] = $this->product_barcode( $product ); 311 316 $row['marka'] = Brendigo_Sidrena_Cijena_Settings::instance()->product_marka( $product ); -
brendigo-sidrena-cijena/includes/class-frontend.php
r3737238 r3801404 1 1 <?php 2 2 /** 3 * Storefront display of sidrena cijena.3 * Storefront display of bazna cijena. 4 4 * 5 5 * @package Brendigo_Sidrena_Cijena … … 38 38 add_action( 'sidrena_cijena', array( $this, 'render_action' ), 10, 1 ); 39 39 add_shortcode( 'sidrena-cijena', array( $this, 'shortcode' ) ); 40 // BAZNA aliases; the historical names remain valid for existing pages. 41 add_shortcode( 'bazna_cijena', array( $this, 'shortcode' ) ); 42 add_shortcode( 'bazna-cijena', array( $this, 'shortcode' ) ); 40 43 add_shortcode( 'sidrena_cijena', array( $this, 'shortcode' ) ); 41 44 add_shortcode( 'brendigo-sidrena-cijena', array( $this, 'shortcode' ) ); 42 45 add_shortcode( 'sidrena-cjenik', array( $this, 'cjenik_shortcode' ) ); 46 add_shortcode( 'bazna_cjenik', array( $this, 'cjenik_shortcode' ) ); 47 add_shortcode( 'bazna-cjenik', array( $this, 'cjenik_shortcode' ) ); 43 48 add_shortcode( 'sidrena_cjenik', array( $this, 'cjenik_shortcode' ) ); 44 49 add_shortcode( 'brendigo-sidrena-cjenik', array( $this, 'cjenik_shortcode' ) ); 45 50 add_shortcode( 'sidrena-arhiva', array( $this, 'arhiva_shortcode' ) ); 51 add_shortcode( 'bazna_arhiva', array( $this, 'arhiva_shortcode' ) ); 52 add_shortcode( 'bazna-arhiva', array( $this, 'arhiva_shortcode' ) ); 46 53 add_shortcode( 'sidrena_arhiva', array( $this, 'arhiva_shortcode' ) ); 47 54 add_shortcode( 'brendigo-sidrena-arhiva', array( $this, 'arhiva_shortcode' ) ); … … 58 65 add_shortcode( 'sidrena_proizvodi', array( $this, 'cjenik_shortcode' ) ); 59 66 add_shortcode( 'sidrena_stavka', array( $this, 'standalone_item_shortcode' ) ); 67 add_shortcode( 'bazna_stavka', array( $this, 'standalone_item_shortcode' ) ); 68 add_shortcode( 'bazna-stavka', array( $this, 'standalone_item_shortcode' ) ); 69 add_shortcode( 'bazna_usluge', array( $this, 'cjenik_shortcode' ) ); 70 add_shortcode( 'bazna_proizvodi', array( $this, 'cjenik_shortcode' ) ); 60 71 61 72 if ( ! Brendigo_Sidrena_Cijena_Plugin::woocommerce_active() ) { … … 365 376 $kind = sanitize_key( (string) $atts['vrsta'] ); 366 377 // Earlier sidrena_usluge incorrectly showed products and services together. 367 if ( 'sidrena_usluge' === $shortcode_tag) {378 if ( in_array( $shortcode_tag, array( 'sidrena_usluge', 'bazna_usluge' ), true ) ) { 368 379 $kind = 'usluge'; 369 } elseif ( 'sidrena_proizvodi' === $shortcode_tag) {380 } elseif ( in_array( $shortcode_tag, array( 'sidrena_proizvodi', 'bazna_proizvodi' ), true ) ) { 370 381 $kind = 'proizvodi'; 371 382 } … … 508 519 } 509 520 510 return has_shortcode( $post->post_content, 'sidrena_graf_cijena' ) 521 return has_shortcode( $post->post_content, 'bazna_cijena' ) 522 || has_shortcode( $post->post_content, 'bazna-cijena' ) 523 || has_shortcode( $post->post_content, 'bazna_stavka' ) 524 || has_shortcode( $post->post_content, 'bazna-stavka' ) 525 || has_shortcode( $post->post_content, 'bazna_povijest_cijena' ) 526 || has_shortcode( $post->post_content, 'bazna-graf-cijena' ) 527 || has_shortcode( $post->post_content, 'sidrena_graf_cijena' ) 511 528 || has_shortcode( $post->post_content, 'sidrena_povijest_cijena' ) 512 529 || has_shortcode( $post->post_content, 'sidrena_najniza_prije_snizenja' ) … … 528 545 } 529 546 530 return has_shortcode( $post->post_content, 'sidrena-cjenik' ) 547 return has_shortcode( $post->post_content, 'bazna_cjenik' ) 548 || has_shortcode( $post->post_content, 'bazna-cjenik' ) 549 || has_shortcode( $post->post_content, 'bazna_proizvodi' ) 550 || has_shortcode( $post->post_content, 'bazna_usluge' ) 551 || has_shortcode( $post->post_content, 'sidrena-cjenik' ) 531 552 || has_shortcode( $post->post_content, 'sidrena_cjenik' ) 532 553 || has_shortcode( $post->post_content, 'sidrena_objava_cjenika' ) -
brendigo-sidrena-cijena/includes/class-i18n.php
r3737344 r3801404 112 112 113 113 if ( function_exists( 'pll_register_string' ) ) { 114 pll_register_string( 'prefix', $prefix, ' Sidrena cijena', false );115 pll_register_string( 'tooltip', $tooltip, ' Sidrena cijena', true );114 pll_register_string( 'prefix', $prefix, 'Bazna cijena', false ); 115 pll_register_string( 'tooltip', $tooltip, 'Bazna cijena', true ); 116 116 } 117 117 } … … 419 419 private function apply_gettext_default( $key, $value ) { 420 420 if ( 'prefix' === $key && Brendigo_Sidrena_Cijena_Settings::DEFAULT_PREFIX === $value ) { 421 return __( ' Sidrena cijena', 'brendigo-sidrena-cijena' );421 return __( 'Bazna cijena', 'brendigo-sidrena-cijena' ); 422 422 } 423 423 424 424 if ( 'tooltip' === $key && Brendigo_Sidrena_Cijena_Settings::DEFAULT_TOOLTIP === $value ) { 425 return __( ' Sidrena cijena je referentna maloprodajna cijena koja je za proizvod ili uslugu vrijedila na navedeni datum.', 'brendigo-sidrena-cijena' );425 return __( 'Bazna cijena je referentna maloprodajna cijena koja je za proizvod ili uslugu vrijedila na navedeni datum.', 'brendigo-sidrena-cijena' ); 426 426 } 427 427 -
brendigo-sidrena-cijena/includes/class-import-export.php
r3737238 r3801404 60 60 */ 61 61 public function export_columns( $columns ) { 62 $columns['sidrena_cijena'] = __( ' Sidrena cijena', 'brendigo-sidrena-cijena' );63 $columns['sidrena_cijena_datum'] = __( ' Sidrena cijena datum', 'brendigo-sidrena-cijena' );64 $columns['sidrena_cijena_cjm'] = __( ' Sidrena cijena CJM', 'brendigo-sidrena-cijena' );65 $columns['sidrena_cijena_cjm_suffix'] = __( ' Sidrena cijena CJM dodatak', 'brendigo-sidrena-cijena' );62 $columns['sidrena_cijena'] = __( 'Bazna cijena', 'brendigo-sidrena-cijena' ); 63 $columns['sidrena_cijena_datum'] = __( 'Bazna cijena datum', 'brendigo-sidrena-cijena' ); 64 $columns['sidrena_cijena_cjm'] = __( 'Bazna cijena CJM', 'brendigo-sidrena-cijena' ); 65 $columns['sidrena_cijena_cjm_suffix'] = __( 'Bazna cijena CJM dodatak', 'brendigo-sidrena-cijena' ); 66 66 $columns['sidrena_naziv_posebnog_oblika'] = __( 'Naziv posebnog oblika prodaje', 'brendigo-sidrena-cijena' ); 67 67 $columns['sidrena_jedinica_mjere'] = __( 'Jedinica mjere', 'brendigo-sidrena-cijena' ); … … 154 154 */ 155 155 public function import_options( $options ) { 156 $options['sidrena_cijena'] = __( ' Sidrena cijena', 'brendigo-sidrena-cijena' );157 $options['sidrena_cijena_datum'] = __( ' Sidrena cijena datum', 'brendigo-sidrena-cijena' );158 $options['sidrena_cijena_cjm'] = __( ' Sidrena cijena CJM', 'brendigo-sidrena-cijena' );159 $options['sidrena_cijena_cjm_suffix'] = __( ' Sidrena cijena CJM dodatak', 'brendigo-sidrena-cijena' );156 $options['sidrena_cijena'] = __( 'Bazna cijena', 'brendigo-sidrena-cijena' ); 157 $options['sidrena_cijena_datum'] = __( 'Bazna cijena datum', 'brendigo-sidrena-cijena' ); 158 $options['sidrena_cijena_cjm'] = __( 'Bazna cijena CJM', 'brendigo-sidrena-cijena' ); 159 $options['sidrena_cijena_cjm_suffix'] = __( 'Bazna cijena CJM dodatak', 'brendigo-sidrena-cijena' ); 160 160 $options['sidrena_naziv_posebnog_oblika'] = __( 'Naziv posebnog oblika prodaje', 'brendigo-sidrena-cijena' ); 161 161 $options['sidrena_jedinica_mjere'] = __( 'Jedinica mjere', 'brendigo-sidrena-cijena' ); … … 171 171 */ 172 172 public function import_default_columns( $columns ) { 173 $columns[ __( ' Sidrena cijena', 'brendigo-sidrena-cijena' ) ] = 'sidrena_cijena';174 $columns[ __( ' Sidrena cijena datum', 'brendigo-sidrena-cijena' ) ] = 'sidrena_cijena_datum';175 $columns[ __( ' Sidrena cijena CJM', 'brendigo-sidrena-cijena' ) ] = 'sidrena_cijena_cjm';176 $columns[ __( ' Sidrena cijena CJM dodatak', 'brendigo-sidrena-cijena' ) ] = 'sidrena_cijena_cjm_suffix';173 $columns[ __( 'Bazna cijena', 'brendigo-sidrena-cijena' ) ] = 'sidrena_cijena'; 174 $columns[ __( 'Bazna cijena datum', 'brendigo-sidrena-cijena' ) ] = 'sidrena_cijena_datum'; 175 $columns[ __( 'Bazna cijena CJM', 'brendigo-sidrena-cijena' ) ] = 'sidrena_cijena_cjm'; 176 $columns[ __( 'Bazna cijena CJM dodatak', 'brendigo-sidrena-cijena' ) ] = 'sidrena_cijena_cjm_suffix'; 177 177 $columns['Sidrena cijena'] = 'sidrena_cijena'; 178 178 $columns['Sidrena cijena datum'] = 'sidrena_cijena_datum'; -
brendigo-sidrena-cijena/includes/class-notifications.php
r3737344 r3801404 70 70 $subject = sprintf( 71 71 /* translators: %s: website host name. */ 72 __( '[ SIDRENA] Problem s cjenikom – %s', 'brendigo-sidrena-cijena' ),72 __( '[BAZNA] Problem s cjenikom – %s', 'brendigo-sidrena-cijena' ), 73 73 wp_parse_url( home_url(), PHP_URL_HOST ) 74 74 ); -
brendigo-sidrena-cijena/includes/class-plugin.php
r3737238 r3801404 1 1 <?php 2 2 /** 3 * Bootstrap the Sidrena cijenaplugin.3 * Bootstrap the BAZNA plugin. 4 4 * 5 5 * @package Brendigo_Sidrena_Cijena … … 25 25 public static function init() { 26 26 Brendigo_Sidrena_Cijena_Migration::maybe_migrate(); 27 // One-time cleanup for users upgrading from the licensed build. 28 // Never delete license options or customer data: only an orphaned cron. 29 if ( function_exists( 'wp_next_scheduled' ) && 30 wp_next_scheduled( 'bazna_license_periodic_check' ) ) { 31 wp_clear_scheduled_hook( 'bazna_license_periodic_check' ); 32 } 27 33 28 34 if ( self::legacy_plugin_active() ) { … … 63 69 } 64 70 65 echo '<div class="notice notice-warning"><p><strong>' . esc_html__( 'B rendigo Sidrena Cijena je spremnaza prijelaz.', 'brendigo-sidrena-cijena' ) . '</strong> ';66 echo esc_html__( 'Deaktivirajte prethodne dodatke za sidrenu cijenu i cjenik kako biste izbjegli dvostruki prikaz i koristili samo objedinjeni Brendigo plugin. Podaci su migrirani ne-destruktivno.', 'brendigo-sidrena-cijena' );71 echo '<div class="notice notice-warning"><p><strong>' . esc_html__( 'BAZNA – Bazne cijene spremna je za prijelaz.', 'brendigo-sidrena-cijena' ) . '</strong> '; 72 echo esc_html__( 'Deaktivirajte ranije dodatke za povijesne cijene i cjenik kako biste izbjegli dvostruki prikaz. BAZNA čuva postojeće podatke tijekom migracije.', 'brendigo-sidrena-cijena' ); 67 73 echo ' <a href="' . esc_url( admin_url( 'plugins.php' ) ) . '">' . esc_html__( 'Otvori dodatke', 'brendigo-sidrena-cijena' ) . '</a></p></div>'; 68 74 } … … 102 108 $exception_message = substr( $exception_message, 0, 1000 ); 103 109 } 104 $message = ' Sidrena cijena[' . get_class( $exception ) . ']: ' . $exception_message;110 $message = 'BAZNA [' . get_class( $exception ) . ']: ' . $exception_message; 105 111 if ( function_exists( 'wc_get_logger' ) ) { 106 112 wc_get_logger()->error( $message, array( 'source' => 'sidrena-cijena' ) ); … … 144 150 Brendigo_Sidrena_Cijena_Frontend::instance(); 145 151 152 // Preserve storefront meta, theme compatibility and Woo Blocks regardless 153 // of whether WooCommerce catalog import tools are enabled. 154 if ( self::woocommerce_active() ) { 155 Brendigo_Sidrena_Cijena_Product_Meta::instance(); 156 Brendigo_Sidrena_Cijena_Compat::instance(); 157 Brendigo_Sidrena_Cijena_Woo_Blocks::instance(); 158 } 159 146 160 if ( is_admin() ) { 147 161 Brendigo_Sidrena_Cijena_Admin::instance(); … … 151 165 if ( defined( 'WP_CLI' ) && WP_CLI ) { 152 166 WP_CLI::add_command( 'sidrena-cijena', 'Brendigo_Sidrena_Cijena_CLI' ); 167 WP_CLI::add_command( 'bazna', 'Brendigo_Sidrena_Cijena_CLI' ); 153 168 } 154 169 … … 159 174 add_action( 'sidrena_cijena_snapshot_batch', array( 'Brendigo_Sidrena_Cijena_Activator', 'process_batch' ) ); 160 175 161 Brendigo_Sidrena_Cijena_Product_Meta::instance(); 162 Brendigo_Sidrena_Cijena_Compat::instance(); 163 Brendigo_Sidrena_Cijena_Woo_Blocks::instance(); 176 // WooCommerce editing integration requires the actual WC plugin, not a key. 164 177 Brendigo_Sidrena_Cijena_Import_Export::instance(); 165 178 } 166 179 167 180 /** 168 * Activation: defaults. Sidrena prices stay empty until someone fills them.181 * Activation: defaults. Base prices stay empty until verified and entered. 169 182 */ 170 183 public static function activate() { … … 194 207 public static function deactivate() { 195 208 wp_clear_scheduled_hook( 'sidrena_cijena_snapshot_batch' ); 209 wp_clear_scheduled_hook( 'bazna_license_periodic_check' ); 196 210 wp_clear_scheduled_hook( Brendigo_Sidrena_Cijena_Price_History::SEED_HOOK ); 197 211 wp_clear_scheduled_hook( Brendigo_Sidrena_Cijena_Price_History::MANUAL_SEED_HOOK ); -
brendigo-sidrena-cijena/includes/class-price-history.php
r3737238 r3801404 60 60 add_action( 'admin_init', array( $this, 'seed_without_cron' ), 25 ); 61 61 add_shortcode( 'sidrena_povijest_cijena', array( $this, 'shortcode' ) ); 62 add_shortcode( 'bazna_povijest_cijena', array( $this, 'shortcode' ) ); 63 add_shortcode( 'bazna-povijest-cijena', array( $this, 'shortcode' ) ); 62 64 add_shortcode( 'sidrena_najniza_prije_snizenja', array( $this, 'shortcode_before_sale' ) ); 65 add_shortcode( 'bazna_najniza_prije_snizenja', array( $this, 'shortcode_before_sale' ) ); 63 66 add_shortcode( 'sidrena_graf_cijena', array( $this, 'shortcode_chart' ) ); 67 add_shortcode( 'bazna_graf_cijena', array( $this, 'shortcode_chart' ) ); 68 add_shortcode( 'bazna-graf-cijena', array( $this, 'shortcode_chart' ) ); 64 69 if ( ! Brendigo_Sidrena_Cijena_Plugin::woocommerce_active() ) { 65 70 return; -
brendigo-sidrena-cijena/includes/class-product-fields.php
r3727711 r3801404 45 45 <span class="sidrena-cijena-admin-fields__mark" aria-hidden="true">B</span> 46 46 <div> 47 <strong><?php echo esc_html__( 'B rendigo Sidrena Cijena', 'brendigo-sidrena-cijena' ); ?></strong>47 <strong><?php echo esc_html__( 'BAZNA – Bazne cijene', 'brendigo-sidrena-cijena' ); ?></strong> 48 48 <small><?php echo esc_html__( 'Referentna cijena i podaci javnog cjenika', 'brendigo-sidrena-cijena' ); ?></small> 49 49 </div> … … 61 61 'id' => 'sidrena_cijena', 62 62 'name' => 'sidrena_cijena', 63 'label' => __( ' Sidrena cijena', 'brendigo-sidrena-cijena' ) . ' (' . get_woocommerce_currency_symbol() . ')',63 'label' => __( 'Bazna cijena', 'brendigo-sidrena-cijena' ) . ' (' . get_woocommerce_currency_symbol() . ')', 64 64 'desc_tip' => true, 65 65 'description' => __( 'Referentna maloprodajna cijena koja je vrijedila na datumu upisanom uz proizvod.', 'brendigo-sidrena-cijena' ), … … 83 83 $sidrena_date_help = sprintf( 84 84 /* translators: 1: general reference date, 2: FMCG reference date. */ 85 __( ' Ostavite prazno za zaključani opći referentni datum %1$s. Za obuhvaćene kategorije hrane, pića, kozmetike i kućanskih potrepština koristite %2$s. Vlastiti datum koristite samo kada je dopušten za novu stavku nakon referentnog datuma.', 'brendigo-sidrena-cijena' ),85 __( 'Prazan datum znači da povijesni datum nije utvrđen; ne popunjava se automatski. Kad imate dokaz, koristite %1$s za opću referentnu skupinu ili %2$s za ranije obuhvaćene skupine. Za novu stavku primijenite pravila uvođenja i sačuvajte dokaz.', 'brendigo-sidrena-cijena' ), 86 86 Brendigo_Sidrena_Cijena_Settings::REFERENCE_DATE_GENERAL, 87 87 Brendigo_Sidrena_Cijena_Settings::REFERENCE_DATE_FMCG … … 93 93 'name' => 'sidrena_cijena_datum', 94 94 'label' => __( 'Referentni datum', 'brendigo-sidrena-cijena' ), 95 'placeholder' => Brendigo_Sidrena_Cijena_Settings::instance()->get( 'default_date' ),95 'placeholder' => 'DD.MM.GGGG.', 96 96 'desc_tip' => true, 97 97 'description' => $sidrena_date_help, … … 203 203 * @param WP_Post $variation Variation post. 204 204 */ 205 public function render_variation_fields( $loop, $variation_data, $variation ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter 205 public function render_variation_fields( $loop, $variation_data, $variation ) { 206 // Variation data is part of the WooCommerce hook signature. 206 207 $meta = Brendigo_Sidrena_Cijena_Product_Meta::instance(); 207 208 $id = $variation->ID; … … 211 212 <div class="sidrena-cijena-variation-fields"> 212 213 <div class="sidrena-cijena-variation-fields__head"> 213 <strong><?php echo esc_html__( 'B rendigo Sidrena Cijena', 'brendigo-sidrena-cijena' ); ?></strong>214 <strong><?php echo esc_html__( 'BAZNA – Bazne cijene', 'brendigo-sidrena-cijena' ); ?></strong> 214 215 <small><?php echo esc_html__( 'Referentna cijena i datum', 'brendigo-sidrena-cijena' ); ?></small> 215 216 </div> 216 217 <p class="form-row form-row-first"> 217 <label><?php echo esc_html__( ' Sidrena cijena', 'brendigo-sidrena-cijena' ) . ' (' . esc_html( get_woocommerce_currency_symbol() ) . ')'; ?></label>218 <label><?php echo esc_html__( 'Bazna cijena', 'brendigo-sidrena-cijena' ) . ' (' . esc_html( get_woocommerce_currency_symbol() ) . ')'; ?></label> 218 219 <input type="text" class="short wc_input_price" name="sidrena_cijena[<?php echo esc_attr( (string) $loop ); ?>]" value="<?php echo esc_attr( wc_format_localized_price( $meta->get_price( $id ) ) ); ?>" /> 219 220 </p> … … 238 239 <p class="form-row form-row-first"> 239 240 <label><?php echo esc_html__( 'Referentni datum', 'brendigo-sidrena-cijena' ); ?></label> 240 <input type="text" class="short" name="sidrena_cijena_datum[<?php echo esc_attr( (string) $loop ); ?>]" value="<?php echo esc_attr( $meta->get_date( $id ) ); ?>" placeholder=" <?php echo esc_attr( Brendigo_Sidrena_Cijena_Settings::instance()->get( 'default_date' ) ); ?>" />241 <input type="text" class="short" name="sidrena_cijena_datum[<?php echo esc_attr( (string) $loop ); ?>]" value="<?php echo esc_attr( $meta->get_date( $id ) ); ?>" placeholder="DD.MM.GGGG." /> 241 242 </p> 242 243 <p class="form-row form-row-last"> -
brendigo-sidrena-cijena/includes/class-product-meta.php
r3737238 r3801404 39 39 private function __construct() { 40 40 add_action( 'init', array( $this, 'register_meta' ) ); 41 add_action( 'woocommerce_after_product_object_save', array( $this, 'maybe_autofill' ), 20, 1 ); 41 // Do not register the obsolete autofill hook: today's price cannot 42 // establish a historical base price. The legacy no-op public method is 43 // retained for compatibility with older third-party integrations. 42 44 add_action( 'added_post_meta', array( $this, 'maybe_clear_overview_cache' ), 10, 4 ); 43 45 add_action( 'updated_post_meta', array( $this, 'maybe_clear_overview_cache' ), 10, 4 ); … … 55 57 'show_in_rest' => true, 56 58 'auth_callback' => static function ( $allowed, $meta_key, $post_id ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter 59 // REST writes remain restricted to authorized product editors. 57 60 return current_user_can( 'edit_post', (int) $post_id ); 58 61 }, … … 707 710 } 708 711 709 $this->snapshot_if_empty( $product, self::today_date() ); 712 // Historical reference prices require independently verified evidence. 713 // The legacy auto-fill option must never write a present-day price as history. 714 return; 710 715 } 711 716 … … 742 747 */ 743 748 public function snapshot_if_empty( $product, $date = '' ) { 744 if ( ! $this->can_snapshot( $product ) ) { 745 return false; 746 } 747 748 $id = $product->get_id(); 749 $this->set_price( $id, $product->get_regular_price() ); 750 751 $date = is_string( $date ) ? trim( $date ) : ''; 752 if ( '' !== $date && '' === $this->get_date( $id ) ) { 753 $this->set_date( $id, $date ); 754 } 755 756 return true; 749 // Never derive a legally fixed historical price from today's regular price. 750 // Preserve all existing manually verified historical records unchanged. 751 return false; 757 752 } 758 753 … … 798 793 } 799 794 800 return $this->normalize_date( (string) Brendigo_Sidrena_Cijena_Settings::instance()->get( 'default_date' ) ); 795 // A missing per-product date is unknown; shop defaults are not evidence 796 // that this exact product had the given price on the reference day. 797 return ''; 801 798 } 802 799 -
brendigo-sidrena-cijena/includes/class-public-api.php
r3737238 r3801404 17 17 18 18 public function register() { 19 register_rest_route( 'brendigo-sidrena/v1', '/cjenici', array( 19 // New BAZNA-facing paths are canonical; legacy paths stay read-only 20 // and fully functional for installed Android clients and old embeds. 21 foreach ( array( 'brendigo-bazna/v1', 'brendigo-sidrena/v1' ) as $namespace ) { 22 register_rest_route( $namespace, '/cjenici', array( 20 23 'methods' => WP_REST_Server::READABLE, 21 24 'callback' => array( $this, 'index' ), 22 25 'permission_callback' => '__return_true', 23 26 ) ); 24 register_rest_route( 'brendigo-sidrena/v1', '/arhiva', array( 27 // Public snapshot of services priced on request, NEVER draft rows. 28 register_rest_route( $namespace, '/usluge-na-upit', array( 29 'methods' => WP_REST_Server::READABLE, 30 'callback' => array( $this, 'on_request_services' ), 31 'permission_callback' => '__return_true', 32 ) ); 33 register_rest_route( $namespace, '/arhiva', array( 25 34 'methods' => WP_REST_Server::READABLE, 26 35 'callback' => array( $this, 'archive_index' ), … … 31 40 ), 32 41 ) ); 33 register_rest_route( 'brendigo-sidrena/v1', '/cjenici/(?P<kind>proizvodi|usluge)/(?P<format>xml|csv)', array(42 register_rest_route( $namespace, '/cjenici/(?P<kind>proizvodi|usluge)/(?P<format>xml|csv)', array( 34 43 'methods' => WP_REST_Server::READABLE, 35 44 'callback' => array( $this, 'feed' ), … … 37 46 'args' => array( 'oznaka' => array( 'type' => 'string', 'default' => '', 'sanitize_callback' => 'sanitize_text_field' ) ), 38 47 ) ); 48 } 49 } 50 51 /** 52 * Read-only feed readiness flag used by mobile and public catalog clients. 53 * No private metadata or filesystem path is exposed to visitors. 54 * 55 * @param string $kind Product or service feed. 56 * @param string $format CSV or XML. 57 * @param string $oznaka Optional public outlet code. 58 * @return bool 59 */ 60 private function feed_available( $kind, $format = 'csv', $oznaka = '' ) { 61 $path = Brendigo_Sidrena_Cijena_Feed_Files::instance()->get_type_public_path( $kind, $format, $oznaka ); 62 return is_string( $path ) && '' !== $path && is_file( $path ) && is_readable( $path ); 39 63 } 40 64 … … 43 67 $meta = $export->get_public_meta(); 44 68 $out = array( 69 'api_version' => 1, 70 'platform' => 'wordpress', 71 'plugin_version' => BRENDIGO_SIDRENA_CIJENA_VERSION, 72 'branding' => array( 73 'name' => 'BAZNA', 74 'description' => 'Bazne cijene', 75 ), 76 // Public-only Android integration. No credentials, session data, or 77 // unpublished WooCommerce metadata are available through this route. 78 'connection' => array( 79 'mode' => 'public_read_only', 80 'authentication_required' => false, 81 'csv_publication_required' => true, 82 'rest_endpoint' => esc_url_raw( rest_url( 'brendigo-bazna/v1/cjenici' ) ), 83 ), 84 'legal' => Brendigo_Sidrena_Cijena_Legal::public_contract(), 45 85 'published_at' => isset( $meta['generated'] ) ? gmdate( 'c', (int) $meta['generated'] ) : null, 46 86 'cjenik' => esc_url_raw( $export->get_cjenik_url() ), 47 87 'archive' => esc_url_raw( $export->get_archive_url() ), 48 'type_archive' => esc_url_raw( rest_url( 'brendigo- sidrena/v1/arhiva' ) ),88 'type_archive' => esc_url_raw( rest_url( 'brendigo-bazna/v1/arhiva' ) ), 49 89 'combined' => esc_url_raw( $export->get_public_url() ), 50 90 'feeds' => array(), 91 // Optional additive REST v1 endpoint (MJDD-compatible HTML-only services). 92 'on_request' => esc_url_raw( rest_url( 'brendigo-bazna/v1/usluge-na-upit' ) ), 51 93 'outlets' => array(), 52 94 ); 53 95 foreach ( array( 'proizvodi', 'usluge' ) as $kind ) { 54 $out['feeds'][ $kind ] = array( );96 $out['feeds'][ $kind ] = array( 'available_csv' => $this->feed_available( $kind ) ); 55 97 foreach ( array( 'xml', 'csv' ) as $ext ) { 56 $out['feeds'][ $kind ][ $ext ] = esc_url_raw( rest_url( 'brendigo- sidrena/v1/cjenici/' . $kind . '/' . $ext ) );98 $out['feeds'][ $kind ][ $ext ] = esc_url_raw( rest_url( 'brendigo-bazna/v1/cjenici/' . $kind . '/' . $ext ) ); 57 99 } 58 100 } … … 63 105 continue; 64 106 } 65 $entry = array( 'name' => isset( $outlet['naziv'] ) ? $outlet['naziv'] : $code, 'code' => $code, 'feeds' => array() ); 107 $entry = array( 108 'name' => isset( $outlet['naziv'] ) ? $outlet['naziv'] : $code, 109 'code' => $code, 110 // Outlet addresses already appear in public price-list 111 // filenames. Publish only the sanitized business address; 112 // never send internal IDs, assignments or stock records. 113 'address' => isset( $outlet['adresa'] ) ? sanitize_text_field( (string) $outlet['adresa'] ) : '', 114 'feeds' => array(), 115 ); 116 foreach ( array( 'proizvodi', 'usluge' ) as $kind ) { 117 $entry['feeds'][ $kind ] = array( 'available_csv' => $this->feed_available( $kind, 'csv', $code ) ); 118 } 66 119 foreach ( array( 'proizvodi', 'usluge' ) as $kind ) { 67 120 foreach ( array( 'xml', 'csv' ) as $ext ) { 68 $entry['feeds'][ $kind ][ $ext ] = esc_url_raw( add_query_arg( 'oznaka', $code, rest_url( 'brendigo- sidrena/v1/cjenici/' . $kind . '/' . $ext ) ) );121 $entry['feeds'][ $kind ][ $ext ] = esc_url_raw( add_query_arg( 'oznaka', $code, rest_url( 'brendigo-bazna/v1/cjenici/' . $kind . '/' . $ext ) ) ); 69 122 } 70 123 } … … 72 125 } 73 126 } 74 return rest_ensure_response( $out ); 127 // A published CSV may be older than WooCommerce edits still awaiting 128 // the next public rebuild. Expose this distinction without private data. 129 $pending = array(); 130 if ( class_exists( 'Brendigo_Sidrena_Cijena_Automation' ) ) { 131 $pending = Brendigo_Sidrena_Cijena_Automation::instance()->get_pending_state(); 132 } 133 $pending_changes = is_array( $pending ) && ! empty( $pending['since'] ); 134 // Each outlet has independent published CSV paths. A valid webshop feed 135 // does not prove that every outlet's files were generated. 136 $all_outlets_ready = true; 137 foreach ( $out['outlets'] as $outlet ) { 138 if ( ! $outlet['feeds']['proizvodi']['available_csv'] || 139 ! $outlet['feeds']['usluge']['available_csv'] ) { 140 $all_outlets_ready = false; 141 break; 142 } 143 } 144 // Optional, backwards-compatible status: old clients still use feeds[*].csv. 145 $out['publication'] = array( 146 'csv_ready' => $out['feeds']['proizvodi']['available_csv'] && $out['feeds']['usluge']['available_csv'], 147 'csv_ready_all_outlets' => $out['feeds']['proizvodi']['available_csv'] && $out['feeds']['usluge']['available_csv'] && $all_outlets_ready, 148 'generated_at' => $out['published_at'], 149 'pending_changes' => $pending_changes, 150 // This technical status is never certification of legal price accuracy. 151 'compliance_certified' => false, 152 ); 153 // Discovery includes live publication/readiness flags. Never serve a 154 // cached "not published" or "no pending changes" status to Android. 155 $response = rest_ensure_response( $out ); 156 $response->header( 'Cache-Control', 'no-store, max-age=0, must-revalidate' ); 157 return $response; 158 } 159 160 /** 161 * Read ONLY the snapshot recorded after a successful public feed rebuild. 162 * The admin's live option may contain unsent edits and must not leak here. 163 */ 164 public function on_request_services( $request = null ) { 165 $requested_outlet = ''; 166 $requested_query = ''; 167 if ( is_object( $request ) && method_exists( $request, 'get_param' ) ) { 168 $requested_outlet = $request->get_param( 'outlet' ); 169 $requested_query = $request->get_param( 'q' ); 170 } 171 $requested_outlet = null === $requested_outlet ? '' : $requested_outlet; 172 $requested_query = null === $requested_query ? '' : $requested_query; 173 if ( ! is_string( $requested_outlet ) || ! is_string( $requested_query ) || 174 ! preg_match( '/^[a-zA-Z0-9-]{0,64}$/D', $requested_outlet ) || 175 strlen( $requested_query ) > 100 || 176 preg_match( '/[\\x00-\\x1F]/', $requested_query ) ) { 177 return rest_ensure_response( array( 'schema' => 1, 'items' => array() ) ); 178 } 179 $terms = preg_split( '/\\s+/u', trim( $requested_query ), -1, PREG_SPLIT_NO_EMPTY ); 180 if ( false === $terms ) { 181 $terms = array(); 182 } 183 $stored = get_option( 'brendigo_bazna_published_inquiry_v1', array() ); 184 $items = array(); 185 if ( is_array( $stored ) ) { 186 foreach ( array_slice( $stored, 0, 500 ) as $row ) { 187 if ( ! is_array( $row ) ) { 188 continue; 189 } 190 $name = isset( $row['name'] ) && is_string( $row['name'] ) ? $row['name'] : ''; 191 $criteria = isset( $row['criteria'] ) && is_string( $row['criteria'] ) ? $row['criteria'] : ''; 192 $outlet = isset( $row['outlet'] ) && is_string( $row['outlet'] ) ? $row['outlet'] : ''; 193 $id = isset( $row['id'] ) && is_string( $row['id'] ) ? $row['id'] : ''; 194 if ( '' === trim( $name ) || '' === trim( $criteria ) || 195 strlen( $name ) > 240 || strlen( $criteria ) > 800 || 196 ! preg_match( '/^[a-zA-Z0-9-]{0,64}$/D', $outlet ) || 197 ! preg_match( '/^[0-9]{1,12}$/D', $id ) ) { 198 continue; 199 } 200 if ( '' !== $requested_outlet && $outlet !== $requested_outlet ) { 201 continue; 202 } 203 $haystack = $name . ' ' . $criteria; 204 $matches = true; 205 foreach ( $terms as $term ) { 206 if ( function_exists( 'mb_stripos' ) ? 207 false === mb_stripos( $haystack, $term, 0, 'UTF-8' ) : 208 false === stripos( $haystack, $term ) ) { 209 $matches = false; 210 break; 211 } 212 } 213 if ( ! $matches ) { 214 continue; 215 } 216 $items[] = array( 217 'id' => $id, 218 'name' => $name, 219 'criteria' => $criteria, 220 'outlet' => $outlet, 221 ); 222 } 223 } 224 $response = rest_ensure_response( array( 'schema' => 1, 'items' => $items ) ); 225 $response->header( 'Cache-Control', 'no-store, max-age=0, must-revalidate' ); 226 return $response; 75 227 } 76 228 … … 78 230 $kind = $request->get_param( 'kind' ); 79 231 $outlet = $request->get_param( 'outlet' ); 80 return rest_ensure_response( Brendigo_Sidrena_Cijena_Archive::instance()->separate_archive_files( $kind ? $kind : '', $outlet ? sanitize_key( $outlet ) : '' ) ); 232 $response = rest_ensure_response( Brendigo_Sidrena_Cijena_Archive::instance()->separate_archive_files( $kind ? $kind : '', $outlet ? sanitize_key( $outlet ) : '' ) ); 233 $response->header( 'Cache-Control', 'no-store, max-age=0, must-revalidate' ); 234 return $response; 81 235 } 82 236 … … 96 250 $response = new WP_REST_Response( null, 302 ); 97 251 $response->header( 'Location', $files->get_type_public_url( $kind, $ext, $oznaka ) ); 98 $response->header( 'Cache-Control', 'public, max-age=300' ); 252 // A cached 302 can point at an older published file after rebuilding. 253 $response->header( 'Cache-Control', 'no-store, max-age=0, must-revalidate' ); 99 254 return $response; 100 255 } -
brendigo-sidrena-cijena/includes/class-settings.php
r3737238 r3801404 14 14 15 15 const OPTION_KEY = 'sidrena_cijena_settings'; 16 const DEFAULT_PREFIX = 'Sidrena cijena'; 16 const DEFAULT_PREFIX = 'Bazna cijena'; 17 const PREVIOUS_BRAND_PREFIX = 'Sidrena cijena'; 17 18 const LEGACY_PREFIX = 'Cijena'; 18 19 const REFERENCE_DATE_GENERAL = '10.09.2026.'; 19 20 const REFERENCE_DATE_FMCG = '02.05.2025.'; 20 const DEFAULT_TOOLTIP = 'Sidrena cijena je referentna maloprodajna cijena koja je za proizvod ili uslugu vrijedila na navedeni datum.'; 21 const DEFAULT_TOOLTIP = 'Bazna cijena je dokumentirana maloprodajna cijena koja je vrijedila na točno određeni referentni dan. Nije isto što i najniža cijena prije sniženja.'; 22 const PREVIOUS_BRAND_TOOLTIP = 'Sidrena cijena je referentna maloprodajna cijena koja je za proizvod ili uslugu vrijedila na navedeni datum.'; 21 23 const PREVIOUS_TOOLTIP_HASH = '4fdd1b2eba2678023ab9618dc15839bd2efc789ee3404c799ba199eb47dd5404'; 22 24 const LEGACY_TOOLTIP_HASH = '2c8ca8cdc51d22e369144a40b69c504ba24db0b1a08a1e42a04bb065d1102661'; … … 138 140 } 139 141 142 if ( isset( $stored['prefix'] ) && self::PREVIOUS_BRAND_PREFIX === trim( (string) $stored['prefix'] ) ) { 143 // Migrate only our old factory default, never a merchant's custom label. 144 $stored['prefix'] = self::DEFAULT_PREFIX; 145 $dirty = true; 146 } 147 140 148 if ( isset( $stored['prefix'] ) && self::LEGACY_PREFIX === trim( (string) $stored['prefix'] ) ) { 141 149 $stored['prefix'] = self::DEFAULT_PREFIX; … … 145 153 if ( isset( $stored['tooltip'] ) ) { 146 154 $tooltip_hash = hash( 'sha256', trim( (string) $stored['tooltip'] ) ); 147 if ( in_array( $tooltip_hash, array( self::LEGACY_TOOLTIP_HASH, self::PREVIOUS_TOOLTIP_HASH ), true ) ) { 155 if ( trim( (string) $stored['tooltip'] ) === self::PREVIOUS_BRAND_TOOLTIP || 156 in_array( $tooltip_hash, array( self::LEGACY_TOOLTIP_HASH, self::PREVIOUS_TOOLTIP_HASH ), true ) ) { 148 157 $stored['tooltip'] = self::DEFAULT_TOOLTIP; 149 158 $dirty = true; … … 153 162 if ( isset( $stored['i18n']['prefix'] ) && is_array( $stored['i18n']['prefix'] ) ) { 154 163 foreach ( $stored['i18n']['prefix'] as $lang => $value ) { 155 if ( is_string( $value ) && self::LEGACY_PREFIX === trim( $value ) ) {164 if ( is_string( $value ) && in_array( trim( $value ), array( self::LEGACY_PREFIX, self::PREVIOUS_BRAND_PREFIX ), true ) ) { 156 165 $stored['i18n']['prefix'][ $lang ] = self::DEFAULT_PREFIX; 157 166 $dirty = true; … … 167 176 if ( isset( $stored['i18n']['tooltip'] ) && is_array( $stored['i18n']['tooltip'] ) ) { 168 177 foreach ( $stored['i18n']['tooltip'] as $lang => $value ) { 169 if ( is_string( $value ) && self::LEGACY_TOOLTIP_HASH === hash( 'sha256', trim( $value ) ) ) { 178 if ( is_string( $value ) && ( 179 self::PREVIOUS_BRAND_TOOLTIP === trim( $value ) 180 || in_array( hash( 'sha256', trim( $value ) ), array( self::LEGACY_TOOLTIP_HASH, self::PREVIOUS_TOOLTIP_HASH ), true ) 181 ) ) { 170 182 $stored['i18n']['tooltip'][ $lang ] = self::DEFAULT_TOOLTIP; 171 183 $dirty = true; … … 276 288 */ 277 289 public function is_auto_fill_enabled() { 278 return 'yes' === $this->get( 'auto_fill' ); 290 // A saved legacy preference cannot establish a verified historical price. 291 // This safeguard also applies to sites upgrading from older plugin versions. 292 return false; 279 293 } 280 294 -
brendigo-sidrena-cijena/readme.txt
r3737344 r3801404 1 === SIDRENA – Sidrene cijene i cjenici ===1 === BAZNA – Bazne cijene i cjenici === 2 2 Contributors: brendigo 3 3 Tags: reference-prices, price-list, csv, croatia, woocommerce … … 5 5 Tested up to: 7.1 6 6 Requires PHP: 7.4 7 Stable tag: 1.5. 07 Stable tag: 1.5.20 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 Manage reference prices and dates, publish a public HTML pricelist, and generate XML/CSV archives for WooCommerce or standalone catalogs.11 BAZNA by Brendigo: bazne cijene i datumi, javni HTML cjenici te CSV/XML arhiva za WordPress i WooCommerce. 12 12 13 13 == Description == 14 14 15 **SIDRENA brings reference prices, transparent public pricelists and dated archives together in one WordPress dashboard.** Built for WooCommerce stores and independent WordPress catalogs, without adding an external account or mandatory hosted service. 15 **Svi alati bez aktivacije:** BAZNA 1.5.20 radi bez licencnog ključa, online provjere, probnog roka ili aktivacije. Administratorske mogućnosti dostupne su ovlaštenim WordPress korisnicima; postojeće cijene i povijest nisu resetirani. 16 17 18 **BAZNA brings reference prices, transparent public pricelists and dated archives together in one WordPress dashboard.** Built for WooCommerce stores and independent WordPress catalogs, without adding an external account or mandatory hosted service. 16 19 17 20 = Publish with clarity = … … 28 31 29 32 30 Brendigo Sidrena Cijenaprovides one interface for managing reference-price data and publishing a public pricelist.33 Brendigo Bazne cijene provides one interface for managing reference-price data and publishing a public pricelist. 31 34 32 35 Key features: … … 56 59 Reference prices and dates are entered or imported by the site administrator. The plugin does not infer historical prices. 57 60 58 Documentation: https://brendigo.com/ sidrene-cijene61 Documentation: https://brendigo.com/ 59 62 60 63 == Installation == 61 64 62 After activation, open the **Upute** (Guide) tab inside Brendigo Sidrena Cijenafor a step-by-step onboarding guide in Croatian: separate instructions for standalone WordPress and WooCommerce, publishing, imports, public shortcodes, and troubleshooting.63 64 65 1. Install the ZIP from WordPress Plugins > Add New, or upload the `brendigo-sidrena-cijena` folder to `/wp-content/plugins/`.66 2. Activate ** SIDRENA**.67 3. Open WooCommerce > SIDRENA. Without WooCommerce, use the standalone SIDRENA menu.65 After activation, open the **Upute** (Guide) tab inside Brendigo Bazne cijene for a step-by-step onboarding guide in Croatian: separate instructions for standalone WordPress and WooCommerce, publishing, imports, public shortcodes, and troubleshooting. 66 67 68 1. Install the ZIP from WordPress Plugins > Add New, or upload the unmodified BAZNA plugin folder through your hosting file manager. 69 2. Activate **BAZNA**. 70 3. Open WooCommerce > BAZNA. Without WooCommerce, use the standalone BAZNA menu. 68 71 4. Open **Products** to enter reference prices and dates. 69 72 5. Open **Public pricelist** to choose the daily publication time and publish the first version. … … 77 80 == Standalone WordPress without WooCommerce == 78 81 79 WooCommerce is optional. Activate the plugin in a standard WordPress installation and use the **Brendigo Sidrena Cijena** menu. Add manual products and services in the Products tab, provide the current price, reference price and date, then publish the HTML/XML/CSV pricelist. No checkout or online payment module is added to WordPress by this plugin.80 81 Use `[ sidrena_stavka id="123"]` for a named card showing the current and reference price, `[sidrena-cijena id="123"]` for the reference price, `[sidrena_povijest_cijena id="123"]` for observed price history, and `[sidrena-cjenik]` for the entire pricelist. When WooCommerce is also active, prefix the manual row ID with `d` for shortcodes that may otherwise resolve to a WooCommerce product: `id="d123"`. Individual manual item cards always use the manual catalog.82 WooCommerce is optional. Activate the plugin in a standard WordPress installation and use the **Brendigo Bazne cijene** menu. Add manual products and services in the Products tab, provide the current price, reference price and date, then publish the HTML/XML/CSV pricelist. No checkout or online payment module is added to WordPress by this plugin. 83 84 Use `[bazna-stavka id="123"]` for a named card showing the current and reference price, `[bazna-cijena id="123"]` for the reference price, `[bazna-povijest-cijena id="123"]` for observed price history, and `[bazna-cjenik]` for the entire pricelist. When WooCommerce is also active, prefix the manual row ID with `d` for shortcodes that may otherwise resolve to a WooCommerce product: `id="d123"`. Individual manual item cards always use the manual catalog. 82 85 83 86 Price history starts when tracking is installed or a product is first seen; it does not backdate or establish the legally required historical reference price. Daily publishing uses the WordPress event scheduler and an on-visit recovery fallback; for predictable timing even on low-traffic sites configure a server-side cron. … … 91 94 == Shortcodes == 92 95 93 `[b rendigo-sidrena-cijena]` - reference price for the current product.94 `[b rendigo-sidrena-cijena id="123"]` - reference price for a selected product or manual catalog row.95 `[b rendigo-sidrena-cjenik]` - public pricelist table.96 `[b rendigo-sidrena-arhiva]` - public pricelist archive.97 `[ sidrena_stavka id="123"]` - standalone product or service card, no WooCommerce needed.98 `[ sidrena_povijest_cijena id="123"]` - observed price history in standalone mode; with WooCommerce use `d123` for a manual row.96 `[bazna-cijena]` - reference price for the current product. 97 `[bazna-cijena id="123"]` - reference price for a selected product or manual catalog row. 98 `[bazna-cjenik]` - public pricelist table. 99 `[bazna-arhiva]` - public pricelist archive. 100 `[bazna-stavka id="123"]` - standalone product or service card, no WooCommerce needed. 101 `[bazna-povijest-cijena id="123"]` - observed price history in standalone mode; with WooCommerce use `d123` for a manual row. 99 102 100 103 Legacy shortcode aliases remain available for backward compatibility. … … 102 105 == WP-CLI == 103 106 104 `wp sidrena-cijena regenerate` regenerates and archives the public pricelist.105 106 `wp sidrena-cijena health` reports publication schedule and automation state.107 108 `wp sidrena-cijena fill` can fill empty reference-price fields from regular prices when an administrator intentionally chooses that workflow.107 `wp bazna regenerate` regenerates and archives the public pricelist. 108 109 `wp bazna health` reports publication schedule and automation state. 110 111 `wp bazna fill` is a legacy, administrator-initiated convenience command. It must not be used as evidence of a historical reference price: verify and enter the actual historical amount and date before publication. 109 112 110 113 == Frequently Asked Questions == … … 122 125 Yes. The daily publication time is configurable in the Public pricelist tab. 123 126 124 = Does the plugin send catalog data to an external service? = 125 126 No. The plugin does not make remote API requests for catalog processing. The administrator guide is built into the plugin and does not require an external connection. 127 = Does BAZNA require a license key, account, subscription or external activation service? = 128 129 No. All included local WordPress and WooCommerce features are available to users with the existing WordPress permissions. There are no license keys, trial periods, remote license checks or paid feature locks. WordPress administrators still sign in to protect editing and publication. 130 131 = Does BAZNA send my prices to an external license service? = 132 133 No. BAZNA stores catalog data and publishes only the public price lists chosen by the site owner. The former external activation service has been removed from the plugin. Android and Windows read only approved public HTTPS endpoints; they never need administrator credentials or a BAZNA license key. 134 135 = Is BAZNA derived from an existing GPL project? = 136 137 Yes. Components were adapted from MJDD Sidrena i bazna cijena 1.26.0 by Jure Zadravec / MJDD (GPLv2 or later). See ORIGINAL-CREDITS.txt and LICENSE in the plugin ZIP. BAZNA is separately developed and maintained by Brendigo and does not claim endorsement by MJDD. 127 138 128 139 == Upgrade Notice == … … 169 180 170 181 == Changelog == 182 183 = 1.5.20 = 184 * Uklonjena aktivacijska provjera i zaključavanje uvoza, uređivanja i objave. Službeni ZIP i WordPress.org kandidat koriste istu otključanu jezgru. 185 * REST v1 on-request search supports optional outlet and criteria query; public results never include unapproved drafts. 186 * Same published HTML price-list semantics across PHP/Joomla/Shopify and Android's global catalog search. 187 * Preserve existing accounts, prices, history, WC compatibility, and previous REST v1 endpoints. 188 189 190 = 1.5.19 = 191 * Public WordPress REST v1 publishes only previously published services priced on request, with name, criteria and outlet; drafts stay private. 192 * PHP, Joomla, Shopify and Android share the same published-only data contract. No invented numeric amounts in CSV/XML. 193 * Existing accounts, price history and older REST v1 paths are preserved. 194 195 196 = 1.5.18 = 197 * Usklađen javni status objave svih poslovnica u REST v1 i Androidu. Pravna revizija od 14. 11. 2026. bez automatskog proglašavanja nacrta pravilnika važećim. 198 199 200 = 1.5.17 = 201 * Android BAZNA package changed to com.brendigo.bazna for a new Play listing; WordPress public API and stored price data remain unchanged. 202 203 204 = 1.5.16 = 205 * Audit public BAZNA graphics and all user-visible brand labels on Android, WordPress, Web PHP, Joomla and Shopify. 206 * Correct the WordPress version history and legacy package names in public release documentation. 207 * Keep existing WordPress database keys and REST aliases and the Android application identity for uninterrupted upgrades. 208 * Strengthen all-platform production-readiness checks without inferring historical prices or changing stored evidence. 209 210 = 1.5.15 = 211 * Improve BAZNA integration parity across standalone PHP, Joomla, Shopify and Android while preserving the original public WordPress REST v1 endpoints and published price history. 212 * Align legal metadata, reference dates and public licensing status checks across supported BAZNA platforms. 213 * Preserve compatibility with existing WordPress installations, WooCommerce product metadata, shortcodes and published CSV/XML feeds. 214 * WordPress.org review candidate continues to ship with local features unlocked; the private licensed distribution remains separate. 215 216 = 1.5.14 = 217 * Improve BAZNA integration parity across standalone PHP, Joomla, Shopify and Android while preserving existing WordPress REST v1 endpoints and historical price records. 218 * Align legal metadata, reference dates and public licensing status checks across supported BAZNA platforms. 219 * Preserve compatibility with existing WordPress installations, WooCommerce product metadata, shortcodes and published CSV/XML feeds. 220 * Keep the WordPress.org review candidate with local features unlocked and the private licensed distribution separate. 221 222 = 1.5.13 = 223 * Keep already published WooCommerce reference prices visible in theme/builder layouts and cart/checkout blocks even when the admin license is inactive. 224 * Preserve the bounded offline license grace during HTTP 429, temporary service failure or malformed network response; revoke only an explicit invalid-key/domain decision. 225 * Restrict Woo product metadata editing and REST access until BAZNA license activation without deleting saved prices. 226 * Android accepts bare WordPress domains and adds HTTPS automatically, retaining same-origin and safe-DNS checks. 227 * Add license-server CLI preflight to the complete upload package, with extra Android/WordPress regression tests. 228 * Retain legal distinction between actual, reference and 30-day lowest prices and publicly readable CSV/XML feeds. 229 230 = 1.5.12 = 231 * Publish a deployable standalone BAZNA PHP/JSON license-server archive, with protected paths, Nginx/Apache instructions and private-config overlay. 232 * License API readiness now refuses to claim success if the required master secret, PHP modules or private JSON storage are unavailable. 233 * Keep a permanent one-domain registration, reject unsafe JSON registry states and never publish keys to Android REST clients. 234 * Android now checks the optional non-sensitive license status and continues displaying published prices even when the admin license is inactive. 235 * Add CI tests, reproducible checksums, 2026 Croatian legal notes and hardened infrastructure documentation. 236 237 = 1.5.11 = 238 * Rebrand the user-facing system as BAZNA — Bazne cijene, including WordPress administration and Android/Windows interfaces. 239 * Keep the existing WordPress plugin folder, REST v1 routes, database options and WooCommerce meta for in-place updates. 240 * Add bazna_cijena, bazna_cjenik and bazna_arhiva shortcode aliases while preserving legacy shortcodes. 241 * Migrate only factory default reference-price labels and tooltips; preserve merchant customizations. 242 * Introduce a BAZNA vector icon and legacy-install-safe desktop branding. 243 * Add compatibility and regression checks, legal terminology review and staged migration documentation. 244 245 = 1.5.10 = 246 * Prevent stale public REST publication status and 302 feed redirects with explicit no-store cache policy. 247 * Harden Android CSV handling against duplicate or ambiguous price headers and malformed row widths. 248 * Validate public read-only Android connection capabilities in the official WordPress discovery contract. 249 * Request fresh published data and reject incomplete HTTP responses; add contract regression tests. 250 * Preserve existing historical prices, public CSV/XML columns, archives and anonymous read-only REST v1 routes. 251 252 = 1.5.9 = 253 * Improve Android HTTPS linking on WordPress installations using plain or pretty REST permalinks, without allowing cross-origin or private network access. 254 * Add explicit, anonymous, read-only Android connection details to the public v1 discovery API; all published CSV/XML and archive routes remain unchanged. 255 * Remove unreachable legacy price-snapshot routines that must not infer historic reference prices. 256 * Expand WordPress/Android API contract, security and legal regression checks. 257 258 = 1.5.8 = 259 * Improve responsive editor headings and action buttons on mobile and tablet WordPress admin screens. 260 * Extend Chrome UI regression checks for wrapped catalog headings without modifying existing product or price data. 261 * Keep public REST v1, archive, CSV/XML and legal reference prices compatible with prior versions. 262 263 = 1.5.7 = 264 * Improve mobile and tablet editing ergonomics in the wide catalog without changing catalog data or columns. 265 * Use minimum 44px controls inside the horizontally scrollable price table. 266 * Expand browser regression checks for editable rows and ensure all mobile failures are reported independently. 267 * Preserve REST v1, historical anchor prices and existing CSV/XML formats. 268 269 = 1.5.6 = 270 * Fix narrow WordPress administrator navigation so all BAZNA tabs are visible in two columns without unwanted horizontal clipping. 271 * Increase navigation, search, select and save controls to 44px minimum touch height on mobile. 272 * Add 13-viewport browser regression checks for navigation layout, tap targets and viewport clipping. 273 * Preserve existing prices, historical records, public CSV/XML formats and REST v1 API. 274 275 = 1.5.5 = 276 * Improve mobile pricelist card wrapping and visual consistency with BAZNA Android. 277 * Preserve existing CSV/XML fields, prices, historical dates and REST v1 compatibility. 278 * Refine WordPress mobile interface regression checks without external runtime dependencies. 279 280 = 1.5.4 = 281 * Added public read-only CSV feed availability flags in the existing BAZNA REST API, including separate business outlet statuses, to prevent misleading Android loading states. 282 * Added optional WooCommerce product thumbnails to the public product CSV/XML feed without changing the required price, date or service columns. 283 * Added a WordPress dashboard connection panel for the BAZNA Android application, with copyable HTTPS address and actual published-feed readiness. 284 * Aligned BAZNA admin and public price-list colors with the Android brand; no new third-party dependencies. 285 * Kept API version 1 and compatibility with older Android clients. Changes are prepared in a PR and require deployment to become available. 286 287 = 1.5.3 = 288 * Separate the 30-day sale baseline from documented historical reference prices in the public legal metadata. 289 * Document the effective date of NN 105/2026 and pending 2026 rulebook consultation without changing existing public CSV/XML schemas or saved prices. 290 291 = 1.5.2 = 292 * Published machine-readable legal guidance for the 2026 reference-price dates, effective date and 30-day public archive requirement in the existing read-only REST catalog discovery endpoint. 293 * Kept CSV/XML publication schemas backward-compatible with version 1.5.0 and made the public API identify the exact plugin version. 294 * Preserved the administrator's responsibility to assign the appropriate historical reference date; no automatic invention of prices or inference of product categories. 171 295 172 296 = 1.5.0 = … … 174 298 * Fixed Serbian Latin translation filenames to `sr_RS_latin` and regenerated all compiled locale catalogs. 175 299 * Removed manual translation loading discouraged for WordPress.org-hosted plugins. 176 * Added SIDRENA brand symbol to the WordPress admin and prepared separate WordPress.org icon/banner assets.300 * Added BAZNA brand symbol to the WordPress admin and prepared separate WordPress.org icon/banner assets. 177 301 * Kept Croatian as the source language and reference-price logic unchanged. 178 179 302 180 303 = 1.4.4 = … … 194 317 * Kept current public price outputs and WordPress.org distribution clean of extra markdown files. 195 318 196 197 319 = 1.4.1 = 198 320 * Fixed WordPress.org Plugin Check errors for options, temporary XLSX files and product query filters. 199 321 * Improved plugin-owned SQL safety and reduced repeat database reads while retaining up-to-date administrator audit information. 200 322 * Removed internal development documentation from the distributable package. 201 202 323 203 324 = 1.3.3 = … … 209 330 = 1.3.1 = 210 331 * Fully support observing manual product/service price changes without WooCommerce; protect history from WooCommerce ID collisions. 211 * Add `[ sidrena_stavka id="123"]` for a lightweight named manual product/service card.332 * Add `[bazna-stavka id="123"]` for a lightweight named manual product/service card. 212 333 * Prevent malformed or truncated catalog JSON from wiping stored data, strictly validate item IDs, and avoid reusing automatic row IDs after deletion. 213 334 * Improve manual-row lookup with an in-request index and prevent accidental repeated unslashing of stored text.
Note:
See TracChangeset
for help on using the changeset viewer.