Right to Rent changes: The final straw for landlords thinking of selling?
Property118 Right to Rent changes: The final straw for landlords thinking of selling? New Right to Rent rules take effect today, and for landlords already questioning their future in the rental market, they may feel like one more thing to manage. Landlords in England who choose to use a digital verification service for eligible checks must now use a registered provider. The revised Home Office guidance also makes clear that prospective tenants must not be treated less favourably because they choose to provide acceptable physical documents. On its own, a change to checking procedures may not persuade a landlord to sell, but for a landlord already juggling rising costs and compliance, it may feel like one more reason to ask: “Is it time to sell?” At Landlord Sales Agency, we understand that question. We were founded by landlords for landlords, and our portfolio exit specialists deal with the practical problems that can hold up a buy-to-let sale, from tenants and paperwork to financing and property condition. We know landlords want cash in the bank without a long, drawn-out sale. That is why we look at the property and the seller’s priorities before choosing a route. Our buyers can include investors, other landlords and owner-occupiers. Where suitable, we can also help an existing tenant explore buying their home. If your tenants are the reason you think you cannot sell yet, speak to us before starting an eviction. Selling with tenants in place may be possible, with rent continuing to be collected until completion. Where vacant possession is needed, we can work with tenants to explore practical solutions, including relocation or, in some cases, help with the cost of moving. You do not have to decide between keeping every property and selling everything. We can help sell one rental, a partial portfolio or an entire portfolio, allowing you to release cash from the properties you no longer want while keeping those that still work for you. We have an extensive private database of over 30,000 buyers who will buy your properties with or without tenants and get text messages to alert them to new properties every time a landlord comes to us to sell. This dramatically cuts down the time it takes to sell, plus means that you can continue collecting rent all the way up until the actual sale. We typically achieve 85 – 90% of the market value, and for that we cover all the costs and take away all the hassle that comes with selling the portfolio. You won’t get a higher price for the service, and any company promising you 100% market value is hiding a huge list of costs that are going to come after the sale. That’s not the case with us. It’s what makes us different. The new Right to Rent code may be the latest reason you are reconsidering your plans. Whether you own one buy-to-let or a large portfolio, the decision does not have to be “carry on as you are” or “sell everything tomorrow”. Start by finding out what your properties could sell for, who might buy them and how a sale could work with your tenants in place. If you are ready to turn property into cash, contact Landlord Sales Agency for a free, no-obligation conversation. Name * Email * Phone * Please give us details of how we can help and the properties in question * Privacy Policy * I have read and accept Property118’s Privacy Policy (function(){var el=document.getElementById("ts-607776b5-3f7b-431c-b5cc-fc304603fee3");if(!el)return;var b=document.body,h=document.documentElement;var dark=b.classList.contains("dark-mode")||b.classList.contains("dark")||b.classList.contains("night-mode")||h.classList.contains("dark");if(!dark){var bg=window.getComputedStyle(b).backgroundColor,m=bg.match(/\d+/g);if(m)dark=(m[0]*0.299+m[1]*0.587+m[2]*0.114) Submit (function(){ var uid = "crm-form-ba09a29b"; var form = document.getElementById(uid + '-form'); var wrap = document.getElementById(uid); var msg = wrap.querySelector('.crm-message'); var totalPages = 1; var curPage = 0; // ── Name casing ────────────────────────────────────────────────────── // Tidy a name box as the visitor leaves it, so they are not staring at // "JOHN SMITH" in their own form. Deliberately cosmetic: the API runs // the same normalisation on submit and is the authority on what gets // stored, so a disagreement here is harmless. Kept in step with // packages/shared/src/names.ts. var NAME_PARTICLES = ' van von de del della der den di da dal du la le el bin ibn al dos das do ter ten '; var NAME_MACS = ' macdonald macintyre macleod macarthur macgregor macneil macpherson macrae mackinnon macqueen '; function nameUp(s){ return s.replace(/[a-z]/i, function(c){ return c.toUpperCase(); }); } function isParticle(w){ return NAME_PARTICLES.indexOf(' ' + w.toLowerCase() + ' ') >= 0; } function nameRecase(atom){ if (!/[a-z]/i.test(atom)) return atom; var dot = atom.charAt(atom.length - 1) === '.' ? '.' : ''; var core = dot ? atom.slice(0, -1) : atom; var lower = core.toLowerCase(); if (/^(?:II|III|IV|VI|VII|VIII|IX|XI|XII)$/.test(core.toUpperCase())) return core.toUpperCase() + dot; if (lower === 'jr' || lower === 'sr') return nameUp(lower) + dot; if (core.length === 1) return core.toUpperCase() + dot; var mc = /^mc([a-z]{2,})$/.exec(lower); if (mc) return 'Mc' + nameUp(mc[1]) + dot; if (NAME_MACS.indexOf(' ' + lower + ' ') >= 0) return 'Mac' + nameUp(lower.slice(3)) + dot; return nameUp(lower) + dot; } function nameWellFormed(atom){ // "Mccoll" has its leading capital but still wants McColl. Safe only // because "Mc" is unambiguous — "Mac" deliberately has no such rule. if (/^Mc[a-z]{2,}$/.test(atom)) return false; return /^(?:[A-Z][a-z]*|[A-Z][a-z]+[A-Z][A-Za-z]*|O[A-Z][a-z]+|[A-Z]{1,3}|[IVX]+)$/.test(atom); } function tidyName(value){ var v = (value || '').replace(/\s+/g, ' ').replace(/^ | $/g, ''); if (!v) return value; if (/[@\d,]|&[a-z]+;|&#|https?:|www\./i.test(v)) return value; // not a name var words = v.split(' '); var deliberate = words.every(function(w){ // A lone particle is not a particle — it is someone's name (Di, Al). if (words.length > 1 && isParticle(w)) return true; return w.split(/[-'\u2019.]/).filter(function(seg){ return /[a-z]/i.test(seg); }) .every(function(seg){ return nameWellFormed(seg); }); }); if (deliberate) return v; return words.map(function(w, i){ if (i > 0 && isParticle(w)) return w.toLowerCase(); return w.split(/([-'\u2019.])/).map(function(seg){ return /^[-'\u2019.]$/.test(seg) ? seg : nameRecase(seg); }).join(''); }).join(' '); } // ── Thousand separators ────────────────────────────────────────────── // Opt-in per field (data-thousands). Mirrors formatThousands() and the // caret helpers in the CRM's packages/shared/src/numbers.ts. The CRM // strips the separators again on submit, so storage is unaffected. function groupThousands(value){ var raw = String(value == null ? '' : value).replace(/,/g, ''); if (!raw) return ''; var neg = raw.charAt(0) === '-'; var body = neg ? raw.slice(1) : raw; var dot = body.indexOf('.'); var digits = function(x){ return x.replace(/[^0-9]/g, ''); }; var whole = digits(dot === -1 ? body : body.slice(0, dot)); var frac = dot === -1 ? null : digits(body.slice(dot + 1)); if (!whole && frac === null) return neg ? '-' : ''; var grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ','); return (neg ? '-' : '') + grouped + (frac === null ? '' : '.' + frac); } // Reposition by digit count, not character index: commas appear and // vanish to the left of the caret, and counting characters would throw // it to the end of the field on every keystroke. function caretAfterGrouping(formatted, digitsBefore){ if (digitsBefore parseFloat(cmp); case 'lessthan': return parseFloat(val) [ ][ ]', so the prefix arm above // collects EVERY rendered row. Demanding all of them be filled means one blank // extra row - added by mistake, or rendered by settings.minRows - blocks Next and // Submit with a generic message on the wrapper. Only the first row is required. var firstRow = form.querySelector('[data-field-id="' + fld.id + '"] .crm-repeater-row'); if (firstRow) { reqEls = Array.prototype.filter.call(reqEls, function (el) { return firstRow.contains(el); }); } var toTest = reqEls.length ? reqEls : [els[0]]; return Array.prototype.every.call(toTest, function (el) { return (el.value || '').trim() !== ''; }); } function crmFirstInvalid(pageIdx) { for (var i = 0; i [ ][ ]". // Group those flat keys into an array of row objects under the repeater // id. Plain fields, checkbox "[]" arrays and single-bracket composites // (name[first], address[city]) don't match the double-bracket pattern, so // ordinary submissions are unchanged. var _repRe = /^(.+?)\[(\d+)\]\[(.+)\]$/; var _repIds = {}; Object.keys( data ).forEach( function ( key ) { var m = key.match( _repRe ); if ( ! m ) { return; } var rid = m[1], row = parseInt( m[2], 10 ), sub = m[3]; _repIds[ rid ] = true; if ( ! Array.isArray( data[ rid ] ) ) { data[ rid ] = []; } if ( ! data[ rid ][ row ] || typeof data[ rid ][ row ] !== 'object' ) { data[ rid ][ row ] = {}; } data[ rid ][ row ][ sub ] = data[ key ]; delete data[ key ]; } ); Object.keys( _repIds ).forEach( function ( rid ) { if ( Array.isArray( data[ rid ] ) ) { data[ rid ] = data[ rid ].filter( function ( r ) { return r && typeof r === 'object'; } ); } } ); // GF auto-substituted {user_agent} / {referer} on hidden fields // at render time. We do the equivalent right before submit so // fields whose default value carries these placeholders // resolve to the browser's actual values rather than being // stored as literal "{user_agent}" / "{referer}" strings. // The last ARTICLE the visitor read (set client-side on post views by // P118_Article_Views). Used to attribute the enquiry to the article // even after navigating away or with a stripped/absent referer. var lastPost = ''; try { var lpm = document.cookie.match(/(?:^|;\s*)p118_last_post=([^;]+)/); if (lpm) lastPost = decodeURIComponent(lpm[1]); } catch (e) {} var subs = { '{user_agent}': navigator.userAgent || '', // Prefer the last article read; fall back to the (lossy) HTTP referer. '{referer}': lastPost || document.referrer || '', '{last_post}': lastPost || '', '{embed_url}': window.location.href || '', }; for (var name in data) { if (!data.hasOwnProperty(name)) continue; var v = data[name]; if (typeof v !== 'string') continue; for (var tag in subs) { if (v.indexOf(tag) !== -1) v = v.split(tag).join(subs[tag]); } data[name] = v; } // Agent/BDM attribution — read LIVE so it works even on a fully cached // page (the browser always sees the real URL + cookie). URL ?ataid=/?cid= // first, then the 30-day agent_id/cid cookies set by atat-tracking.php. var _qp = new URLSearchParams(window.location.search); var _ataid = _qp.get('ataid') || (document.cookie.match(/(?:^|;\s*)agent_id=([^;]+)/) || [])[1] || ''; var _cid = _qp.get('cid') || (document.cookie.match(/(?:^|;\s*)cid=([^;]+)/) || [])[1] || ''; if (_ataid) data.agent_id = decodeURIComponent(_ataid); if (_cid) data.bdm_id = decodeURIComponent(_cid); // Which page the form was actually on. Read live for the same reason // as the attribution above: on a cached page the server has no idea // which URL it is being served as, but the browser always does. data._sourceUrl = window.location.href; // …and what sent them to it. Read live for the same reason: a cached // page cannot know either, but the browser does. Blank when they // typed the address, used a bookmark, or came from an email client — // which is the honest answer, not a gap to be filled in server-side. data._referrerUrl = document.referrer || ''; // This browser's progress through a multi-page form is now sent. if (typeof progVisit !== 'undefined' && progVisit) data._visitId = progVisit; return data; } function uploadFiles(data) { var fileInputs = form.querySelectorAll('input[type=file][data-crm-file-field]'); var uploads = []; fileInputs.forEach(function(el) { if (!el.files || !el.files[0]) return; var fd = new FormData(); fd.append('file', el.files[0]); var fieldName = el.name; uploads.push( fetch(crmApiUrl + '/public/forms/' + "08ceeaae-4809-444e-ba0f-88da5836c463" + '/upload', { method: 'POST', body: fd }) .then(function(r) { if (!r.ok) throw new Error('File upload failed (' + r.status + ')'); return r.json(); }) .then(function(res) { if (res.path) data[fieldName] = res.path; else throw new Error(res.error || 'File upload failed'); }) ); }); return Promise.all(uploads).then(function() { return data; }); } function submitFormData(data) { var body = new FormData(); body.append('action', 'p118_crm_submit'); body.append('form_id', "08ceeaae-4809-444e-ba0f-88da5836c463"); body.append('data', JSON.stringify(data)); // Embed-page context for GF-style merge tags ({embed_url}, // {embed_post:post_title}, {embed_post:ID}). Captured PHP-side // at render time, then echoed to JS so the submit fetch can // forward to V2 as request headers. body.append('embed_url', ""); body.append('embed_post_id', "0"); body.append('embed_post_title', ""); return fetch("https:\/\/www.property118.com\/wp-admin\/admin-ajax.php", { method: 'POST', body: body, credentials: 'same-origin' }) .then(function(r){ return r.json(); }) .then(function(res){ var p = res.data || res; if (p && p.success) { if (typeof progDone === 'function') progDone(); if (p.confirmationType === 'form' && p.nextFormId) { return swapInNextForm(p.nextFormId, p.prefill || {}); } if (p.confirmationType === 'redirect' && p.confirmationRedirectUrl) { window.location.href = p.confirmationRedirectUrl; } else { form.style.display = 'none'; msg.className = 'crm-message success'; msg.innerHTML = p.confirmationMessage || 'Thank you for your submission.'; // Carry the calculator's own results across. A calculator form // renders its figures into [data-iht-results] as the visitor // types; hiding the form hid those too, so the completion // screen went blank and the visitor lost what they had just // worked out. Nothing happens on forms without that element. var resultsEl = form.querySelector('[data-iht-results]'); if (resultsEl && resultsEl.innerHTML.trim()) { var carried = document.createElement('div'); carried.className = 'crm-message-results'; carried.innerHTML = resultsEl.innerHTML; msg.appendChild(carried); } // Download link for a generated report, present only when the // API filed the PDF before responding. Built through the DOM // rather than concatenated into innerHTML so the URL cannot // inject markup. if (p.reportDownloadUrl) { var dlWrap = document.createElement('p'); dlWrap.className = 'crm-report-download'; var dl = document.createElement('a'); dl.className = 'crm-report-button'; // Building through the DOM stops markup injection but not a // javascript: URL, which would run in this origin the moment // the submitter clicks the button. dl.href = /^https?:\/\//i.test(String(p.reportDownloadUrl)) ? p.reportDownloadUrl : '#'; dl.target = '_blank'; dl.rel = 'noopener noreferrer'; dl.textContent = 'Download your report (PDF)'; dlWrap.appendChild(dl); msg.appendChild(dlWrap); } msg.style.display = 'block'; if (msg.scrollIntoView) { msg.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } } else { throw new Error((p && p.error) || 'Submission failed.'); } }); } // Replace this whole form widget with another form, rendered server-side // with the carried-over values seeded in. Inline injected via // innerHTML won't run, so we re-create each script node to execute it // (this is what wires up the new form's submit / conditional logic). function swapInNextForm(nextFormId, prefill) { var rbody = new FormData(); rbody.append('action', 'p118_crm_render_form'); rbody.append('form_id', nextFormId); rbody.append('prefill', JSON.stringify(prefill || {})); return fetch("https:\/\/www.property118.com\/wp-admin\/admin-ajax.php", { method: 'POST', body: rbody, credentials: 'same-origin' }) .then(function(r){ return r.json(); }) .then(function(res2){ var pd = res2.data || res2; if (!pd || !pd.html) { throw new Error((pd && pd.error) || 'Could not load the next form.'); } var frag = document.createElement('div'); frag.innerHTML = pd.html; var parent = wrap.parentNode; var nodes = []; while (frag.firstChild) { var node = frag.firstChild; parent.insertBefore(node, wrap); nodes.push(node); } parent.removeChild(wrap); function reexec(old) { var s = document.createElement('script'); for (var a = 0; a The post Right to Rent changes: The final straw for landlords thinking of selling? appeared first on Property118 .
Originally published by
Property118