Plugin Directory

Changeset 3801404


Ignore:
Timestamp:
11/14/2026 04:36:41 AM (28 hours ago)
Author:
brendigo
Message:

initial commit

Location:
brendigo-sidrena-cijena
Files:
146 added
37 edited

Legend:

Unmodified
Added
Removed
  • brendigo-sidrena-cijena/LICENSE

    r3723942 r3801404  
    11Sidrena
    22Copyright (C) 2026 Brendigo
     3Portions adapted from MJDD Sidrena i bazna cijena 1.26.0:
     4Copyright (C) 2026 Jure Zadravec / MJDD (GPL-2.0-or-later)
    35
    46License: GNU General Public License v2 or later
  • brendigo-sidrena-cijena/assets/css/admin.css

    r3737344 r3801404  
    38153815    object-fit: contain;
    38163816}
     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. */
     3965body.sidrena-cijena-screen,
     3966body.sidrena-cijena-screen #wpcontent,
     3967body.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  
    11:root {
    22        color-scheme: dark;
    3         --br-bg: #06101e;
     3        --br-bg: #07182d;
    44        --br-line: rgba(159, 181, 210, 0.16);
    5         --br-text: #f7f9fc;
    6         --br-muted: #9aaac0;
    7         --br-gold: #f4bd52;
     5        --br-text: #ffffff;
     6        --br-muted: #a9bad1;
     7        --br-gold: #ff852c;
    88}
    99* { box-sizing: border-box; }
  • brendigo-sidrena-cijena/assets/css/cjenik.css

    r3727711 r3801404  
    11:root {
    22        color-scheme: dark;
    3         --br-bg: #06101e;
     3        --br-bg: #07182d;
    44        --br-line: rgba(159, 181, 210, 0.16);
    5         --br-text: #f7f9fc;
    6         --br-muted: #9aaac0;
    7         --br-gold: #f4bd52;
    8         --br-green: #39d99b;
     5        --br-text: #ffffff;
     6        --br-muted: #a9bad1;
     7        --br-gold: #ff852c;
     8        --br-green: #52d9a3;
    99        --br-red: #ff7d8f;
    1010}
    … …  
    1616        background:
    1717                radial-gradient(circle at 82% 4%, rgba(115, 87, 255, 0.16), transparent 28%),
    18                 radial-gradient(circle at 12% 92%, rgba(244, 189, 82, 0.08), transparent 30%),
     18                radial-gradient(circle at 12% 92%, rgba(255, 133, 44, 0.08), transparent 30%),
    1919                var(--br-bg);
    2020        color: var(--br-text);
    … …  
    4747        height: 330px;
    4848        border-radius: 50%;
    49         background: radial-gradient(circle, rgba(244, 189, 82, 0.16), transparent 66%);
     49        background: radial-gradient(circle, rgba(255, 133, 44, 0.16), transparent 66%);
    5050        pointer-events: none;
    5151}
    … …  
    102102
    103103.cjenik-btn {
    104         background: linear-gradient(135deg, #f6cb69, #e2a239);
     104        background: linear-gradient(135deg, #ffaa55, #ff852c);
    105105        color: #111924;
    106106        box-shadow: 0 10px 24px rgba(226, 162, 57, 0.16);
    … …  
    131131        border: 1px solid var(--br-line);
    132132        border-radius: 11px;
    133         background: #071525;
     133        background: #19304a;
    134134        color: var(--br-text);
    135135        font: inherit;
    … …  
    137137}
    138138.cjenik-search input::placeholder { color: #71849d; }
    139 .cjenik-search input:focus { border-color: rgba(244, 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); }
    140140
    141141.cjenik-pager {
    … …  
    147147}
    148148.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(244, 189, 82, 0.45); background: #13243a; }
    151 .cjenik-page.is-current { border-color: rgba(244, 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; }
    152152.cjenik-page-gap { color: var(--br-muted); }
    153153
    … …  
    177177
    178178.cjenik-table th, .cjenik-upit th {
    179         background: #0d1b2d;
     179        background: #10263d;
    180180        color: #aebdd0;
    181181        font-size: 0.72rem;
    … …  
    233233
    234234@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  
    189189.sidrena-price-chart__note{font-size:.875em;opacity:.85}
    190190.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  
    6767                        }
    6868                        var prefix = typeof sidrenaCijenaAdmin !== "undefined" && sidrenaCijenaAdmin.catalogIdPrefix ? sidrenaCijenaAdmin.catalogIdPrefix : "";
    69                         return '[sidrena-cijena id="' + prefix + id + '"]';
     69                        return '[bazna-cijena id="' + prefix + id + '"]';
    7070                }
    7171
    … …  
    688688                        }
    689689                        if (!$.trim(row.sidrena_cijena || "")) {
    690                                 missing.push("sidrena");
     690                                missing.push("bazna_cijena");
    691691                        }
    692692                        return missing;
    … …  
    738738                        });
    739739
    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.";
    741741                        var $notice = $form.find(".brendigo-catalog-validation");
    742742                        if (!$notice.length) {
    … …  
    837837                $form.on("input change", ".brendigo-woo-row :input", updateChangeStatus);
    838838
    839                 function visibleRows() {
    840                         return $rows.filter(function () {
    841                                 return !$(this).is("[hidden]");
    842                         });
    843                 }
    844 
    845839                function applyFilters() {
    846840                        var query = $.trim($("#sidrena-wc-filter").val() || "").toLowerCase();
    … …  
    871865                $form.on("change", ".js-sidrena-wc-price", applyFilters);
    872866
    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.
    902869
    903870                $resetButton.on("click", function () {
  • brendigo-sidrena-cijena/assets/js/admin.js

    r3727711 r3801404  
    4141
    4242                        if (!prefix && style !== "plain") {
    43                                 prefix = "Sidrena cijena";
     43                                prefix = "Bazna cijena";
    4444                        }
    4545
  • brendigo-sidrena-cijena/brendigo-sidrena-cijena.php

    r3737344 r3801404  
    22/**
    33 * 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.0
     4 * 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
    77 * Requires at least: 6.6
    88 * Requires PHP: 7.4
    … …  
    1919defined( 'ABSPATH' ) || exit;
    2020
    21 define( 'BRENDIGO_SIDRENA_CIJENA_VERSION', '1.5.0' );
     21define( 'BRENDIGO_SIDRENA_CIJENA_VERSION', '1.5.20' );
    2222define( 'BRENDIGO_SIDRENA_CIJENA_FILE', __FILE__ );
    2323define( '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
    144= 1.5.0 – 2026-10-09 =
    245* Matched the plugin name and readme heading exactly for WordPress.org Plugin Check.
  • brendigo-sidrena-cijena/includes/admin/tab-javni-xml.php

    r3737238 r3801404  
    7575                        }
    7676                }
    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' ) );
    7878
    7979                if ( $sidrena_settings->is_multi_poslovnica() ) {
    … …  
    8686                ?>
    8787        </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>
    88171
    89172        <?php if ( $sidrena_generated_at > 0 ) : ?>
  • brendigo-sidrena-cijena/includes/admin/tab-postavke.php

    r3737238 r3801404  
    1414        <div>
    1515                <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>
    1717                <p><?php echo esc_html__( 'Odredite naziv, datum i način prikaza referentne cijene uz proizvod.', 'brendigo-sidrena-cijena' ); ?></p>
    1818        </div>
    … …  
    2828                        <div class="sidrena-cijena-card__head brendigo-card-title">
    2929                                <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>
    3131                        </div>
    3232
    3333                        <?php if ( $sidrena_woo ) : ?>
    3434                        <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>
    3636                                <?php $this->render_toggle( 'sidrena_cijena_auto_display', 'sidrena_cijena_auto_display', 'yes' === $sidrena_settings->get( 'auto_display' ), __( 'Automatski prikaz', 'brendigo-sidrena-cijena' ) ); ?>
    3737                        </div>
    3838                        <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>
    4142                        </div>
    4243                        <?php endif; ?>
    4344
    4445                        <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>
    4647                                <?php $this->render_toggle( 'sidrena_cijena_enable_tooltip', 'sidrena_cijena_enable_tooltip', 'yes' === $sidrena_settings->get( 'enable_tooltip' ), __( 'Tooltip', 'brendigo-sidrena-cijena' ) ); ?>
    4748                        </div>
    … …  
    5051                                <span><?php echo esc_html__( 'Oznaka retka', 'brendigo-sidrena-cijena' ); ?></span>
    5152                                <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>
    5354                        </label>
    5455
    … …  
    5657                                <span><?php echo esc_html__( 'Format datuma', 'brendigo-sidrena-cijena' ); ?></span>
    5758                                <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>
    6061                                </div>
    6162                                <code id="sidrena-cijena-preview"><?php echo esc_html( $sidrena_settings->get_preview_label() . $sidrena_settings->preview_separator() . '19,99 €' ); ?></code>
    … …  
    9596
    9697                <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>
    9899                        <div class="brendigo-preview-demo">
    99100                                <div class="brendigo-preview-demo__media"><span class="dashicons dashicons-products" aria-hidden="true"></span></div>
    … …  
    103104                                printf(
    104105                                        /* translators: %s: locked general reference date. */
    105                                         esc_html__( 'Sidrena cijena (%s)', 'brendigo-sidrena-cijena' ),
     106                                        esc_html__( 'Bazna cijena (%s)', 'brendigo-sidrena-cijena' ),
    106107                                        esc_html( Brendigo_Sidrena_Cijena_Settings::REFERENCE_DATE_GENERAL )
    107108                                );
    … …  
    119120<?php if ( $sidrena_woo ) : ?>
    120121<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>
    131126        </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>
    135131</section>
    136132<?php endif; ?>
  • brendigo-sidrena-cijena/includes/admin/tab-pregled.php

    r3737238 r3801404  
    9191                <div>
    9292                        <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>
    9494                        <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>
    9595                </div>
    … …  
    102102</section>
    103103
     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    &nbsp;·&nbsp; <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
    104141<section class="brendigo-kpi-grid" aria-label="<?php echo esc_attr__( 'Sažetak', 'brendigo-sidrena-cijena' ); ?>">
    105142        <article class="brendigo-kpi-card">
    106143                <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 sa 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>
    108145        </article>
    109146        <article class="brendigo-kpi-card">
    … …  
    145182
    146183        <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>
    148185                <?php if ( '' !== $sidrena_preview_name ) : ?>
    149186                        <div class="brendigo-product-preview__body">
    … …  
    156193                                        <?php
    157194                                        /* 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 );
    159196                                        ?>
    160197                                        <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>
    162199                                </div>
    163200                        </div>
    164201                <?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>
    166203                <?php endif; ?>
    167204        </article>
  • brendigo-sidrena-cijena/includes/admin/tab-proizvodi.php

    r3737238 r3801404  
    3131                <div class="sidrena-cijena-callout">
    3232                        <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>
    3434                </div>
    3535
    … …  
    3939                                <div>
    4040                                        <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>
    4242                                </div>
    4343                                <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>
    … …  
    6565                                        <select id="sidrena-wc-price-filter">
    6666                                                <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__( 'Sa 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>
    6969                                        </select>
    7070                                </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>
    7772                        </div>
    7873                        <div class="brendigo-woo-catalog-summary">
    … …  
    9388                                                        <th><?php echo esc_html__( 'SKU', 'brendigo-sidrena-cijena' ); ?></th>
    9489                                                        <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>
    9691                                                        <th><?php echo esc_html__( 'Cijena je vrijedila na dan', 'brendigo-sidrena-cijena' ); ?></th>
    9792                                                        <th><?php echo esc_html__( 'Barkod', 'brendigo-sidrena-cijena' ); ?></th>
    … …  
    111106                                                                <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>
    112107                                                                <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>
    114109                                                                <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>
    115110                                                                <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>
    … …  
    123118                                <div class="brendigo-woo-catalog-footer">
    124119                                        <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>
    126121                                                <button type="button" class="button button-secondary js-sidrena-wc-reset"><?php echo esc_html__( 'Poništi nespremljene promjene', 'brendigo-sidrena-cijena' ); ?></button>
    127122                                        </div>
    … …  
    220215                                                                <th><?php echo esc_html__( 'Jedinica mjere', 'brendigo-sidrena-cijena' ); ?></th>
    221216                                                                <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>
    223218                                                                <th><?php echo esc_html__( 'Datum sidrene', 'brendigo-sidrena-cijena' ); ?></th>
    224219                                                                <?php if ( Brendigo_Sidrena_Cijena_Settings::instance()->is_cjm_enabled() ) : ?>
  • brendigo-sidrena-cijena/includes/admin/tab-upute.php

    r3737238 r3801404  
    2929                'title' => __( 'Prije prvog korištenja', 'brendigo-sidrena-cijena' ),
    3030                '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' ) ),
    3232                        array( __( 'Napravite sigurnosnu kopiju stranice i baze podataka, posebno ako prelazite sa starije verzije dodatka.', 'brendigo-sidrena-cijena' ) ),
    3333                        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' ) ),
    3434                        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' ) ),
    3636                ),
    3737        ),
    … …  
    4242        'intro'  => __( 'Za cjenik proizvoda i usluga ne trebate internetsku trgovinu. Ovaj način rada ne uključuje košaricu ni naplatu.', 'brendigo-sidrena-cijena' ),
    4343        'steps' => array(
    44                 array( __( 'Nakon aktivacije u lijevom izborniku otvorite Brendigo 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' ) ),
    4545                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' ) ),
    4747                array( __( 'Ako imate više poslovnica, odaberite onu kojoj stavka pripada. Zatim kliknite „Spremi cjenik”.', 'brendigo-sidrena-cijena' ) ),
    4848                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' ) ),
    5050        ),
    5151);
    … …  
    5353$sidrena_help_woocommerce = array(
    5454        'title' => __( 'Upute: WordPress s WooCommerceom', 'brendigo-sidrena-cijena' ),
    55         'intro'  => __( 'WooCommerce upravlja nazivima proizvoda, zalihama i aktualnim cijenama. SIDRENA dodaje sidrene podatke i 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' ),
    5656        'steps' => array(
    5757                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 → Brendigo 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' ) ),
    6262                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' ) ),
    6363                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' ) ),
    … …  
    146146<section id="sidrena-help-faq" class="sidrena-cijena-card sidrena-help__section" aria-labelledby="sidrena-help-faq-title">
    147147        <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>
    149149        <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>
    151151        <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>
    152152        <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  
    1212                        <div class="sidrena-cijena-card__head">
    1313                                <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>
    1515                        </div>
    1616
    … …  
    6262                                        </label>
    6363                                        <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>
    6565                                                <select id="sidrena-import-map-sidrena"></select>
    6666                                        </label>
    6767                                        <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>
    6969                                                <select id="sidrena-import-map-datum"></select>
    7070                                        </label>
    … …  
    144144                        <div class="sidrena-cijena-card__head">
    145145                                <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>
    147147                        </div>
    148148                        <form method="post" action="<?php echo esc_url( $this->get_settings_tab_url( 'uvoz-izvoz' ) ); ?>">
    … …  
    162162                                        <button type="submit" class="button button-secondary" name="sidrena_cijena_action" value="export_missing">
    163163                                                <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' ); ?>
    165165                                        </button>
    166166                                        <button type="submit" class="button button-secondary" name="sidrena_cijena_action" value="export_template">
  • brendigo-sidrena-cijena/includes/class-activator.php

    r3727711 r3801404  
    3030
    3131        /**
    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.
    4337         */
    4438        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.
    20547        }
    20648
    … …  
    265107
    266108                $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                }
    267116
    268117                if ( $fast ) {
    … …  
    324173         */
    325174        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                }
    326178                $page       = max( 1, absint( $page ) );
    327179                $batch_size = max( 1, absint( $batch_size ) );
    … …  
    398250         */
    399251        public static function fast_fill( $dry_run = false ) {
     252                if ( ! $dry_run ) {
     253                        return array( 'written' => 0, 'updated' => 0, 'inserted' => 0, 'blocked' => true );
     254                }
    400255                global $wpdb;
    401256
  • brendigo-sidrena-cijena/includes/class-admin-save.php

    r3737238 r3801404  
    153153                        $payload['brand_taxonomy'] = isset( $_POST['sidrena_cijena_brand_taxonomy'] ) ? sanitize_text_field( wp_unslash( $_POST['sidrena_cijena_brand_taxonomy'] ) ) : '';
    154154                        $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.
    156156                }
    157157
    … …  
    386386                        wp_send_json_error( array( 'message' => 'forbidden' ), 403 );
    387387                }
     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;
    388395
    389396                while ( ob_get_level() > 0 ) {
  • brendigo-sidrena-cijena/includes/class-admin.php

    r3737344 r3801404  
    6464
    6565        /**
    66          * Whether the current request is the Sidrena cijena settings screen.
     66         * Whether the current request is the Bazna cijena settings screen.
    6767         *
    6868         * @return bool
    … …  
    119119        public function register_menu() {
    120120                $cap   = Brendigo_Sidrena_Cijena_Plugin::manage_capability();
    121                 $title = __( 'Brendigo Sidrena Cijena', 'brendigo-sidrena-cijena' );
     121                $title = __( 'BAZNA – Bazne cijene', 'brendigo-sidrena-cijena' );
    122122
    123123                if ( Brendigo_Sidrena_Cijena_Plugin::woocommerce_active() ) {
    … …  
    163163                $multi     = $settings->is_multi_poslovnica();
    164164                $xml_url   = $export->get_public_url();
    165                 $page_title = 'pregled' === $tab ? __( 'Brendigo 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' ) );
    166166                $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' ),
    168168                        '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' ),
    171171                        'javni-xml'    => __( 'HTML prikaz, XML/CSV datoteke i arhiva javnog cjenika.', 'brendigo-sidrena-cijena' ),
    172172                        'poslovnice'   => __( 'Više lokacija, zasebni javni cjenici i datoteke po poslovnici.', 'brendigo-sidrena-cijena' ),
    … …  
    177177                <div class="wrap sidrena-cijena-settings brendigo-sidrena-admin">
    178178                        <div class="brendigo-admin-shell">
    179                                 <aside class="brendigo-admin-sidebar" aria-label="<?php echo esc_attr__( 'Brendigo Sidrena Cijena', 'brendigo-sidrena-cijena' ); ?>">
     179                                <aside class="brendigo-admin-sidebar" aria-label="<?php echo esc_attr__( 'BAZNA – Bazne cijene', 'brendigo-sidrena-cijena' ); ?>">
    180180                                        <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>
    183183                                        </a>
    184184                                        <nav class="brendigo-admin-nav">
    … …  
    192192                                        <div class="brendigo-admin-sidebar__legal">
    193193                                                <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>
    195195                                                <small><?php echo esc_html__( 'Referentna cijena s datumom na koji je vrijedila.', 'brendigo-sidrena-cijena' ); ?></small>
    196196                                        </div>
    … …  
    200200                                        <header class="brendigo-admin-topbar">
    201201                                                <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>
    203203                                                        <h1><?php echo esc_html( $page_title ); ?></h1>
    204204                                                        <p><?php echo esc_html( $page_subtitle ); ?></p>
    … …  
    237237                                                        $this->render_tab_postavke( $settings );
    238238                                                } elseif ( 'upute' === $tab ) {
    239                                                         $this->render_tab_upute();
     239                            $this->render_tab_upute();
    240240                                                } else {
    241241                                                        do_action( 'sidrena_cijena_render_settings_tab', $tab );
    … …  
    244244
    245245                                                <footer class="sidrena-cijena-card sidrena-cijena-credit">
    246                                                         <div><strong><?php echo esc_html__( 'Brendigo 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>
    247247                                                        <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>
    248248                                                </footer>
    … …  
    259259         * @return array<string, array{label:string, icon:string}>
    260260         */
    261         private function get_tabs() {
     261        /** WordPress admin tabs remain accessible to authorized users without activation. */
     262    private function get_tabs() {
    262263                $tabs = array();
    263264
    … …  
    297298
    298299                /**
    299                  * Extra Sidrena cijena settings tabs.
     300                 * Extra Bazna cijena settings tabs.
    300301                 *
    301302                 * @param array<string, array{label:string, icon:string}> $tabs Tabs.
    … …  
    319320                }
    320321
    321                 if ( isset( $_GET['sidrena_xml'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     322                if ( isset( $_GET['sidrena_xml'] ) && isset( $tabs['javni-xml'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    322323                        return 'javni-xml';
    323324                }
    … …  
    559560
    560561        /**
    561          * After activation, point 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.
    562563         */
    563564        private function render_fill_prompt_notice() {
    … …  
    573574
    574575                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' );
    576577                echo ' <a href="' . esc_url( $settings_url ) . '">' . esc_html__( 'Otvori postavke', 'brendigo-sidrena-cijena' ) . '</a>';
    577578                echo ' · <a href="' . esc_url( $dismiss_url ) . '">' . esc_html__( 'Sakrij', 'brendigo-sidrena-cijena' ) . '</a>';
    … …  
    597598
    598599                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' );
    600601                echo '</p></div>';
    601602        }
    … …  
    633634
    634635                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' );
    636637                echo '</p></div>';
    637638        }
    … …  
    733734                                                'todayConfirm' => sprintf(
    734735                                                        /* 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' ),
    736737                                                        Brendigo_Sidrena_Cijena_Settings::REFERENCE_DATE_GENERAL
    737738                                                ),
    738739                                                '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' ),
    740741                                                'purging'      => __( 'Brisanje podataka…', 'brendigo-sidrena-cijena' ),
    741742                                                'copied'       => __( 'Kopirano', 'brendigo-sidrena-cijena' ),
    742743                                                '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' ),
    744745                                                'noFile'       => __( 'Odaberite CSV, XML ili XLSX datoteku.', 'brendigo-sidrena-cijena' ),
    745746                                                'invalidFile'  => __( 'Dopušteni su CSV, XML i XLSX.', 'brendigo-sidrena-cijena' ),
    … …  
    804805                                                'unsavedLabel'   => __( 'Nespremljene promjene', 'brendigo-sidrena-cijena' ),
    805806                                                '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' ),
    807807                                                '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' ),
    809809                                                'wooResetConfirm'   => __( 'Poništiti sve nespremljene promjene na ovoj stranici?', 'brendigo-sidrena-cijena' ),
    810810                                                'wooVisibleRows'     => __( 'Prikazano {visible} od {total} stavki na ovoj stranici.', 'brendigo-sidrena-cijena' ),
    … …  
    861861         */
    862862        public function add_product_column( $columns ) {
    863                 $columns['sidrena_cijena'] = __( 'Sidrena cijena', 'brendigo-sidrena-cijena' );
     863                $columns['sidrena_cijena'] = __( 'Bazna cijena', 'brendigo-sidrena-cijena' );
    864864                return $columns;
    865865        }
  • brendigo-sidrena-cijena/includes/class-autoloader.php

    r3737238 r3801404  
    2424                'Brendigo_Sidrena_Cijena_Notifications'  => 'includes/class-notifications.php',
    2525                'Brendigo_Sidrena_Cijena_Public_API'     => 'includes/class-public-api.php',
     26                'Brendigo_Sidrena_Cijena_Legal'          => 'includes/class-legal.php',
    2627                'Brendigo_Sidrena_Cijena_Woo_Blocks'     => 'includes/class-woo-blocks.php',
    2728                'Brendigo_Sidrena_Cijena_Settings'        => 'includes/class-settings.php',
  • brendigo-sidrena-cijena/includes/class-bulk-import.php

    r3737238 r3801404  
    6565                nocache_headers();
    6666                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"' );
    6868                header( 'Content-Length: ' . strlen( $bytes ) );
    6969                echo $bytes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- XLSX binary.
  • brendigo-sidrena-cijena/includes/class-catalog.php

    r3737238 r3801404  
    637637                }
    638638
    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 '';
    640641        }
    641642
  • brendigo-sidrena-cijena/includes/class-cli.php

    r3727711 r3801404  
    7979
    8080                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.' );
    8282                        return;
    8383                }
    … …  
    112112                        WP_CLI::success(
    113113                                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.',
    115115                                        $would
    116116                                )
    … …  
    124124                WP_CLI::success(
    125125                        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.',
    127127                                (int) $result['written'],
    128128                                (int) $result['inserted'],
    … …  
    134134
    135135        /**
    136          * Show how many products/variations already have a sidrena cijena.
     136         * Show how many products/variations already have a bazna cijena.
    137137         *
    138138         * ## EXAMPLES
    … …  
    162162                WP_CLI::success(
    163163                        sprintf(
    164                                 '%d of %d eligible items have a sidrena cijena.',
     164                                '%d of %d eligible items have a bazna cijena.',
    165165                                $stats['filled'],
    166166                                $stats['eligible']
  • brendigo-sidrena-cijena/includes/class-export.php

    r3737238 r3801404  
    665665                        }
    666666
     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                        }
    667687                        if ( ! is_wp_error( $result ) && class_exists( 'Brendigo_Sidrena_Cijena_Automation' ) ) {
    668688                                Brendigo_Sidrena_Cijena_Automation::instance()->clear_pending();
  • brendigo-sidrena-cijena/includes/class-feed-files.php

    r3737238 r3801404  
    8787                );
    8888
    89                 $this->headers( 'text/csv; charset=utf-8', 'sidrena-cijena-predlozak.csv' );
     89                $this->headers( 'text/csv; charset=utf-8', 'BAZNA-cjenik-predlozak.csv' );
    9090                echo chr( 0xEF ) . chr( 0xBB ) . chr( 0xBF ) . implode( '', $lines ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    9191                exit;
    … …  
    256256                }
    257257
    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' );
    259259        }
    260260
    … …  
    865865                        ++$row_index;
    866866
    867                         $html .= '<tr data-search="' . esc_attr( $search ) . '"' . $hidden . '>';
     867                        $html .= '<tr data-kind="' . esc_attr( $vrsta ) . '" data-search="' . esc_attr( $search ) . '"' . $hidden . '>';
    868868                        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>';
    870870                        }
    871871                        $html .= '</tr>';
    … …  
    940940                        'maloprodajna_cijena'   => array( 'label' => __( 'Maloprodajna cijena', 'brendigo-sidrena-cijena' ), 'always' => true ),
    941941                        '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 ),
    943943                        'sidrena_datum'         => array( 'label' => __( 'Datum sidrene', 'brendigo-sidrena-cijena' ), 'always' => false ),
    944944                        'dostupnost'            => array( 'label' => __( 'Dostupnost', 'brendigo-sidrena-cijena' ), 'always' => false ),
  • brendigo-sidrena-cijena/includes/class-feed-routes.php

    r3727711 r3801404  
    602602                $files = Brendigo_Sidrena_Cijena_Archive::instance()->get_archive_files();
    603603                $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' );
    605605
    606606                $this->open_public_document(
    … …  
    771771                $count     = (int) $snapshot['count'];
    772772                $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' );
    774774                $label     = $settings->get_preview_label();
    775775                $scope     = is_array( $outlet ) ? $this->outlet_label( $outlet ) : ( $settings->is_multi_poslovnica() ? $this->webshop_oznaka() : '' );
    … …  
    790790                wp_enqueue_script( 'brendigo-sidrena-cijena-cjenik' );
    791791                /* translators: %s: shop name. */
    792                 $meta_description = sprintf( __( 'Važeći cjenik sa sidrenom cijenom: %s', 'brendigo-sidrena-cijena' ), $shop );
     792                $meta_description = sprintf( __( 'Važeći cjenik s baznom cijenom: %s', 'brendigo-sidrena-cijena' ), $shop );
    793793                $this->open_public_document(
    794794                        $shop . ' - ' . $title,
    … …  
    903903        public function serve_cjenik_empty_page() {
    904904                $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' );
    906906
    907907                $this->open_public_document(
    … …  
    925925        public function serve_cjenik_pending_page() {
    926926                $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' );
    928928
    929929                $this->open_public_document(
  • brendigo-sidrena-cijena/includes/class-feed-rows.php

    r3727711 r3801404  
    308308                        $row['id']                     = (string) $product->get_id();
    309309                        $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 ) : '';
    310315                        $row['barkod']                 = $this->product_barcode( $product );
    311316                        $row['marka']                  = Brendigo_Sidrena_Cijena_Settings::instance()->product_marka( $product );
  • brendigo-sidrena-cijena/includes/class-frontend.php

    r3737238 r3801404  
    11<?php
    22/**
    3  * Storefront display of sidrena cijena.
     3 * Storefront display of bazna cijena.
    44 *
    55 * @package Brendigo_Sidrena_Cijena
    … …  
    3838                add_action( 'sidrena_cijena', array( $this, 'render_action' ), 10, 1 );
    3939                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' ) );
    4043                add_shortcode( 'sidrena_cijena', array( $this, 'shortcode' ) );
    4144                add_shortcode( 'brendigo-sidrena-cijena', array( $this, 'shortcode' ) );
    4245                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' ) );
    4348                add_shortcode( 'sidrena_cjenik', array( $this, 'cjenik_shortcode' ) );
    4449                add_shortcode( 'brendigo-sidrena-cjenik', array( $this, 'cjenik_shortcode' ) );
    4550                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' ) );
    4653                add_shortcode( 'sidrena_arhiva', array( $this, 'arhiva_shortcode' ) );
    4754                add_shortcode( 'brendigo-sidrena-arhiva', array( $this, 'arhiva_shortcode' ) );
    … …  
    5865                add_shortcode( 'sidrena_proizvodi', array( $this, 'cjenik_shortcode' ) );
    5966                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' ) );
    6071
    6172                if ( ! Brendigo_Sidrena_Cijena_Plugin::woocommerce_active() ) {
    … …  
    365376                $kind = sanitize_key( (string) $atts['vrsta'] );
    366377                // 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 ) ) {
    368379                        $kind = 'usluge';
    369                 } elseif ( 'sidrena_proizvodi' === $shortcode_tag ) {
     380                } elseif ( in_array( $shortcode_tag, array( 'sidrena_proizvodi', 'bazna_proizvodi' ), true ) ) {
    370381                        $kind = 'proizvodi';
    371382                }
    … …  
    508519                }
    509520
    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' )
    511528                        || has_shortcode( $post->post_content, 'sidrena_povijest_cijena' )
    512529                        || has_shortcode( $post->post_content, 'sidrena_najniza_prije_snizenja' )
    … …  
    528545                }
    529546
    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' )
    531552                        || has_shortcode( $post->post_content, 'sidrena_cjenik' )
    532553                        || has_shortcode( $post->post_content, 'sidrena_objava_cjenika' )
  • brendigo-sidrena-cijena/includes/class-i18n.php

    r3737344 r3801404  
    112112
    113113                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 );
    116116                }
    117117        }
    … …  
    419419        private function apply_gettext_default( $key, $value ) {
    420420                if ( 'prefix' === $key && Brendigo_Sidrena_Cijena_Settings::DEFAULT_PREFIX === $value ) {
    421                         return __( 'Sidrena cijena', 'brendigo-sidrena-cijena' );
     421                        return __( 'Bazna cijena', 'brendigo-sidrena-cijena' );
    422422                }
    423423
    424424                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' );
    426426                }
    427427
  • brendigo-sidrena-cijena/includes/class-import-export.php

    r3737238 r3801404  
    6060         */
    6161        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' );
    6666                $columns['sidrena_naziv_posebnog_oblika']      = __( 'Naziv posebnog oblika prodaje', 'brendigo-sidrena-cijena' );
    6767                $columns['sidrena_jedinica_mjere']             = __( 'Jedinica mjere', 'brendigo-sidrena-cijena' );
    … …  
    154154         */
    155155        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' );
    160160                $options['sidrena_naziv_posebnog_oblika'] = __( 'Naziv posebnog oblika prodaje', 'brendigo-sidrena-cijena' );
    161161                $options['sidrena_jedinica_mjere']        = __( 'Jedinica mjere', 'brendigo-sidrena-cijena' );
    … …  
    171171         */
    172172        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';
    177177                $columns['Sidrena cijena']                                     = 'sidrena_cijena';
    178178                $columns['Sidrena cijena datum']                               = 'sidrena_cijena_datum';
  • brendigo-sidrena-cijena/includes/class-notifications.php

    r3737344 r3801404  
    7070                $subject = sprintf(
    7171                        /* translators: %s: website host name. */
    72                         __( '[SIDRENA] Problem s cjenikom – %s', 'brendigo-sidrena-cijena' ),
     72                        __( '[BAZNA] Problem s cjenikom – %s', 'brendigo-sidrena-cijena' ),
    7373                        wp_parse_url( home_url(), PHP_URL_HOST )
    7474                );
  • brendigo-sidrena-cijena/includes/class-plugin.php

    r3737238 r3801404  
    11<?php
    22/**
    3  * Bootstrap the Sidrena cijena plugin.
     3 * Bootstrap the BAZNA plugin.
    44 *
    55 * @package Brendigo_Sidrena_Cijena
    … …  
    2525        public static function init() {
    2626                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        }
    2733
    2834                if ( self::legacy_plugin_active() ) {
    … …  
    6369                }
    6470
    65                 echo '<div class="notice notice-warning"><p><strong>' . esc_html__( 'Brendigo Sidrena Cijena je spremna za 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' );
    6773                echo ' <a href="' . esc_url( admin_url( 'plugins.php' ) ) . '">' . esc_html__( 'Otvori dodatke', 'brendigo-sidrena-cijena' ) . '</a></p></div>';
    6874        }
    … …  
    102108                        $exception_message = substr( $exception_message, 0, 1000 );
    103109                }
    104                 $message = 'Sidrena cijena [' . get_class( $exception ) . ']: ' . $exception_message;
     110                $message = 'BAZNA [' . get_class( $exception ) . ']: ' . $exception_message;
    105111                if ( function_exists( 'wc_get_logger' ) ) {
    106112                        wc_get_logger()->error( $message, array( 'source' => 'sidrena-cijena' ) );
    … …  
    144150                Brendigo_Sidrena_Cijena_Frontend::instance();
    145151
     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
    146160                if ( is_admin() ) {
    147161                        Brendigo_Sidrena_Cijena_Admin::instance();
    … …  
    151165                if ( defined( 'WP_CLI' ) && WP_CLI ) {
    152166                        WP_CLI::add_command( 'sidrena-cijena', 'Brendigo_Sidrena_Cijena_CLI' );
     167                        WP_CLI::add_command( 'bazna', 'Brendigo_Sidrena_Cijena_CLI' );
    153168                }
    154169
    … …  
    159174                add_action( 'sidrena_cijena_snapshot_batch', array( 'Brendigo_Sidrena_Cijena_Activator', 'process_batch' ) );
    160175
    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.
    164177                Brendigo_Sidrena_Cijena_Import_Export::instance();
    165178        }
    166179
    167180        /**
    168          * Activation: defaults. Sidrena prices stay empty until someone fills them.
     181         * Activation: defaults. Base prices stay empty until verified and entered.
    169182         */
    170183        public static function activate() {
    … …  
    194207        public static function deactivate() {
    195208                wp_clear_scheduled_hook( 'sidrena_cijena_snapshot_batch' );
     209        wp_clear_scheduled_hook( 'bazna_license_periodic_check' );
    196210                wp_clear_scheduled_hook( Brendigo_Sidrena_Cijena_Price_History::SEED_HOOK );
    197211                wp_clear_scheduled_hook( Brendigo_Sidrena_Cijena_Price_History::MANUAL_SEED_HOOK );
  • brendigo-sidrena-cijena/includes/class-price-history.php

    r3737238 r3801404  
    6060                add_action( 'admin_init', array( $this, 'seed_without_cron' ), 25 );
    6161                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' ) );
    6264                add_shortcode( 'sidrena_najniza_prije_snizenja', array( $this, 'shortcode_before_sale' ) );
     65                add_shortcode( 'bazna_najniza_prije_snizenja', array( $this, 'shortcode_before_sale' ) );
    6366                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' ) );
    6469                if ( ! Brendigo_Sidrena_Cijena_Plugin::woocommerce_active() ) {
    6570                        return;
  • brendigo-sidrena-cijena/includes/class-product-fields.php

    r3727711 r3801404  
    4545                        <span class="sidrena-cijena-admin-fields__mark" aria-hidden="true">B</span>
    4646                        <div>
    47                                 <strong><?php echo esc_html__( 'Brendigo Sidrena Cijena', 'brendigo-sidrena-cijena' ); ?></strong>
     47                                <strong><?php echo esc_html__( 'BAZNA – Bazne cijene', 'brendigo-sidrena-cijena' ); ?></strong>
    4848                                <small><?php echo esc_html__( 'Referentna cijena i podaci javnog cjenika', 'brendigo-sidrena-cijena' ); ?></small>
    4949                        </div>
    … …  
    6161                                'id'          => 'sidrena_cijena',
    6262                                '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() . ')',
    6464                                'desc_tip'    => true,
    6565                                'description' => __( 'Referentna maloprodajna cijena koja je vrijedila na datumu upisanom uz proizvod.', 'brendigo-sidrena-cijena' ),
    … …  
    8383                $sidrena_date_help = sprintf(
    8484                        /* 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' ),
    8686                        Brendigo_Sidrena_Cijena_Settings::REFERENCE_DATE_GENERAL,
    8787                        Brendigo_Sidrena_Cijena_Settings::REFERENCE_DATE_FMCG
    … …  
    9393                                'name'        => 'sidrena_cijena_datum',
    9494                                'label'       => __( 'Referentni datum', 'brendigo-sidrena-cijena' ),
    95                                 'placeholder' => Brendigo_Sidrena_Cijena_Settings::instance()->get( 'default_date' ),
     95                                'placeholder' => 'DD.MM.GGGG.',
    9696                                'desc_tip'    => true,
    9797                                'description' => $sidrena_date_help,
    … …  
    203203         * @param WP_Post $variation      Variation post.
    204204         */
    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.
    206207                $meta   = Brendigo_Sidrena_Cijena_Product_Meta::instance();
    207208                $id     = $variation->ID;
    … …  
    211212                <div class="sidrena-cijena-variation-fields">
    212213                        <div class="sidrena-cijena-variation-fields__head">
    213                                 <strong><?php echo esc_html__( 'Brendigo Sidrena Cijena', 'brendigo-sidrena-cijena' ); ?></strong>
     214                                <strong><?php echo esc_html__( 'BAZNA – Bazne cijene', 'brendigo-sidrena-cijena' ); ?></strong>
    214215                                <small><?php echo esc_html__( 'Referentna cijena i datum', 'brendigo-sidrena-cijena' ); ?></small>
    215216                        </div>
    216217                        <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>
    218219                                <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 ) ) ); ?>" />
    219220                        </p>
    … …  
    238239                        <p class="form-row form-row-first">
    239240                                <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." />
    241242                        </p>
    242243                        <p class="form-row form-row-last">
  • brendigo-sidrena-cijena/includes/class-product-meta.php

    r3737238 r3801404  
    3939        private function __construct() {
    4040                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.
    4244                add_action( 'added_post_meta', array( $this, 'maybe_clear_overview_cache' ), 10, 4 );
    4345                add_action( 'updated_post_meta', array( $this, 'maybe_clear_overview_cache' ), 10, 4 );
    … …  
    5557                        'show_in_rest'  => true,
    5658                        'auth_callback' => static function ( $allowed, $meta_key, $post_id ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter
     59                                // REST writes remain restricted to authorized product editors.
    5760                                return current_user_can( 'edit_post', (int) $post_id );
    5861                        },
    … …  
    707710                }
    708711
    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;
    710715        }
    711716
    … …  
    742747         */
    743748        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;
    757752        }
    758753
    … …  
    798793                }
    799794
    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 '';
    801798        }
    802799
  • brendigo-sidrena-cijena/includes/class-public-api.php

    r3737238 r3801404  
    1717
    1818        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(
    2023                        'methods'             => WP_REST_Server::READABLE,
    2124                        'callback'            => array( $this, 'index' ),
    2225                        'permission_callback' => '__return_true',
    2326                ) );
    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(
    2534                        'methods' => WP_REST_Server::READABLE,
    2635                        'callback' => array( $this, 'archive_index' ),
    … …  
    3140                        ),
    3241                ) );
    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(
    3443                        'methods'             => WP_REST_Server::READABLE,
    3544                        'callback'            => array( $this, 'feed' ),
    … …  
    3746                        'args'                => array( 'oznaka' => array( 'type' => 'string', 'default' => '', 'sanitize_callback' => 'sanitize_text_field' ) ),
    3847                ) );
     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 );
    3963        }
    4064
    … …  
    4367                $meta = $export->get_public_meta();
    4468                $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(),
    4585                        'published_at' => isset( $meta['generated'] ) ? gmdate( 'c', (int) $meta['generated'] ) : null,
    4686                        'cjenik'       => esc_url_raw( $export->get_cjenik_url() ),
    4787                        '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' ) ),
    4989                        'combined'     => esc_url_raw( $export->get_public_url() ),
    5090                        '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' ) ),
    5193                        'outlets'      => array(),
    5294                );
    5395                foreach ( array( 'proizvodi', 'usluge' ) as $kind ) {
    54                         $out['feeds'][ $kind ] = array();
     96                        $out['feeds'][ $kind ] = array( 'available_csv' => $this->feed_available( $kind ) );
    5597                        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 ) );
    5799                        }
    58100                }
    … …  
    63105                                        continue;
    64106                                }
    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                                }
    66119                                foreach ( array( 'proizvodi', 'usluge' ) as $kind ) {
    67120                                        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 ) ) );
    69122                                        }
    70123                                }
    … …  
    72125                        }
    73126                }
    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;
    75227        }
    76228
    … …  
    78230                $kind = $request->get_param( 'kind' );
    79231                $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;
    81235        }
    82236
    … …  
    96250                $response = new WP_REST_Response( null, 302 );
    97251                $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' );
    99254                return $response;
    100255        }
  • brendigo-sidrena-cijena/includes/class-settings.php

    r3737238 r3801404  
    1414
    1515        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';
    1718        const LEGACY_PREFIX           = 'Cijena';
    1819        const REFERENCE_DATE_GENERAL  = '10.09.2026.';
    1920        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.';
    2123        const PREVIOUS_TOOLTIP_HASH  = '4fdd1b2eba2678023ab9618dc15839bd2efc789ee3404c799ba199eb47dd5404';
    2224        const LEGACY_TOOLTIP_HASH    = '2c8ca8cdc51d22e369144a40b69c504ba24db0b1a08a1e42a04bb065d1102661';
    … …  
    138140                }
    139141
     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
    140148                if ( isset( $stored['prefix'] ) && self::LEGACY_PREFIX === trim( (string) $stored['prefix'] ) ) {
    141149                        $stored['prefix'] = self::DEFAULT_PREFIX;
    … …  
    145153                if ( isset( $stored['tooltip'] ) ) {
    146154                        $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 ) ) {
    148157                                $stored['tooltip'] = self::DEFAULT_TOOLTIP;
    149158                                $dirty             = true;
    … …  
    153162                if ( isset( $stored['i18n']['prefix'] ) && is_array( $stored['i18n']['prefix'] ) ) {
    154163                        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 ) ) {
    156165                                        $stored['i18n']['prefix'][ $lang ] = self::DEFAULT_PREFIX;
    157166                                        $dirty                             = true;
    … …  
    167176                if ( isset( $stored['i18n']['tooltip'] ) && is_array( $stored['i18n']['tooltip'] ) ) {
    168177                        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                                ) ) {
    170182                                        $stored['i18n']['tooltip'][ $lang ] = self::DEFAULT_TOOLTIP;
    171183                                        $dirty                              = true;
    … …  
    276288         */
    277289        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;
    279293        }
    280294
  • brendigo-sidrena-cijena/readme.txt

    r3737344 r3801404  
    1 === SIDRENA – Sidrene cijene i cjenici ===
     1=== BAZNA – Bazne cijene i cjenici ===
    22Contributors: brendigo
    33Tags: reference-prices, price-list, csv, croatia, woocommerce
    … …  
    55Tested up to: 7.1
    66Requires PHP: 7.4
    7 Stable tag: 1.5.0
     7Stable tag: 1.5.20
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    1010
    11 Manage reference prices and dates, publish a public HTML pricelist, and generate XML/CSV archives for WooCommerce or standalone catalogs.
     11BAZNA by Brendigo: bazne cijene i datumi, javni HTML cjenici te CSV/XML arhiva za WordPress i WooCommerce.
    1212
    1313== Description ==
    1414
    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.
    1619
    1720= Publish with clarity =
    … …  
    2831
    2932
    30 Brendigo Sidrena Cijena provides one interface for managing reference-price data and publishing a public pricelist.
     33Brendigo Bazne cijene provides one interface for managing reference-price data and publishing a public pricelist.
    3134
    3235Key features:
    … …  
    5659Reference prices and dates are entered or imported by the site administrator. The plugin does not infer historical prices.
    5760
    58 Documentation: https://brendigo.com/sidrene-cijene
     61Documentation: https://brendigo.com/
    5962
    6063== Installation ==
    6164
    62 After activation, open the **Upute** (Guide) tab inside Brendigo Sidrena Cijena for 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.
     65After 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
     681. Install the ZIP from WordPress Plugins > Add New, or upload the unmodified BAZNA plugin folder through your hosting file manager.
     692. Activate **BAZNA**.
     703. Open WooCommerce > BAZNA. Without WooCommerce, use the standalone BAZNA menu.
    68714. Open **Products** to enter reference prices and dates.
    69725. Open **Public pricelist** to choose the daily publication time and publish the first version.
    … …  
    7780== Standalone WordPress without WooCommerce ==
    7881
    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.
     82WooCommerce 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
     84Use `[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.
    8285
    8386Price 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.
    … …  
    9194== Shortcodes ==
    9295
    93 `[brendigo-sidrena-cijena]` - reference price for the current product.
    94 `[brendigo-sidrena-cijena id="123"]` - reference price for a selected product or manual catalog row.
    95 `[brendigo-sidrena-cjenik]` - public pricelist table.
    96 `[brendigo-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.
    99102
    100103Legacy shortcode aliases remain available for backward compatibility.
    … …  
    102105== WP-CLI ==
    103106
    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.
    109112
    110113== Frequently Asked Questions ==
    … …  
    122125Yes. The daily publication time is configurable in the Public pricelist tab.
    123126
    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
     129No. 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
     133No. 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
     137Yes. 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.
    127138
    128139== Upgrade Notice ==
    … …  
    169180
    170181== 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.
    171295
    172296= 1.5.0 =
    … …  
    174298* Fixed Serbian Latin translation filenames to `sr_RS_latin` and regenerated all compiled locale catalogs.
    175299* 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.
    177301* Kept Croatian as the source language and reference-price logic unchanged.
    178 
    179302
    180303= 1.4.4 =
    … …  
    194317* Kept current public price outputs and WordPress.org distribution clean of extra markdown files.
    195318
    196 
    197319= 1.4.1 =
    198320* Fixed WordPress.org Plugin Check errors for options, temporary XLSX files and product query filters.
    199321* Improved plugin-owned SQL safety and reduced repeat database reads while retaining up-to-date administrator audit information.
    200322* Removed internal development documentation from the distributable package.
    201 
    202323
    203324= 1.3.3 =
    … …  
    209330= 1.3.1 =
    210331* 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.
    212333* Prevent malformed or truncated catalog JSON from wiping stored data, strictly validate item IDs, and avoid reusing automatic row IDs after deletion.
    213334* 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.